Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/permissions/permission_request_manager.h" | 5 #include "chrome/browser/permissions/permission_request_manager.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/metrics/field_trial.h" | 8 #include "base/metrics/field_trial.h" |
| 9 #include "build/build_config.h" | 9 #include "build/build_config.h" |
| 10 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" | |
| 11 #include "chrome/browser/custom_handlers/register_protocol_handler_permission_re quest.h" | |
| 12 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" | |
| 13 #include "chrome/browser/media/webrtc/media_stream_devices_controller.h" | |
| 10 #include "chrome/browser/permissions/permission_context_base.h" | 14 #include "chrome/browser/permissions/permission_context_base.h" |
| 15 #include "chrome/browser/permissions/permission_request_impl.h" | |
| 11 #include "chrome/browser/permissions/permission_util.h" | 16 #include "chrome/browser/permissions/permission_util.h" |
| 17 #include "chrome/browser/profiles/profile.h" | |
| 12 #include "chrome/browser/ui/browser.h" | 18 #include "chrome/browser/ui/browser.h" |
| 13 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 20 #include "chrome/browser/ui/test/test_browser_dialog.h" | |
| 14 #include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" | 21 #include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" |
| 15 #include "chrome/test/base/in_process_browser_test.h" | 22 #include "chrome/test/base/in_process_browser_test.h" |
| 16 #include "chrome/test/base/ui_test_utils.h" | 23 #include "chrome/test/base/ui_test_utils.h" |
| 17 #include "components/content_settings/core/common/content_settings_types.h" | 24 #include "components/content_settings/core/common/content_settings_types.h" |
| 18 #include "components/variations/variations_associated_data.h" | 25 #include "components/variations/variations_associated_data.h" |
| 19 #include "content/public/test/browser_test_utils.h" | 26 #include "content/public/test/browser_test_utils.h" |
| 20 #include "content/public/test/test_utils.h" | 27 #include "content/public/test/test_utils.h" |
| 21 #include "net/test/embedded_test_server/embedded_test_server.h" | 28 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 22 | 29 |
| 30 namespace test { | |
| 31 class MediaStreamDevicesControllerTestApi { | |
| 32 public: | |
| 33 static MediaStreamDevicesController* Create( | |
| 34 content::WebContents* web_contents, | |
| 35 const content::MediaStreamRequest& request, | |
| 36 const content::MediaResponseCallback& callback) { | |
| 37 return new MediaStreamDevicesController(web_contents, request, callback); | |
| 38 } | |
| 39 }; | |
| 40 } // namespace test | |
| 41 | |
| 23 namespace { | 42 namespace { |
| 24 | 43 |
| 25 const char* kPermissionsKillSwitchFieldStudy = | 44 const char* kPermissionsKillSwitchFieldStudy = |
| 26 PermissionContextBase::kPermissionsKillSwitchFieldStudy; | 45 PermissionContextBase::kPermissionsKillSwitchFieldStudy; |
| 27 const char* kPermissionsKillSwitchBlockedValue = | 46 const char* kPermissionsKillSwitchBlockedValue = |
| 28 PermissionContextBase::kPermissionsKillSwitchBlockedValue; | 47 PermissionContextBase::kPermissionsKillSwitchBlockedValue; |
| 29 const char kPermissionsKillSwitchTestGroup[] = "TestGroup"; | 48 const char kPermissionsKillSwitchTestGroup[] = "TestGroup"; |
| 30 | 49 |
| 31 class PermissionRequestManagerBrowserTest : public InProcessBrowserTest { | 50 class PermissionRequestManagerBrowserTest : public InProcessBrowserTest { |
| 32 public: | 51 public: |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 61 kPermissionsKillSwitchBlockedValue; | 80 kPermissionsKillSwitchBlockedValue; |
| 62 variations::AssociateVariationParams( | 81 variations::AssociateVariationParams( |
| 63 kPermissionsKillSwitchFieldStudy, kPermissionsKillSwitchTestGroup, | 82 kPermissionsKillSwitchFieldStudy, kPermissionsKillSwitchTestGroup, |
| 64 params); | 83 params); |
| 65 base::FieldTrialList::CreateFieldTrial(kPermissionsKillSwitchFieldStudy, | 84 base::FieldTrialList::CreateFieldTrial(kPermissionsKillSwitchFieldStudy, |
| 66 kPermissionsKillSwitchTestGroup); | 85 kPermissionsKillSwitchTestGroup); |
| 67 } | 86 } |
| 68 | 87 |
| 69 private: | 88 private: |
| 70 std::unique_ptr<MockPermissionPromptFactory> mock_permission_prompt_factory_; | 89 std::unique_ptr<MockPermissionPromptFactory> mock_permission_prompt_factory_; |
| 90 | |
| 91 DISALLOW_COPY_AND_ASSIGN(PermissionRequestManagerBrowserTest); | |
| 71 }; | 92 }; |
| 72 | 93 |
| 94 // Harness for testing permissions dialogs invoked by PermissionRequestManager. | |
| 95 // Uses a "real" PermissionPromptFactory rather than a mock. | |
| 96 class PermissionDialogTest | |
| 97 : public SupportsTestDialog<PermissionRequestManagerBrowserTest> { | |
| 98 public: | |
| 99 PermissionDialogTest() {} | |
| 100 | |
| 101 // InProcessBrowserTest: | |
| 102 void SetUpOnMainThread() override { | |
| 103 InProcessBrowserTest::SetUpOnMainThread(); // Skip super. | |
|
raymes
2017/03/12 23:33:53
nit: could you explain why we skip the super setup
tapted
2017/03/14 00:43:52
Done. added comment
// Skip super: It will in
| |
| 104 } | |
| 105 | |
| 106 private: | |
| 107 GURL GetUrl() { return GURL("https://example.com"); } | |
| 108 | |
| 109 PermissionRequest* MakeRegisterProtocolHandlerRequest(); | |
| 110 PermissionRequest* MakeMediaRequest(ContentSettingsType permission); | |
| 111 PermissionRequest* MakePermissionRequest(ContentSettingsType permission); | |
| 112 | |
| 113 // TestBrowserDialog: | |
| 114 void ShowDialog(const std::string& name) override; | |
| 115 | |
| 116 // Holds requests that do not delete themselves. | |
| 117 std::vector<std::unique_ptr<PermissionRequest>> owned_requests_; | |
| 118 | |
| 119 DISALLOW_COPY_AND_ASSIGN(PermissionDialogTest); | |
| 120 }; | |
| 121 | |
| 122 PermissionRequest* PermissionDialogTest::MakeRegisterProtocolHandlerRequest() { | |
| 123 std::string protocol = "mailto"; | |
| 124 bool user_gesture = true; | |
| 125 ProtocolHandler handler = | |
| 126 ProtocolHandler::CreateProtocolHandler(protocol, GetUrl()); | |
| 127 ProtocolHandlerRegistry* registry = | |
| 128 ProtocolHandlerRegistryFactory::GetForBrowserContext( | |
| 129 browser()->profile()); | |
| 130 // Deleted in RegisterProtocolHandlerPermissionRequest::RequestFinished(). | |
| 131 return new RegisterProtocolHandlerPermissionRequest(registry, handler, | |
| 132 GetUrl(), user_gesture); | |
| 133 } | |
| 134 | |
| 135 PermissionRequest* PermissionDialogTest::MakeMediaRequest( | |
| 136 ContentSettingsType permission) { | |
| 137 content::WebContents* web_contents = | |
| 138 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 139 content::MediaStreamRequestType request_type = content::MEDIA_DEVICE_ACCESS; | |
| 140 content::MediaStreamType audio_type = content::MEDIA_NO_SERVICE; | |
| 141 content::MediaStreamType video_type = content::MEDIA_NO_SERVICE; | |
| 142 std::string audio_id = "audio_id"; | |
| 143 std::string video_id = "video_id"; | |
| 144 | |
| 145 if (permission == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) | |
| 146 audio_type = content::MEDIA_DEVICE_AUDIO_CAPTURE; | |
| 147 else | |
| 148 video_type = content::MEDIA_DEVICE_VIDEO_CAPTURE; | |
| 149 content::MediaStreamRequest request(0, 0, 0, GetUrl(), false, request_type, | |
| 150 audio_id, video_id, audio_type, | |
| 151 video_type, false); | |
| 152 | |
| 153 // Add fake devices, otherwise the request will auto-block. | |
| 154 MediaCaptureDevicesDispatcher::GetInstance()->SetTestAudioCaptureDevices( | |
| 155 content::MediaStreamDevices( | |
| 156 1, content::MediaStreamDevice(content::MEDIA_DEVICE_AUDIO_CAPTURE, | |
| 157 audio_id, "Fake Audio"))); | |
| 158 MediaCaptureDevicesDispatcher::GetInstance()->SetTestVideoCaptureDevices( | |
| 159 content::MediaStreamDevices( | |
| 160 1, content::MediaStreamDevice(content::MEDIA_DEVICE_VIDEO_CAPTURE, | |
| 161 video_id, "Fake Video"))); | |
| 162 | |
| 163 auto response = [](const content::MediaStreamDevices& devices, | |
| 164 content::MediaStreamRequestResult result, | |
| 165 std::unique_ptr<content::MediaStreamUI> ui) {}; | |
| 166 // Deleted in MediaStreamDevicesController::RequestFinished(). | |
| 167 return test::MediaStreamDevicesControllerTestApi::Create( | |
| 168 web_contents, request, base::Bind(response)); | |
| 169 } | |
| 170 | |
| 171 PermissionRequest* PermissionDialogTest::MakePermissionRequest( | |
| 172 ContentSettingsType permission) { | |
| 173 bool user_gesture = true; | |
| 174 auto decided = [](bool, ContentSetting) {}; | |
| 175 auto cleanup = [] {}; // Leave cleanup to test harness destructor. | |
| 176 owned_requests_.push_back(base::MakeUnique<PermissionRequestImpl>( | |
| 177 GetUrl(), permission, browser()->profile(), user_gesture, | |
| 178 base::Bind(decided), base::Bind(cleanup))); | |
| 179 return owned_requests_.back().get(); | |
| 180 } | |
| 181 | |
| 182 void PermissionDialogTest::ShowDialog(const std::string& name) { | |
| 183 constexpr const char* kMultipleName = "multiple"; | |
| 184 // Permissions to request for a "multiple" request. Only types handled in | |
| 185 // PermissionRequestImpl::GetMessageTextFragment() are valid. | |
| 186 constexpr ContentSettingsType kMultipleRequests[] = { | |
| 187 CONTENT_SETTINGS_TYPE_GEOLOCATION, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, | |
| 188 CONTENT_SETTINGS_TYPE_MIDI_SYSEX}; | |
| 189 constexpr struct { | |
| 190 const char* name; | |
| 191 ContentSettingsType type; | |
| 192 } kNameToType[] = { | |
| 193 {"flash", CONTENT_SETTINGS_TYPE_PLUGINS}, | |
| 194 {"geolocation", CONTENT_SETTINGS_TYPE_GEOLOCATION}, | |
| 195 {"protected_media", CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER}, | |
| 196 {"notifications", CONTENT_SETTINGS_TYPE_NOTIFICATIONS}, | |
| 197 {"mic", CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC}, | |
| 198 {"camera", CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA}, | |
| 199 {"protocol_handlers", CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS}, | |
| 200 {"midi", CONTENT_SETTINGS_TYPE_MIDI_SYSEX}, | |
| 201 {kMultipleName, CONTENT_SETTINGS_TYPE_DEFAULT}}; | |
| 202 const auto* it = std::begin(kNameToType); | |
| 203 for (; it != std::end(kNameToType); ++it) { | |
| 204 if (name == it->name) | |
| 205 break; | |
| 206 } | |
| 207 if (it == std::end(kNameToType)) { | |
| 208 ADD_FAILURE() << "Unknown: " << name; | |
| 209 return; | |
| 210 } | |
| 211 PermissionRequestManager* manager = GetPermissionRequestManager(); | |
| 212 switch (it->type) { | |
| 213 case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS: | |
| 214 manager->AddRequest(MakeRegisterProtocolHandlerRequest()); | |
| 215 break; | |
| 216 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS: | |
| 217 // TODO(tapted): Prompt for downloading multiple files. | |
| 218 break; | |
| 219 case CONTENT_SETTINGS_TYPE_DURABLE_STORAGE: | |
| 220 // TODO(tapted): Prompt for quota request. | |
| 221 break; | |
| 222 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: | |
| 223 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: | |
| 224 manager->AddRequest(MakeMediaRequest(it->type)); | |
| 225 break; | |
| 226 // Regular permissions requests. | |
| 227 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX: | |
| 228 case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING: // Same as notifications. | |
| 229 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: | |
| 230 case CONTENT_SETTINGS_TYPE_GEOLOCATION: | |
| 231 case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER: // ChromeOS only. | |
| 232 case CONTENT_SETTINGS_TYPE_PPAPI_BROKER: | |
| 233 case CONTENT_SETTINGS_TYPE_PLUGINS: // Flash. | |
| 234 manager->AddRequest(MakePermissionRequest(it->type)); | |
| 235 break; | |
| 236 case CONTENT_SETTINGS_TYPE_MIDI: // Disabled (no icon). | |
|
raymes
2017/03/12 23:33:53
This one actually doesn't prompt either.
tapted
2017/03/14 00:43:53
Done.
| |
| 237 case CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC: // Disabled (doesn't prompt). | |
| 238 ADD_FAILURE() << "PermissionType, but doesn't prompt."; | |
| 239 return; | |
| 240 case CONTENT_SETTINGS_TYPE_COOKIES: | |
| 241 case CONTENT_SETTINGS_TYPE_IMAGES: | |
| 242 case CONTENT_SETTINGS_TYPE_JAVASCRIPT: | |
| 243 case CONTENT_SETTINGS_TYPE_POPUPS: | |
| 244 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE: | |
| 245 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT: | |
| 246 case CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS: | |
| 247 case CONTENT_SETTINGS_TYPE_APP_BANNER: | |
| 248 case CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT: | |
| 249 case CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA: | |
| 250 case CONTENT_SETTINGS_TYPE_BLUETOOTH_GUARD: | |
| 251 case CONTENT_SETTINGS_TYPE_AUTOPLAY: | |
| 252 case CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT: | |
| 253 case CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO: | |
| 254 case CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA: | |
| 255 case CONTENT_SETTINGS_TYPE_SUBRESOURCE_FILTER: | |
| 256 case CONTENT_SETTINGS_NUM_TYPES_DO_NOT_USE: | |
| 257 ADD_FAILURE() << "Not a permission prompt."; | |
| 258 return; | |
| 259 case CONTENT_SETTINGS_TYPE_DEFAULT: | |
| 260 EXPECT_EQ(kMultipleName, name); | |
| 261 for (auto request : kMultipleRequests) | |
| 262 manager->AddRequest(MakePermissionRequest(request)); | |
| 263 break; | |
| 264 // No default case, to pick up new enum values. | |
|
raymes
2017/03/12 23:33:53
I'd actually suggest adding default: here because
tapted
2017/03/14 00:43:52
Done.
| |
| 265 } | |
| 266 manager->DisplayPendingRequests(); | |
| 267 } | |
| 268 | |
| 73 // Requests before the load event should be bundled into one bubble. | 269 // Requests before the load event should be bundled into one bubble. |
| 74 // http://crbug.com/512849 flaky | 270 // http://crbug.com/512849 flaky |
| 75 IN_PROC_BROWSER_TEST_F(PermissionRequestManagerBrowserTest, | 271 IN_PROC_BROWSER_TEST_F(PermissionRequestManagerBrowserTest, |
| 76 DISABLED_RequestsBeforeLoad) { | 272 DISABLED_RequestsBeforeLoad) { |
| 77 ASSERT_TRUE(embedded_test_server()->Start()); | 273 ASSERT_TRUE(embedded_test_server()->Start()); |
| 78 | 274 |
| 79 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | 275 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( |
| 80 browser(), | 276 browser(), |
| 81 embedded_test_server()->GetURL("/permissions/requests-before-load.html"), | 277 embedded_test_server()->GetURL("/permissions/requests-before-load.html"), |
| 82 1); | 278 1); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 241 | 437 |
| 242 // Disable the trial. | 438 // Disable the trial. |
| 243 variations::testing::ClearAllVariationParams(); | 439 variations::testing::ClearAllVariationParams(); |
| 244 | 440 |
| 245 EXPECT_TRUE(content::ExecuteScript(web_contents, "requestNotification();")); | 441 EXPECT_TRUE(content::ExecuteScript(web_contents, "requestNotification();")); |
| 246 bubble_factory()->WaitForPermissionBubble(); | 442 bubble_factory()->WaitForPermissionBubble(); |
| 247 EXPECT_EQ(1, bubble_factory()->show_count()); | 443 EXPECT_EQ(1, bubble_factory()->show_count()); |
| 248 EXPECT_EQ(1, bubble_factory()->total_request_count()); | 444 EXPECT_EQ(1, bubble_factory()->total_request_count()); |
| 249 } | 445 } |
| 250 | 446 |
| 447 // Host wants to run flash. | |
| 448 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_flash) { | |
| 449 RunDialog(); | |
| 450 } | |
| 451 | |
| 452 // Host wants to know your location. | |
| 453 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_geolocation) { | |
| 454 RunDialog(); | |
| 455 } | |
| 456 | |
| 457 // Host wants to show notifications. | |
| 458 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_notifications) { | |
| 459 RunDialog(); | |
| 460 } | |
| 461 | |
| 462 // Host wants to use your microphone. | |
| 463 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_mic) { | |
| 464 RunDialog(); | |
| 465 } | |
| 466 | |
| 467 // Host wants to use your camera. | |
| 468 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_camera) { | |
| 469 RunDialog(); | |
| 470 } | |
| 471 | |
| 472 // Host wants to open email links. | |
| 473 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_protocol_handlers) { | |
| 474 RunDialog(); | |
| 475 } | |
| 476 | |
| 477 // Host wants to use your MIDI devices. | |
| 478 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_midi) { | |
| 479 RunDialog(); | |
| 480 } | |
| 481 | |
| 482 // Shows a permissions bubble with multiple requests. | |
| 483 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_multiple) { | |
| 484 RunDialog(); | |
| 485 } | |
| 486 | |
| 487 // CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER is ChromeOS only. | |
| 488 #if defined(OS_CHROMEOS) | |
| 489 #define MAYBE_InvokeDialog_protected_media InvokeDialog_protected_media | |
| 490 #else | |
| 491 #define MAYBE_InvokeDialog_protected_media DISABLED_InvokeDialog_protected_media | |
| 492 #endif | |
| 493 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, | |
| 494 MAYBE_InvokeDialog_protected_media) { | |
| 495 RunDialog(); | |
| 496 } | |
| 497 | |
| 251 } // anonymous namespace | 498 } // anonymous namespace |
| OLD | NEW |