diff options
53 files changed, 583 insertions, 116 deletions
diff --git a/apps/custom_launcher_page_contents.cc b/apps/custom_launcher_page_contents.cc index 023c305..7a2f4b2 100644 --- a/apps/custom_launcher_page_contents.cc +++ b/apps/custom_launcher_page_contents.cc @@ -126,6 +126,14 @@ void CustomLauncherPageContents::RequestMediaAccessPermission( helper_->RequestMediaAccessPermission(request, callback); } +bool CustomLauncherPageContents::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) { + DCHECK_EQ(web_contents_.get(), web_contents); + return helper_->CheckMediaAccessPermission(security_origin, type); +} + bool CustomLauncherPageContents::OnMessageReceived( const IPC::Message& message) { bool handled = true; diff --git a/apps/custom_launcher_page_contents.h b/apps/custom_launcher_page_contents.h index 36e7f79..eaa7673 100644 --- a/apps/custom_launcher_page_contents.h +++ b/apps/custom_launcher_page_contents.h @@ -71,6 +71,10 @@ class CustomLauncherPageContents content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) OVERRIDE; + virtual bool CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) OVERRIDE; private: // content::WebContentsObserver overrides: diff --git a/athena/extensions/chrome/athena_app_delegate.cc b/athena/extensions/chrome/athena_app_delegate.cc index 64d8d0a..1046cc7 100644 --- a/athena/extensions/chrome/athena_app_delegate.cc +++ b/athena/extensions/chrome/athena_app_delegate.cc @@ -146,6 +146,16 @@ void AthenaAppDelegate::RequestMediaAccessPermission( web_contents, request, callback, extension); } +bool AthenaAppDelegate::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const extensions::Extension* extension) { + return MediaCaptureDevicesDispatcher::GetInstance() + ->CheckMediaAccessPermission( + web_contents, security_origin, type, extension); +} + int AthenaAppDelegate::PreferredIconSize() { // TODO(oshima): Find out what to use. return extension_misc::EXTENSION_ICON_SMALL; diff --git a/athena/extensions/chrome/athena_app_delegate.h b/athena/extensions/chrome/athena_app_delegate.h index 0c41a7b..90d0496 100644 --- a/athena/extensions/chrome/athena_app_delegate.h +++ b/athena/extensions/chrome/athena_app_delegate.h @@ -45,6 +45,11 @@ class AthenaAppDelegate : public extensions::AppDelegate { const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback, const extensions::Extension* extension) OVERRIDE; + virtual bool CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const extensions::Extension* extension) OVERRIDE; virtual int PreferredIconSize() OVERRIDE; virtual gfx::ImageSkia GetAppDefaultIcon() OVERRIDE; virtual void SetWebContentsBlocked(content::WebContents* web_contents, diff --git a/chrome/browser/android/chrome_web_contents_delegate_android.cc b/chrome/browser/android/chrome_web_contents_delegate_android.cc index 5da0e30..6463083 100644 --- a/chrome/browser/android/chrome_web_contents_delegate_android.cc +++ b/chrome/browser/android/chrome_web_contents_delegate_android.cc @@ -226,6 +226,14 @@ void ChromeWebContentsDelegateAndroid::RequestMediaAccessPermission( web_contents, request, callback, NULL); } +bool ChromeWebContentsDelegateAndroid::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) { + return MediaCaptureDevicesDispatcher::GetInstance() + ->CheckMediaAccessPermission(web_contents, security_origin, type); +} + bool ChromeWebContentsDelegateAndroid::RequestPpapiBrokerPermission( WebContents* web_contents, const GURL& url, diff --git a/chrome/browser/android/chrome_web_contents_delegate_android.h b/chrome/browser/android/chrome_web_contents_delegate_android.h index 2b2bef1..e7fdccd 100644 --- a/chrome/browser/android/chrome_web_contents_delegate_android.h +++ b/chrome/browser/android/chrome_web_contents_delegate_android.h @@ -59,6 +59,10 @@ class ChromeWebContentsDelegateAndroid content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) OVERRIDE; + virtual bool CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) OVERRIDE; virtual bool RequestPpapiBrokerPermission( content::WebContents* web_contents, const GURL& url, diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc index 6bd2ea7..9fac03a 100644 --- a/chrome/browser/chromeos/login/ui/webui_login_view.cc +++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc @@ -19,6 +19,7 @@ #include "chrome/browser/chromeos/login/ui/webui_login_display.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" +#include "chrome/browser/media/media_capture_devices_dispatcher.h" #include "chrome/browser/media/media_stream_infobar_delegate.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/renderer_preferences_util.h" @@ -452,6 +453,14 @@ void WebUILoginView::RequestMediaAccessPermission( NOTREACHED() << "Media stream not allowed for WebUI"; } +bool WebUILoginView::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) { + return MediaCaptureDevicesDispatcher::GetInstance() + ->CheckMediaAccessPermission(web_contents, security_origin, type); +} + bool WebUILoginView::PreHandleGestureEvent( content::WebContents* source, const blink::WebGestureEvent& event) { diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.h b/chrome/browser/chromeos/login/ui/webui_login_view.h index 82713db..b48964d 100644 --- a/chrome/browser/chromeos/login/ui/webui_login_view.h +++ b/chrome/browser/chromeos/login/ui/webui_login_view.h @@ -147,6 +147,10 @@ class WebUILoginView : public views::View, content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) OVERRIDE; + virtual bool CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) OVERRIDE; virtual bool PreHandleGestureEvent( content::WebContents* source, const blink::WebGestureEvent& event) OVERRIDE; diff --git a/chrome/browser/extensions/chrome_extension_host_delegate.cc b/chrome/browser/extensions/chrome_extension_host_delegate.cc index 2b23d82..aaf9fca 100644 --- a/chrome/browser/extensions/chrome_extension_host_delegate.cc +++ b/chrome/browser/extensions/chrome_extension_host_delegate.cc @@ -56,4 +56,14 @@ void ChromeExtensionHostDelegate::ProcessMediaAccessRequest( web_contents, request, callback, extension); } +bool ChromeExtensionHostDelegate::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const Extension* extension) { + return MediaCaptureDevicesDispatcher::GetInstance() + ->CheckMediaAccessPermission( + web_contents, security_origin, type, extension); +} + } // namespace extensions diff --git a/chrome/browser/extensions/chrome_extension_host_delegate.h b/chrome/browser/extensions/chrome_extension_host_delegate.h index 207cd68..da8bcb2 100644 --- a/chrome/browser/extensions/chrome_extension_host_delegate.h +++ b/chrome/browser/extensions/chrome_extension_host_delegate.h @@ -32,6 +32,10 @@ class ChromeExtensionHostDelegate : public ExtensionHostDelegate { const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback, const Extension* extension) OVERRIDE; + virtual bool CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const Extension* extension) OVERRIDE; }; } // namespace extensions diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc index 3279b88..07d924c 100644 --- a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc +++ b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc @@ -138,7 +138,18 @@ void ChromeWebViewPermissionHelperDelegate::RequestMediaAccessPermission( false /* allowed_by_default */); } - void ChromeWebViewPermissionHelperDelegate::OnMediaPermissionResponse( +bool ChromeWebViewPermissionHelperDelegate::CheckMediaAccessPermission( + content::WebContents* source, + const GURL& security_origin, + content::MediaStreamType type) { + return web_view_guest() + ->embedder_web_contents() + ->GetDelegate() + ->CheckMediaAccessPermission( + web_view_guest()->embedder_web_contents(), security_origin, type); +} + +void ChromeWebViewPermissionHelperDelegate::OnMediaPermissionResponse( const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback, bool allow, diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h index fbf5bab..d8a9fb2 100644 --- a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h +++ b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h @@ -24,6 +24,10 @@ class ChromeWebViewPermissionHelperDelegate : content::WebContents* source, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) OVERRIDE; + virtual bool CheckMediaAccessPermission( + content::WebContents* source, + const GURL& security_origin, + content::MediaStreamType type) OVERRIDE; virtual void CanDownload( content::RenderViewHost* render_view_host, const GURL& url, diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc index a3a1ddc..ed05b5f 100644 --- a/chrome/browser/media/media_capture_devices_dispatcher.cc +++ b/chrome/browser/media/media_capture_devices_dispatcher.cc @@ -403,6 +403,69 @@ bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission( return false; } +bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE || + type == content::MEDIA_DEVICE_VIDEO_CAPTURE); + + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + + if (CheckAllowAllMediaStreamContentForOrigin(profile, security_origin)) + return true; + + const char* policy_name = type == content::MEDIA_DEVICE_AUDIO_CAPTURE + ? prefs::kAudioCaptureAllowed + : prefs::kVideoCaptureAllowed; + const char* list_policy_name = type == content::MEDIA_DEVICE_AUDIO_CAPTURE + ? prefs::kAudioCaptureAllowedUrls + : prefs::kVideoCaptureAllowedUrls; + if (GetDevicePolicy( + profile, security_origin, policy_name, list_policy_name) == + ALWAYS_ALLOW) { + return true; + } + + // There's no secondary URL for these content types, hence duplicating + // |security_origin|. + if (profile->GetHostContentSettingsMap()->GetContentSetting( + security_origin, + security_origin, + type == content::MEDIA_DEVICE_AUDIO_CAPTURE + ? CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC + : CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, + NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_ALLOW) { + return true; + } + + return false; +} + +#if defined(ENABLE_EXTENSIONS) +bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const extensions::Extension* extension) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE || + type == content::MEDIA_DEVICE_VIDEO_CAPTURE); + + if (extension->is_platform_app() || + IsMediaRequestWhitelistedForExtension(extension)) { + return extension->permissions_data()->HasAPIPermission( + type == content::MEDIA_DEVICE_AUDIO_CAPTURE + ? extensions::APIPermission::kAudioCapture + : extensions::APIPermission::kVideoCapture); + } + + return CheckMediaAccessPermission(web_contents, security_origin, type); +} +#endif + void MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest( content::WebContents* web_contents, const content::MediaStreamRequest& request, diff --git a/chrome/browser/media/media_capture_devices_dispatcher.h b/chrome/browser/media/media_capture_devices_dispatcher.h index 162c654..a6930ad 100644 --- a/chrome/browser/media/media_capture_devices_dispatcher.h +++ b/chrome/browser/media/media_capture_devices_dispatcher.h @@ -90,6 +90,20 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver, const GURL& security_origin, content::MediaStreamType type); + // Method called from WebCapturerDelegate implementations to check media + // access permission. Note that this does not query the user. + bool CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type); + + // Same as above but for an |extension|, which may not be NULL. +#if defined(ENABLE_EXTENSIONS) + bool CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const extensions::Extension* extension); +#endif + // Helper to get the default devices which can be used by the media request. // Uses the first available devices if the default devices are not available. // If the return list is empty, it means there is no available device on the diff --git a/chrome/browser/ui/app_list/start_page_service.cc b/chrome/browser/ui/app_list/start_page_service.cc index 3615a6e..8392be2 100644 --- a/chrome/browser/ui/app_list/start_page_service.cc +++ b/chrome/browser/ui/app_list/start_page_service.cc @@ -88,6 +88,14 @@ class StartPageService::StartPageWebContentsDelegate NOTREACHED() << "Media stream not allowed for WebUI"; } + virtual bool CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) OVERRIDE { + return MediaCaptureDevicesDispatcher::GetInstance() + ->CheckMediaAccessPermission(web_contents, security_origin, type); + } + private: DISALLOW_COPY_AND_ASSIGN(StartPageWebContentsDelegate); }; diff --git a/chrome/browser/ui/apps/chrome_app_delegate.cc b/chrome/browser/ui/apps/chrome_app_delegate.cc index 2cf0588..d146250 100644 --- a/chrome/browser/ui/apps/chrome_app_delegate.cc +++ b/chrome/browser/ui/apps/chrome_app_delegate.cc @@ -245,6 +245,16 @@ void ChromeAppDelegate::RequestMediaAccessPermission( web_contents, request, callback, extension); } +bool ChromeAppDelegate::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const extensions::Extension* extension) { + return MediaCaptureDevicesDispatcher::GetInstance() + ->CheckMediaAccessPermission( + web_contents, security_origin, type, extension); +} + int ChromeAppDelegate::PreferredIconSize() { #if defined(USE_ASH) return ash::kShelfSize; diff --git a/chrome/browser/ui/apps/chrome_app_delegate.h b/chrome/browser/ui/apps/chrome_app_delegate.h index 382dda4..3e9e444 100644 --- a/chrome/browser/ui/apps/chrome_app_delegate.h +++ b/chrome/browser/ui/apps/chrome_app_delegate.h @@ -54,6 +54,11 @@ class ChromeAppDelegate : public extensions::AppDelegate, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback, const extensions::Extension* extension) OVERRIDE; + virtual bool CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const extensions::Extension* extension) OVERRIDE; virtual int PreferredIconSize() OVERRIDE; virtual gfx::ImageSkia GetAppDefaultIcon() OVERRIDE; virtual void SetWebContentsBlocked(content::WebContents* web_contents, diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 6770f8e..0525e02 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc @@ -1759,6 +1759,12 @@ void Browser::RequestMediaAccessPermission( ::RequestMediaAccessPermission(web_contents, profile_, request, callback); } +bool Browser::CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) { + return ::CheckMediaAccessPermission(web_contents, security_origin, type); +} + bool Browser::RequestPpapiBrokerPermission( WebContents* web_contents, const GURL& url, diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index 5f358cb..02e343c 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h @@ -647,6 +647,10 @@ class Browser : public TabStripModelObserver, content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) OVERRIDE; + virtual bool CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) OVERRIDE; virtual bool RequestPpapiBrokerPermission( content::WebContents* web_contents, const GURL& url, diff --git a/chrome/browser/ui/media_utils.cc b/chrome/browser/ui/media_utils.cc index 7101cc4..52d4633 100644 --- a/chrome/browser/ui/media_utils.cc +++ b/chrome/browser/ui/media_utils.cc @@ -6,6 +6,7 @@ #include "chrome/browser/media/media_capture_devices_dispatcher.h" #include "chrome/browser/profiles/profile.h" +#include "content/public/browser/web_contents.h" #if defined(ENABLE_EXTENSIONS) #include "chrome/browser/extensions/extension_service.h" @@ -13,11 +14,24 @@ #include "extensions/common/constants.h" #endif -class Profile; +namespace { -namespace content { -class WebContents; +#if defined(ENABLE_EXTENSIONS) +const extensions::Extension* GetExtensionForOrigin(Profile* profile, + const GURL& security_origin) { + if (!security_origin.SchemeIs(extensions::kExtensionScheme)) + return NULL; + + ExtensionService* extensions_service = + extensions::ExtensionSystem::Get(profile)->extension_service(); + const extensions::Extension* extension = + extensions_service->extensions()->GetByID(security_origin.host()); + DCHECK(extension); + return extension; } +#endif + +} // namespace void RequestMediaAccessPermission( content::WebContents* web_contents, @@ -26,15 +40,29 @@ void RequestMediaAccessPermission( const content::MediaResponseCallback& callback) { const extensions::Extension* extension = NULL; #if defined(ENABLE_EXTENSIONS) - GURL origin(request.security_origin); - if (origin.SchemeIs(extensions::kExtensionScheme)) { - ExtensionService* extensions_service = - extensions::ExtensionSystem::Get(profile)->extension_service(); - extension = extensions_service->extensions()->GetByID(origin.host()); - DCHECK(extension); - } + extension = GetExtensionForOrigin(profile, request.security_origin); #endif - MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest( web_contents, request, callback, extension); } + +bool CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) { +#if defined(ENABLE_EXTENSIONS) + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + const extensions::Extension* extension = + GetExtensionForOrigin(profile, security_origin); + if (extension) { + return MediaCaptureDevicesDispatcher::GetInstance() + ->CheckMediaAccessPermission( + web_contents, security_origin, type, extension); + } + return MediaCaptureDevicesDispatcher::GetInstance() + ->CheckMediaAccessPermission(web_contents, security_origin, type); +#else + return MediaCaptureDevicesDispatcher::GetInstance() + ->CheckMediaAccessPermission(web_contents, security_origin, type); +#endif +} diff --git a/chrome/browser/ui/media_utils.h b/chrome/browser/ui/media_utils.h index 8da821b..5db46e6 100644 --- a/chrome/browser/ui/media_utils.h +++ b/chrome/browser/ui/media_utils.h @@ -5,8 +5,10 @@ #ifndef CHROME_BROWSER_UI_MEDIA_UTILS_H_ #define CHROME_BROWSER_UI_MEDIA_UTILS_H_ +#include "base/callback.h" #include "content/public/common/media_stream_request.h" +class GURL; class Profile; namespace content { @@ -19,4 +21,8 @@ void RequestMediaAccessPermission( const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback); +bool CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type); + #endif // CHROME_BROWSER_UI_MEDIA_UTILS_H_ diff --git a/content/browser/frame_host/render_frame_host_delegate.cc b/content/browser/frame_host/render_frame_host_delegate.cc index ea95490..b96f2b5 100644 --- a/content/browser/frame_host/render_frame_host_delegate.cc +++ b/content/browser/frame_host/render_frame_host_delegate.cc @@ -44,6 +44,14 @@ void RenderFrameHostDelegate::RequestMediaAccessPermission( scoped_ptr<MediaStreamUI>()); } +bool RenderFrameHostDelegate::CheckMediaAccessPermission( + const GURL& security_origin, + MediaStreamType type) { + DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || + type == MEDIA_DEVICE_VIDEO_CAPTURE); + return false; +} + AccessibilityMode RenderFrameHostDelegate::GetAccessibilityMode() const { return AccessibilityModeOff; } diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h index b0ebe38..0d927a4 100644 --- a/content/browser/frame_host/render_frame_host_delegate.h +++ b/content/browser/frame_host/render_frame_host_delegate.h @@ -130,6 +130,12 @@ class CONTENT_EXPORT RenderFrameHostDelegate { const MediaStreamRequest& request, const MediaResponseCallback& callback); + // Checks if we have permission to access the microphone or camera. Note that + // this does not query the user. |type| must be MEDIA_DEVICE_AUDIO_CAPTURE + // or MEDIA_DEVICE_VIDEO_CAPTURE. + virtual bool CheckMediaAccessPermission(const GURL& security_origin, + MediaStreamType type); + // Get the accessibility mode for the WebContents that owns this frame. virtual AccessibilityMode GetAccessibilityMode() const; diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc index 5f4b7e96..ba78d44 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc @@ -212,39 +212,6 @@ class MockMediaStreamUIProxy : public FakeMediaStreamUIProxy { const MediaStreamUIProxy::WindowIdCallback& window_id_callback)); }; -class MediaStreamManagerForTest : public MediaStreamManager { - public: - MediaStreamManagerForTest(media::AudioManager* audio_manager) - : MediaStreamManager(audio_manager), - mic_access_(true), - camera_access_(true) {} - - virtual ~MediaStreamManagerForTest() {} - - void set_mic_access(bool allow_access) { - mic_access_ = allow_access; - } - - void set_camera_access(bool allow_access) { - camera_access_ = allow_access; - } - - private: - virtual bool CheckMediaAccessPermissionOnUIThread( - int render_process_id, - const GURL& security_origin, - MediaStreamType type) OVERRIDE { - if (type == MEDIA_DEVICE_AUDIO_CAPTURE) - return mic_access_; - else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) - return camera_access_; - return false; - } - - bool mic_access_; - bool camera_access_; -}; - class MediaStreamDispatcherHostTest : public testing::Test { public: MediaStreamDispatcherHostTest() @@ -257,8 +224,7 @@ class MediaStreamDispatcherHostTest : public testing::Test { base::CommandLine::ForCurrentProcess()->AppendSwitch( switches::kUseFakeDeviceForMediaStream); // Create our own MediaStreamManager. - media_stream_manager_.reset( - new MediaStreamManagerForTest(audio_manager_.get())); + media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get())); video_capture_device_factory_ = static_cast<media::FakeVideoCaptureDeviceFactory*>( media_stream_manager_->video_capture_manager() @@ -298,12 +264,12 @@ class MediaStreamDispatcherHostTest : public testing::Test { protected: virtual void SetupFakeUI(bool expect_started) { - scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy()); + stream_ui_ = new MockMediaStreamUIProxy(); if (expect_started) { - EXPECT_CALL(*stream_ui, OnStarted(_, _)); + EXPECT_CALL(*stream_ui_, OnStarted(_, _)); } media_stream_manager_->UseFakeUI( - stream_ui.PassAs<FakeMediaStreamUIProxy>()); + scoped_ptr<FakeMediaStreamUIProxy>(stream_ui_)); } void GenerateStreamAndWaitForResult(int render_frame_id, @@ -446,7 +412,8 @@ class MediaStreamDispatcherHostTest : public testing::Test { scoped_refptr<MockMediaStreamDispatcherHost> host_; scoped_ptr<media::AudioManager> audio_manager_; - scoped_ptr<MediaStreamManagerForTest> media_stream_manager_; + scoped_ptr<MediaStreamManager> media_stream_manager_; + MockMediaStreamUIProxy* stream_ui_; ContentBrowserClient* old_browser_client_; scoped_ptr<ContentClient> content_client_; content::TestBrowserThreadBundle thread_bundle_; @@ -911,26 +878,30 @@ TEST_F(MediaStreamDispatcherHostTest, VideoDeviceUnplugged) { } TEST_F(MediaStreamDispatcherHostTest, EnumerateAudioDevices) { + SetupFakeUI(false); EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId, MEDIA_DEVICE_AUDIO_CAPTURE); EXPECT_TRUE(DoesContainLabels(host_->enumerated_devices_)); } TEST_F(MediaStreamDispatcherHostTest, EnumerateVideoDevices) { + SetupFakeUI(false); EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId, MEDIA_DEVICE_VIDEO_CAPTURE); EXPECT_TRUE(DoesContainLabels(host_->enumerated_devices_)); } TEST_F(MediaStreamDispatcherHostTest, EnumerateAudioDevicesNoAccess) { - media_stream_manager_->set_mic_access(false); + SetupFakeUI(false); + stream_ui_->SetMicAccess(false); EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId, MEDIA_DEVICE_AUDIO_CAPTURE); EXPECT_TRUE(DoesNotContainLabels(host_->enumerated_devices_)); } TEST_F(MediaStreamDispatcherHostTest, EnumerateVideoDevicesNoAccess) { - media_stream_manager_->set_camera_access(false); + SetupFakeUI(false); + stream_ui_->SetCameraAccess(false); EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId, MEDIA_DEVICE_VIDEO_CAPTURE); EXPECT_TRUE(DoesNotContainLabels(host_->enumerated_devices_)); diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index 991d174..4080cbe 100644 --- a/content/browser/renderer_host/media/media_stream_manager.cc +++ b/content/browser/renderer_host/media/media_stream_manager.cc @@ -1472,6 +1472,14 @@ void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label, request->devices.clear(); } + if (use_fake_ui_) { + if (!fake_ui_) + fake_ui_.reset(new FakeMediaStreamUIProxy()); + request->ui_proxy = fake_ui_.Pass(); + } else { + request->ui_proxy = MediaStreamUIProxy::Create(); + } + // Output label permissions are based on input permission. MediaStreamType type = request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE || @@ -1479,40 +1487,16 @@ void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label, ? MEDIA_DEVICE_AUDIO_CAPTURE : MEDIA_DEVICE_VIDEO_CAPTURE; - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::UI, - FROM_HERE, - base::Bind(&MediaStreamManager::CheckMediaAccessPermissionOnUIThread, - base::Unretained(this), - request->requesting_process_id, - request->security_origin, - type), + request->ui_proxy->CheckAccess( + request->security_origin, + type, + request->requesting_process_id, + request->requesting_frame_id, base::Bind(&MediaStreamManager::HandleCheckMediaAccessResponse, base::Unretained(this), label)); } -bool MediaStreamManager::CheckMediaAccessPermissionOnUIThread( - int render_process_id, - const GURL& security_origin, - MediaStreamType type) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - RenderProcessHost* host = - RenderProcessHost::FromID(render_process_id); - if (!host) { - // This can happen if the renderer goes away during the lifetime of a - // request. - return false; - } - content::BrowserContext* context = host->GetBrowserContext(); - DCHECK(context); - return GetContentClient()->browser()->CheckMediaAccessPermission( - context, - security_origin, - type); -} - void MediaStreamManager::HandleCheckMediaAccessResponse( const std::string& label, bool have_access) { diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h index 50cef78..1eba375 100644 --- a/content/browser/renderer_host/media/media_stream_manager.h +++ b/content/browser/renderer_host/media/media_stream_manager.h @@ -321,11 +321,6 @@ class CONTENT_EXPORT MediaStreamManager const MediaStreamDevices& devices); void FinalizeEnumerateDevices(const std::string& label, DeviceRequest* request); - - // Checks for media access. Overridden by unit tests. - virtual bool CheckMediaAccessPermissionOnUIThread(int render_process_id, - const GURL& security_origin, - MediaStreamType type); void HandleCheckMediaAccessResponse(const std::string& label, bool have_access); diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy.cc b/content/browser/renderer_host/media/media_stream_ui_proxy.cc index 837577a..c4eb0d7 100644 --- a/content/browser/renderer_host/media/media_stream_ui_proxy.cc +++ b/content/browser/renderer_host/media/media_stream_ui_proxy.cc @@ -20,6 +20,10 @@ class MediaStreamUIProxy::Core { ~Core(); void RequestAccess(const MediaStreamRequest& request); + bool CheckAccess(const GURL& security_origin, + MediaStreamType type, + int process_id, + int frame_id); void OnStarted(gfx::NativeViewId* window_id); private: @@ -27,6 +31,8 @@ class MediaStreamUIProxy::Core { content::MediaStreamRequestResult result, scoped_ptr<MediaStreamUI> stream_ui); void ProcessStopRequestFromUI(); + RenderFrameHostDelegate* GetRenderFrameHostDelegate(int render_process_id, + int render_frame_id); base::WeakPtr<MediaStreamUIProxy> proxy_; scoped_ptr<MediaStreamUI> ui_; @@ -55,14 +61,8 @@ void MediaStreamUIProxy::Core::RequestAccess( const MediaStreamRequest& request) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - RenderFrameHostDelegate* render_delegate; - if (test_render_delegate_) { - render_delegate = test_render_delegate_; - } else { - RenderFrameHostImpl* const host = RenderFrameHostImpl::FromID( - request.render_process_id, request.render_frame_id); - render_delegate = host ? host->delegate() : NULL; - } + RenderFrameHostDelegate* render_delegate = GetRenderFrameHostDelegate( + request.render_process_id, request.render_frame_id); // Tab may have gone away, or has no delegate from which to request access. if (!render_delegate) { @@ -78,6 +78,20 @@ void MediaStreamUIProxy::Core::RequestAccess( weak_factory_.GetWeakPtr())); } +bool MediaStreamUIProxy::Core::CheckAccess(const GURL& security_origin, + MediaStreamType type, + int render_process_id, + int render_frame_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + RenderFrameHostDelegate* render_delegate = + GetRenderFrameHostDelegate(render_process_id, render_frame_id); + if (!render_delegate) + return false; + + return render_delegate->CheckMediaAccessPermission(security_origin, type); +} + void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (ui_) { @@ -107,6 +121,16 @@ void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() { base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI, proxy_)); } +RenderFrameHostDelegate* MediaStreamUIProxy::Core::GetRenderFrameHostDelegate( + int render_process_id, + int render_frame_id) { + if (test_render_delegate_) + return test_render_delegate_; + RenderFrameHostImpl* host = + RenderFrameHostImpl::FromID(render_process_id, render_frame_id); + return host ? host->delegate() : NULL; +} + // static scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() { return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL)); @@ -141,6 +165,28 @@ void MediaStreamUIProxy::RequestAccess( base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request)); } +void MediaStreamUIProxy::CheckAccess( + const GURL& security_origin, + MediaStreamType type, + int render_process_id, + int render_frame_id, + const base::Callback<void(bool)>& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + BrowserThread::PostTaskAndReplyWithResult( + BrowserThread::UI, + FROM_HERE, + base::Bind(&Core::CheckAccess, + base::Unretained(core_.get()), + security_origin, + type, + render_process_id, + render_frame_id), + base::Bind(&MediaStreamUIProxy::OnCheckedAccess, + weak_factory_.GetWeakPtr(), + callback)); +} + void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback, const WindowIdCallback& window_id_callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -160,13 +206,6 @@ void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback, base::Owned(window_id))); } -void MediaStreamUIProxy::OnWindowId(const WindowIdCallback& window_id_callback, - gfx::NativeViewId* window_id) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!window_id_callback.is_null()) - window_id_callback.Run(*window_id); -} - void MediaStreamUIProxy::ProcessAccessRequestResponse( const MediaStreamDevices& devices, content::MediaStreamRequestResult result) { @@ -187,8 +226,25 @@ void MediaStreamUIProxy::ProcessStopRequestFromUI() { cb.Run(); } +void MediaStreamUIProxy::OnWindowId(const WindowIdCallback& window_id_callback, + gfx::NativeViewId* window_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!window_id_callback.is_null()) + window_id_callback.Run(*window_id); +} + +void MediaStreamUIProxy::OnCheckedAccess( + const base::Callback<void(bool)>& callback, + bool have_access) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!callback.is_null()) + callback.Run(have_access); +} + FakeMediaStreamUIProxy::FakeMediaStreamUIProxy() - : MediaStreamUIProxy(NULL) { + : MediaStreamUIProxy(NULL), + mic_access_(true), + camera_access_(true) { } FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {} @@ -198,6 +254,14 @@ void FakeMediaStreamUIProxy::SetAvailableDevices( devices_ = devices; } +void FakeMediaStreamUIProxy::SetMicAccess(bool access) { + mic_access_ = access; +} + +void FakeMediaStreamUIProxy::SetCameraAccess(bool access) { + camera_access_ = access; +} + void FakeMediaStreamUIProxy::RequestAccess( const MediaStreamRequest& request, const ResponseCallback& response_callback) { @@ -242,7 +306,7 @@ void FakeMediaStreamUIProxy::RequestAccess( } } - // Fail the request if a device exist for the requested type. + // Fail the request if a device doesn't exist for the requested type. if ((request.audio_type != MEDIA_NO_SERVICE && !accepted_audio) || (request.video_type != MEDIA_NO_SERVICE && !accepted_video)) { devices_to_use.clear(); @@ -258,6 +322,33 @@ void FakeMediaStreamUIProxy::RequestAccess( MEDIA_DEVICE_OK)); } +void FakeMediaStreamUIProxy::CheckAccess( + const GURL& security_origin, + MediaStreamType type, + int render_process_id, + int render_frame_id, + const base::Callback<void(bool)>& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || + type == MEDIA_DEVICE_VIDEO_CAPTURE); + + bool have_access = false; + if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kUseFakeUIForMediaStream) != "deny") { + have_access = + type == MEDIA_DEVICE_AUDIO_CAPTURE ? mic_access_ : camera_access_; + } + + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&MediaStreamUIProxy::OnCheckedAccess, + weak_factory_.GetWeakPtr(), + callback, + have_access)); + return; +} + void FakeMediaStreamUIProxy::OnStarted( const base::Closure& stop_callback, const WindowIdCallback& window_id_callback) {} diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy.h b/content/browser/renderer_host/media/media_stream_ui_proxy.h index 810a29a..cf5ba1a 100644 --- a/content/browser/renderer_host/media/media_stream_ui_proxy.h +++ b/content/browser/renderer_host/media/media_stream_ui_proxy.h @@ -41,6 +41,16 @@ class CONTENT_EXPORT MediaStreamUIProxy { virtual void RequestAccess(const MediaStreamRequest& request, const ResponseCallback& response_callback); + // Checks if we have permission to access the microphone or camera. Note that + // this does not query the user, it checks any stored settings such as policy + // or extension permissions. |type| must be MEDIA_DEVICE_AUDIO_CAPTURE + // or MEDIA_DEVICE_VIDEO_CAPTURE. + virtual void CheckAccess(const GURL& security_origin, + MediaStreamType type, + int render_process_id, + int render_frame_id, + const base::Callback<void(bool)>& callback); + // Notifies the UI that the MediaStream has been started. Must be called after // access has been approved using RequestAccess(). |stop_callback| is be // called on the IO thread after the user has requests the stream to be @@ -65,6 +75,8 @@ class CONTENT_EXPORT MediaStreamUIProxy { void ProcessStopRequestFromUI(); void OnWindowId(const WindowIdCallback& window_id_callback, gfx::NativeViewId* window_id); + void OnCheckedAccess(const base::Callback<void(bool)>& callback, + bool have_access); scoped_ptr<Core, content::BrowserThread::DeleteOnUIThread> core_; ResponseCallback response_callback_; @@ -81,17 +93,29 @@ class CONTENT_EXPORT FakeMediaStreamUIProxy : public MediaStreamUIProxy { virtual ~FakeMediaStreamUIProxy(); void SetAvailableDevices(const MediaStreamDevices& devices); + void SetMicAccess(bool access); + void SetCameraAccess(bool access); // MediaStreamUIProxy overrides. virtual void RequestAccess( const MediaStreamRequest& request, const ResponseCallback& response_callback) OVERRIDE; + virtual void CheckAccess(const GURL& security_origin, + MediaStreamType type, + int render_process_id, + int render_frame_id, + const base::Callback<void(bool)>& callback) OVERRIDE; virtual void OnStarted(const base::Closure& stop_callback, const WindowIdCallback& window_id_callback) OVERRIDE; private: + // This is used for RequestAccess(). MediaStreamDevices devices_; + // These are used for CheckAccess(). + bool mic_access_; + bool camera_access_; + DISALLOW_COPY_AND_ASSIGN(FakeMediaStreamUIProxy); }; diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc index 3bc1b06..e729717 100644 --- a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc +++ b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc @@ -24,6 +24,9 @@ class MockRenderFrameHostDelegate : public RenderFrameHostDelegate { MOCK_METHOD2(RequestMediaAccessPermission, void(const MediaStreamRequest& request, const MediaResponseCallback& callback)); + MOCK_METHOD2(CheckMediaAccessPermission, + bool(const GURL& security_origin, + MediaStreamType type)); }; class MockResponseCallback { @@ -31,6 +34,7 @@ class MockResponseCallback { MOCK_METHOD2(OnAccessRequestResponse, void(const MediaStreamDevices& devices, content::MediaStreamRequestResult result)); + MOCK_METHOD1(OnCheckResponse, void(bool have_access)); }; class MockMediaStreamUI : public MediaStreamUI { @@ -247,4 +251,16 @@ TEST_F(MediaStreamUIProxyTest, WindowIdCallbackCalled) { message_loop_.RunUntilIdle(); } +TEST_F(MediaStreamUIProxyTest, CheckAccess) { + proxy_->CheckAccess(GURL("http://origin/"), + MEDIA_DEVICE_AUDIO_CAPTURE, + 0, + 0, + base::Bind(&MockResponseCallback::OnCheckResponse, + base::Unretained(&response_callback_))); + EXPECT_CALL(delegate_, CheckMediaAccessPermission(_, _)); + EXPECT_CALL(response_callback_, OnCheckResponse(_)); + message_loop_.RunUntilIdle(); +} + } // content diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 8cf5a0f..976c921 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -1779,6 +1779,14 @@ void WebContentsImpl::RequestMediaAccessPermission( } } +bool WebContentsImpl::CheckMediaAccessPermission(const GURL& security_origin, + MediaStreamType type) { + DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || + type == MEDIA_DEVICE_VIDEO_CAPTURE); + return delegate_ && + delegate_->CheckMediaAccessPermission(this, security_origin, type); +} + SessionStorageNamespace* WebContentsImpl::GetSessionStorageNamespace( SiteInstance* instance) { return controller_.GetSessionStorageNamespace(instance); diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index c50025c..dd998c6 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h @@ -477,6 +477,8 @@ class CONTENT_EXPORT WebContentsImpl virtual void RequestMediaAccessPermission( const MediaStreamRequest& request, const MediaResponseCallback& callback) OVERRIDE; + virtual bool CheckMediaAccessPermission(const GURL& security_origin, + MediaStreamType type) OVERRIDE; virtual SessionStorageNamespace* GetSessionStorageNamespace( SiteInstance* instance) OVERRIDE; virtual SessionStorageNamespaceMap GetSessionStorageNamespaceMap() OVERRIDE; diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc index 0028339..d930aed 100644 --- a/content/public/browser/web_contents_delegate.cc +++ b/content/public/browser/web_contents_delegate.cc @@ -169,6 +169,15 @@ void WebContentsDelegate::RequestMediaAccessPermission( scoped_ptr<MediaStreamUI>()); } +bool WebContentsDelegate::CheckMediaAccessPermission( + WebContents* web_contents, + const GURL& security_origin, + MediaStreamType type) { + DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || + type == MEDIA_DEVICE_VIDEO_CAPTURE); + return false; +} + bool WebContentsDelegate::RequestPpapiBrokerPermission( WebContents* web_contents, const GURL& url, diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h index b9aa02d..d040256 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h @@ -444,6 +444,13 @@ class CONTENT_EXPORT WebContentsDelegate { const MediaStreamRequest& request, const MediaResponseCallback& callback); + // Checks if we have permission to access the microphone or camera. Note that + // this does not query the user. |type| must be MEDIA_DEVICE_AUDIO_CAPTURE + // or MEDIA_DEVICE_VIDEO_CAPTURE. + virtual bool CheckMediaAccessPermission(WebContents* web_contents, + const GURL& security_origin, + MediaStreamType type); + // Requests permission to access the PPAPI broker. The delegate should return // true and call the passed in |callback| with the result, or return false // to indicate that it does not support asking for permission. diff --git a/extensions/browser/app_window/app_delegate.h b/extensions/browser/app_window/app_delegate.h index 7b247af..2d5fa1d 100644 --- a/extensions/browser/app_window/app_delegate.h +++ b/extensions/browser/app_window/app_delegate.h @@ -63,6 +63,10 @@ class AppDelegate { const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback, const Extension* extension) = 0; + virtual bool CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const Extension* extension) = 0; virtual int PreferredIconSize() = 0; virtual gfx::ImageSkia GetAppDefaultIcon() = 0; diff --git a/extensions/browser/app_window/app_web_contents_helper.cc b/extensions/browser/app_window/app_web_contents_helper.cc index 54153ac..fb66479 100644 --- a/extensions/browser/app_window/app_web_contents_helper.cc +++ b/extensions/browser/app_window/app_web_contents_helper.cc @@ -97,6 +97,17 @@ void AppWebContentsHelper::RequestMediaAccessPermission( web_contents_, request, callback, extension); } +bool AppWebContentsHelper::CheckMediaAccessPermission( + const GURL& security_origin, + content::MediaStreamType type) const { + const Extension* extension = GetExtension(); + if (!extension) + return false; + + return app_delegate_->CheckMediaAccessPermission( + web_contents_, security_origin, type, extension); +} + const Extension* AppWebContentsHelper::GetExtension() const { return ExtensionRegistry::Get(browser_context_) ->enabled_extensions() diff --git a/extensions/browser/app_window/app_web_contents_helper.h b/extensions/browser/app_window/app_web_contents_helper.h index 3d17851..ea4f13e 100644 --- a/extensions/browser/app_window/app_web_contents_helper.h +++ b/extensions/browser/app_window/app_web_contents_helper.h @@ -48,6 +48,11 @@ class AppWebContentsHelper { const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) const; + // Checks permission to use the camera or microphone. See + // WebContentsDelegate. + bool CheckMediaAccessPermission(const GURL& security_origin, + content::MediaStreamType type) const; + private: const Extension* GetExtension() const; diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc index 3218a24..1cc9ae2 100644 --- a/extensions/browser/app_window/app_window.cc +++ b/extensions/browser/app_window/app_window.cc @@ -346,6 +346,13 @@ void AppWindow::RequestMediaAccessPermission( helper_->RequestMediaAccessPermission(request, callback); } +bool AppWindow::CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) { + DCHECK_EQ(AppWindow::web_contents(), web_contents); + return helper_->CheckMediaAccessPermission(security_origin, type); +} + WebContents* AppWindow::OpenURLFromTab(WebContents* source, const content::OpenURLParams& params) { DCHECK_EQ(web_contents(), source); diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h index 7b84ed7..3cef2ed 100644 --- a/extensions/browser/app_window/app_window.h +++ b/extensions/browser/app_window/app_window.h @@ -382,6 +382,10 @@ class AppWindow : public content::WebContentsDelegate, content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) OVERRIDE; + virtual bool CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) OVERRIDE; virtual content::WebContents* OpenURLFromTab( content::WebContents* source, const content::OpenURLParams& params) OVERRIDE; diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc index 2f0572e..3920e47 100644 --- a/extensions/browser/extension_host.cc +++ b/extensions/browser/extension_host.cc @@ -428,6 +428,14 @@ void ExtensionHost::RequestMediaAccessPermission( web_contents, request, callback, extension()); } +bool ExtensionHost::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) { + return delegate_->CheckMediaAccessPermission( + web_contents, security_origin, type, extension()); +} + bool ExtensionHost::IsNeverVisible(content::WebContents* web_contents) { ViewType view_type = extensions::GetViewType(web_contents); return view_type == extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE; diff --git a/extensions/browser/extension_host.h b/extensions/browser/extension_host.h index 24bd9ba..548e8f8 100644 --- a/extensions/browser/extension_host.h +++ b/extensions/browser/extension_host.h @@ -101,6 +101,10 @@ class ExtensionHost : public content::WebContentsDelegate, content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) OVERRIDE; + virtual bool CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type) OVERRIDE; virtual bool IsNeverVisible(content::WebContents* web_contents) OVERRIDE; // content::NotificationObserver diff --git a/extensions/browser/extension_host_delegate.h b/extensions/browser/extension_host_delegate.h index 0bf52a4..b14580d 100644 --- a/extensions/browser/extension_host_delegate.h +++ b/extensions/browser/extension_host_delegate.h @@ -56,6 +56,14 @@ class ExtensionHostDelegate { const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback, const Extension* extension) = 0; + + // Checks if we have permission to access the microphone or camera. Note that + // this does not query the user. |type| must be MEDIA_DEVICE_AUDIO_CAPTURE + // or MEDIA_DEVICE_VIDEO_CAPTURE. + virtual bool CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const Extension* extension) = 0; }; } // namespace extensions diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc index 0522514..bfc29f5 100644 --- a/extensions/browser/guest_view/web_view/web_view_guest.cc +++ b/extensions/browser/guest_view/web_view/web_view_guest.cc @@ -791,6 +791,13 @@ void WebViewGuest::RequestMediaAccessPermission( callback); } +bool WebViewGuest::CheckMediaAccessPermission(content::WebContents* source, + const GURL& security_origin, + content::MediaStreamType type) { + return web_view_permission_helper_->CheckMediaAccessPermission( + source, security_origin, type); +} + void WebViewGuest::CanDownload( content::RenderViewHost* render_view_host, const GURL& url, diff --git a/extensions/browser/guest_view/web_view/web_view_guest.h b/extensions/browser/guest_view/web_view/web_view_guest.h index 926a67b..f593213 100644 --- a/extensions/browser/guest_view/web_view/web_view_guest.h +++ b/extensions/browser/guest_view/web_view/web_view_guest.h @@ -121,6 +121,10 @@ class WebViewGuest : public GuestView<WebViewGuest>, content::WebContents* source, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) OVERRIDE; + virtual bool CheckMediaAccessPermission( + content::WebContents* source, + const GURL& security_origin, + content::MediaStreamType type) OVERRIDE; virtual void CanDownload(content::RenderViewHost* render_view_host, const GURL& url, const std::string& request_method, diff --git a/extensions/browser/guest_view/web_view/web_view_permission_helper.cc b/extensions/browser/guest_view/web_view/web_view_permission_helper.cc index 079282b..d713279 100644 --- a/extensions/browser/guest_view/web_view/web_view_permission_helper.cc +++ b/extensions/browser/guest_view/web_view/web_view_permission_helper.cc @@ -180,10 +180,18 @@ void WebViewPermissionHelper::RequestMediaAccessPermission( content::WebContents* source, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) { - web_view_permission_helper_delegate_-> RequestMediaAccessPermission( + web_view_permission_helper_delegate_->RequestMediaAccessPermission( source, request, callback); } +bool WebViewPermissionHelper::CheckMediaAccessPermission( + content::WebContents* source, + const GURL& security_origin, + content::MediaStreamType type) { + return web_view_permission_helper_delegate_->CheckMediaAccessPermission( + source, security_origin, type); +} + void WebViewPermissionHelper::CanDownload( content::RenderViewHost* render_view_host, const GURL& url, diff --git a/extensions/browser/guest_view/web_view/web_view_permission_helper.h b/extensions/browser/guest_view/web_view/web_view_permission_helper.h index db9f1ab..8fb9037 100644 --- a/extensions/browser/guest_view/web_view/web_view_permission_helper.h +++ b/extensions/browser/guest_view/web_view/web_view_permission_helper.h @@ -60,6 +60,9 @@ class WebViewPermissionHelper content::WebContents* source, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback); + bool CheckMediaAccessPermission(content::WebContents* source, + const GURL& security_origin, + content::MediaStreamType type); void CanDownload(content::RenderViewHost* render_view_host, const GURL& url, const std::string& request_method, diff --git a/extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.cc b/extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.cc index 1ce7c28..4fbbef8 100644 --- a/extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.cc +++ b/extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.cc @@ -18,4 +18,12 @@ WebViewPermissionHelperDelegate::WebViewPermissionHelperDelegate( WebViewPermissionHelperDelegate::~WebViewPermissionHelperDelegate() { } +bool WebViewPermissionHelperDelegate::CheckMediaAccessPermission( + content::WebContents* source, + const GURL& security_origin, + content::MediaStreamType type) { + // Defensive default implementation for privacy reasons. + return false; +} + } // namespace extensions diff --git a/extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.h b/extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.h index b43b73a..d919105 100644 --- a/extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.h +++ b/extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.h @@ -25,6 +25,10 @@ class WebViewPermissionHelperDelegate : public content::WebContentsObserver { const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) {} + virtual bool CheckMediaAccessPermission(content::WebContents* source, + const GURL& security_origin, + content::MediaStreamType type); + virtual void CanDownload( content::RenderViewHost* render_view_host, const GURL& url, diff --git a/extensions/shell/browser/media_capture_util.cc b/extensions/shell/browser/media_capture_util.cc index 364e19d..30e3fb6 100644 --- a/extensions/shell/browser/media_capture_util.cc +++ b/extensions/shell/browser/media_capture_util.cc @@ -42,14 +42,9 @@ void GrantMediaStreamRequest(content::WebContents* web_contents, request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE); MediaStreamDevices devices; - const PermissionsData* permissions_data = extension->permissions_data(); if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) { - // app_shell has no UI surface to show an error, and on an embedded device - // it's better to crash than to have a feature not work. - CHECK(permissions_data->HasAPIPermission(APIPermission::kAudioCapture)) - << "Audio capture request but no audioCapture permission in manifest."; - + VerifyMediaAccessPermission(request.audio_type, extension); const MediaStreamDevice* device = GetRequestedDeviceOrDefault( MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices(), request.requested_audio_device_id); @@ -58,10 +53,7 @@ void GrantMediaStreamRequest(content::WebContents* web_contents, } if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) { - // See APIPermission::kAudioCapture check above. - CHECK(permissions_data->HasAPIPermission(APIPermission::kVideoCapture)) - << "Video capture request but no videoCapture permission in manifest."; - + VerifyMediaAccessPermission(request.video_type, extension); const MediaStreamDevice* device = GetRequestedDeviceOrDefault( MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices(), request.requested_video_device_id); @@ -77,5 +69,20 @@ void GrantMediaStreamRequest(content::WebContents* web_contents, ui.Pass()); } +void VerifyMediaAccessPermission(content::MediaStreamType type, + const Extension* extension) { + const PermissionsData* permissions_data = extension->permissions_data(); + if (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) { + // app_shell has no UI surface to show an error, and on an embedded device + // it's better to crash than to have a feature not work. + CHECK(permissions_data->HasAPIPermission(APIPermission::kAudioCapture)) + << "Audio capture request but no audioCapture permission in manifest."; + } else { + DCHECK(type == content::MEDIA_DEVICE_VIDEO_CAPTURE); + CHECK(permissions_data->HasAPIPermission(APIPermission::kVideoCapture)) + << "Video capture request but no videoCapture permission in manifest."; + } +} + } // namespace media_capture_util } // namespace extensions diff --git a/extensions/shell/browser/media_capture_util.h b/extensions/shell/browser/media_capture_util.h index f254071..b1b15ba 100644 --- a/extensions/shell/browser/media_capture_util.h +++ b/extensions/shell/browser/media_capture_util.h @@ -28,6 +28,10 @@ void GrantMediaStreamRequest(content::WebContents* web_contents, const content::MediaResponseCallback& callback, const Extension* extension); +// Verifies that the extension has permission for |type|. If not, crash. +void VerifyMediaAccessPermission(content::MediaStreamType type, + const Extension* extension); + } // namespace media_capture_util } // namespace extensions diff --git a/extensions/shell/browser/shell_app_delegate.cc b/extensions/shell/browser/shell_app_delegate.cc index 4380d6a..483da67 100644 --- a/extensions/shell/browser/shell_app_delegate.cc +++ b/extensions/shell/browser/shell_app_delegate.cc @@ -62,6 +62,15 @@ void ShellAppDelegate::RequestMediaAccessPermission( web_contents, request, callback, extension); } +bool ShellAppDelegate::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const Extension* extension) { + media_capture_util::VerifyMediaAccessPermission(type, extension); + return true; +} + int ShellAppDelegate::PreferredIconSize() { return extension_misc::EXTENSION_ICON_SMALL; } diff --git a/extensions/shell/browser/shell_app_delegate.h b/extensions/shell/browser/shell_app_delegate.h index 6e58e17..b842edb 100644 --- a/extensions/shell/browser/shell_app_delegate.h +++ b/extensions/shell/browser/shell_app_delegate.h @@ -40,6 +40,10 @@ class ShellAppDelegate : public AppDelegate { const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback, const Extension* extension) OVERRIDE; + virtual bool CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const Extension* extension) OVERRIDE; virtual int PreferredIconSize() OVERRIDE; virtual gfx::ImageSkia GetAppDefaultIcon() OVERRIDE; virtual void SetWebContentsBlocked(content::WebContents* web_contents, diff --git a/extensions/shell/browser/shell_extension_host_delegate.cc b/extensions/shell/browser/shell_extension_host_delegate.cc index 0053c64..a02d604 100644 --- a/extensions/shell/browser/shell_extension_host_delegate.cc +++ b/extensions/shell/browser/shell_extension_host_delegate.cc @@ -52,5 +52,13 @@ void ShellExtensionHostDelegate::ProcessMediaAccessRequest( web_contents, request, callback, extension); } -} // namespace extensions +bool ShellExtensionHostDelegate::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const Extension* extension) { + media_capture_util::VerifyMediaAccessPermission(type, extension); + return true; +} +} // namespace extensions diff --git a/extensions/shell/browser/shell_extension_host_delegate.h b/extensions/shell/browser/shell_extension_host_delegate.h index 759a465..d7265f3 100644 --- a/extensions/shell/browser/shell_extension_host_delegate.h +++ b/extensions/shell/browser/shell_extension_host_delegate.h @@ -33,6 +33,10 @@ class ShellExtensionHostDelegate : public ExtensionHostDelegate { const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback, const Extension* extension) OVERRIDE; + virtual bool CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const Extension* extension) OVERRIDE; private: DISALLOW_COPY_AND_ASSIGN(ShellExtensionHostDelegate); |