diff options
-rw-r--r-- | chrome/browser/geolocation/geolocation_permission_context.cc | 305 | ||||
-rw-r--r-- | chrome/browser/geolocation/geolocation_permission_context.h | 39 | ||||
-rw-r--r-- | chrome/browser/geolocation/geolocation_permission_context_unittest.cc | 127 | ||||
-rw-r--r-- | chrome/browser/profile.cc | 11 | ||||
-rw-r--r-- | chrome/browser/profile.h | 7 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 2 | ||||
-rw-r--r-- | chrome/test/testing_profile.h | 9 |
7 files changed, 371 insertions, 129 deletions
diff --git a/chrome/browser/geolocation/geolocation_permission_context.cc b/chrome/browser/geolocation/geolocation_permission_context.cc index ae8cc0d..a0e76f8 100644 --- a/chrome/browser/geolocation/geolocation_permission_context.cc +++ b/chrome/browser/geolocation/geolocation_permission_context.cc @@ -27,19 +27,73 @@ #include "grit/theme_resources.h" #include "net/base/net_util.h" +// This class controls the geolocation infobar queue per profile, and it's an +// internal class to GeolocationPermissionContext. +// An alternate approach would be to have this queue per tab, and use +// notifications to broadcast when permission is set / listen to notification to +// cancel pending requests. This may be specially useful if there are other +// things listening for such notifications. +// For the time being this class is self-contained and it doesn't seem pulling +// the notification infrastructure would simplify. +class GeolocationInfoBarQueueController { + public: + GeolocationInfoBarQueueController( + GeolocationPermissionContext* geolocation_permission_context, + Profile* profile); + ~GeolocationInfoBarQueueController(); + + // The InfoBar will be displayed immediately if the tab is not already + // displaying one, otherwise it'll be queued. + void CreateInfoBarRequest( + int render_process_id, int render_view_id, int bridge_id, + const GURL& requesting_frame, const GURL& emebedder); + + // Cancels a specific infobar request. + void CancelInfoBarRequest( + int render_process_id, int render_view_id, int bridge_id); + + // Called by the InfoBarDelegate to notify it's closed. It'll display a new + // InfoBar if there's any request pending for this tab. + void OnInfoBarClosed( + int render_process_id, int render_view_id, int bridge_id); + + // Called by the InfoBarDelegate to notify permission has been set. + // It'll notify and dismiss any other pending InfoBar request for the same + // |requesting_frame| and embedder. + void OnPermissionSet( + int render_process_id, int render_view_id, int bridge_id, + const GURL& requesting_frame, const GURL& embedder, bool allowed); + + private: + struct PendingInfoBarRequest; + typedef std::vector<PendingInfoBarRequest> PendingInfoBarRequests; + + // Shows the first pending infobar for this tab. + void ShowQueuedInfoBar(int render_process_id, int render_view_id); + + // Cancels an InfoBar request and returns the next iterator position. + std::vector<PendingInfoBarRequest>::iterator CancelInfoBarRequestInternal( + std::vector<PendingInfoBarRequest>::iterator i); + + GeolocationPermissionContext* const geolocation_permission_context_; + Profile* const profile_; + // Contains all pending infobar requests. + PendingInfoBarRequests pending_infobar_requests_; +}; + namespace { // This is the delegate used to display the confirmation info bar. class GeolocationConfirmInfoBarDelegate : public ConfirmInfoBarDelegate { public: GeolocationConfirmInfoBarDelegate( - TabContents* tab_contents, GeolocationPermissionContext* context, + TabContents* tab_contents, GeolocationInfoBarQueueController* controller, int render_process_id, int render_view_id, int bridge_id, const GURL& requesting_frame_url, const std::wstring& display_languages) : ConfirmInfoBarDelegate(tab_contents), tab_contents_(tab_contents), - context_(context), + controller_(controller), render_process_id_(render_process_id), render_view_id_(render_view_id), bridge_id_(bridge_id), @@ -49,13 +103,13 @@ class GeolocationConfirmInfoBarDelegate : public ConfirmInfoBarDelegate { // ConfirmInfoBarDelegate virtual void InfoBarClosed() { - context_->OnInfoBarClosed(tab_contents_, render_process_id_, - render_view_id_, bridge_id_); + controller_->OnInfoBarClosed(render_process_id_, render_view_id_, + bridge_id_); delete this; } virtual Type GetInfoBarType() { return INFO_TYPE; } - virtual bool Accept() { return SetPermission(true); } - virtual bool Cancel() { return SetPermission(false); } + virtual bool Accept() { return OnPermissionSet(true); } + virtual bool Cancel() { return OnPermissionSet(false); } virtual int GetButtons() const { return BUTTON_OK | BUTTON_CANCEL; } virtual std::wstring GetButtonLabel(InfoBarButton button) const { switch (button) { @@ -91,15 +145,15 @@ class GeolocationConfirmInfoBarDelegate : public ConfirmInfoBarDelegate { } private: - bool SetPermission(bool confirm) { - context_->SetPermission( + bool OnPermissionSet(bool confirm) { + controller_->OnPermissionSet( render_process_id_, render_view_id_, bridge_id_, requesting_frame_url_, - confirm); + tab_contents_->GetURL(), confirm); return true; } TabContents* tab_contents_; - scoped_refptr<GeolocationPermissionContext> context_; + GeolocationInfoBarQueueController* controller_; int render_process_id_; int render_view_id_; int bridge_id_; @@ -111,11 +165,12 @@ class GeolocationConfirmInfoBarDelegate : public ConfirmInfoBarDelegate { } // namespace -struct GeolocationPermissionContext::PendingInfoBarRequest { +struct GeolocationInfoBarQueueController::PendingInfoBarRequest { int render_process_id; int render_view_id; int bridge_id; GURL requesting_frame; + GURL embedder; // If non-NULL, it's the current geolocation infobar for this tab. InfoBarDelegate* infobar_delegate; @@ -124,6 +179,11 @@ struct GeolocationPermissionContext::PendingInfoBarRequest { render_view_id == p_render_view_id; } + bool IsForPair(const GURL& p_requesting_frame, const GURL& p_embedder) const { + return requesting_frame == p_requesting_frame && + embedder == p_embedder; + } + bool Equals(int p_render_process_id, int p_render_view_id, int p_bridge_id) const { @@ -132,9 +192,133 @@ struct GeolocationPermissionContext::PendingInfoBarRequest { } }; +GeolocationInfoBarQueueController::GeolocationInfoBarQueueController( + GeolocationPermissionContext* geolocation_permission_context, + Profile* profile) + : geolocation_permission_context_(geolocation_permission_context), + profile_(profile) { +} + +GeolocationInfoBarQueueController::~GeolocationInfoBarQueueController() { +} + +void GeolocationInfoBarQueueController::CreateInfoBarRequest( + int render_process_id, int render_view_id, int bridge_id, + const GURL& requesting_frame, const GURL& embedder) { + PendingInfoBarRequest pending_infobar_request; + pending_infobar_request.render_process_id = render_process_id; + pending_infobar_request.render_view_id = render_view_id; + pending_infobar_request.bridge_id = bridge_id; + pending_infobar_request.requesting_frame = requesting_frame; + pending_infobar_request.embedder = embedder; + pending_infobar_request.infobar_delegate = NULL; + pending_infobar_requests_.push_back(pending_infobar_request); + ShowQueuedInfoBar(render_process_id, render_view_id); +} + +void GeolocationInfoBarQueueController::CancelInfoBarRequest( + int render_process_id, int render_view_id, int bridge_id) { + for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); + i != pending_infobar_requests_.end(); ++i) { + if (i->Equals(render_process_id, render_view_id, bridge_id)) { + CancelInfoBarRequestInternal(i); + break; + } + } +} + +void GeolocationInfoBarQueueController::OnInfoBarClosed( + int render_process_id, int render_view_id, int bridge_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); + i != pending_infobar_requests_.end(); ++i) { + if (i->Equals(render_process_id, render_view_id, bridge_id)) { + pending_infobar_requests_.erase(i); + break; + } + } + ShowQueuedInfoBar(render_process_id, render_view_id); +} + +void GeolocationInfoBarQueueController::OnPermissionSet( + int render_process_id, int render_view_id, int bridge_id, + const GURL& requesting_frame, const GURL& embedder, bool allowed) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + // Persist the permission. + ContentSetting content_setting = + allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; + profile_->GetGeolocationContentSettingsMap()->SetContentSetting( + requesting_frame.GetOrigin(), embedder.GetOrigin(), content_setting); + + // Now notify all pending requests that the permission has been set. + for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); + i != pending_infobar_requests_.end();) { + if (i->IsForPair(requesting_frame, embedder)) { + // There was a pending request for the same [frame, embedder]. + if (i->Equals(render_process_id, render_view_id, bridge_id)) { + // The request that set permission will be removed by TabContents + // itself, that is, we should not try to cancel the infobar that has + // just notified us. + i->infobar_delegate = NULL; + } + // Cancel it first, and then notify the permission. + // Note: if the pending request had an infobar, TabContents will + // eventually close it and we will pump the queue via OnInfoBarClosed(). + PendingInfoBarRequest other_request = *i; + i = CancelInfoBarRequestInternal(i); + geolocation_permission_context_->NotifyPermissionSet( + other_request.render_process_id, other_request.render_view_id, + other_request.bridge_id, other_request.requesting_frame, allowed); + } else { + ++i; + } + } +} + +void GeolocationInfoBarQueueController::ShowQueuedInfoBar( + int render_process_id, int render_view_id) { + for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); + i != pending_infobar_requests_.end(); ++i) { + if (i->IsForTab(render_process_id, render_view_id)) { + // Check if already displayed. + if (i->infobar_delegate) + break; + TabContents* tab_contents = + tab_util::GetTabContentsByID(render_process_id, render_view_id); + i->infobar_delegate = + new GeolocationConfirmInfoBarDelegate( + tab_contents, this, + render_process_id, render_view_id, + i->bridge_id, i->requesting_frame, + profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); + tab_contents->AddInfoBar(i->infobar_delegate); + break; + } + } +} + +std::vector<GeolocationInfoBarQueueController::PendingInfoBarRequest>::iterator + GeolocationInfoBarQueueController::CancelInfoBarRequestInternal( + std::vector<PendingInfoBarRequest>::iterator i) { + TabContents* tab_contents = + tab_util::GetTabContentsByID(i->render_process_id, i->render_view_id); + if (tab_contents && i->infobar_delegate) { + // TabContents will destroy the InfoBar, which will remove from our vector + // asynchronously. + tab_contents->RemoveInfoBar(i->infobar_delegate); + return ++i; + } else { + // Remove it directly from the pending vector. + return pending_infobar_requests_.erase(i); + } +} + GeolocationPermissionContext::GeolocationPermissionContext( Profile* profile) - : profile_(profile) { + : profile_(profile), + ALLOW_THIS_IN_INITIALIZER_LIST( + geolocation_infobar_queue_controller_( + new GeolocationInfoBarQueueController(this, profile))) { } GeolocationPermissionContext::~GeolocationPermissionContext() { @@ -200,31 +384,17 @@ void GeolocationPermissionContext::RequestGeolocationPermission( } else if (content_setting == CONTENT_SETTING_ALLOW) { NotifyPermissionSet(render_process_id, render_view_id, bridge_id, requesting_frame, true); - } else { // setting == ask. Prompt the user. - RequestPermissionFromUI(tab_contents, render_process_id, render_view_id, - bridge_id, requesting_frame); + } else { // setting == ask. Prompt the user. + geolocation_infobar_queue_controller_->CreateInfoBarRequest( + render_process_id, render_view_id, bridge_id, requesting_frame, + embedder); } } void GeolocationPermissionContext::CancelGeolocationPermissionRequest( int render_process_id, int render_view_id, int bridge_id, const GURL& requesting_frame) { - CancelPendingInfoBar(render_process_id, render_view_id, bridge_id); -} - -void GeolocationPermissionContext::SetPermission( - int render_process_id, int render_view_id, int bridge_id, - const GURL& requesting_frame, bool allowed) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - TabContents* tab_contents = - tab_util::GetTabContentsByID(render_process_id, render_view_id); - GURL embedder = tab_contents->GetURL(); - ContentSetting content_setting = - allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; - profile_->GetGeolocationContentSettingsMap()->SetContentSetting( - requesting_frame.GetOrigin(), embedder.GetOrigin(), content_setting); - NotifyPermissionSet(render_process_id, render_view_id, bridge_id, - requesting_frame, allowed); + CancelPendingInfoBarRequest(render_process_id, render_view_id, bridge_id); } GeolocationArbitrator* GeolocationPermissionContext::StartUpdatingRequested( @@ -248,36 +418,7 @@ GeolocationArbitrator* GeolocationPermissionContext::StartUpdatingRequested( void GeolocationPermissionContext::StopUpdatingRequested( int render_process_id, int render_view_id, int bridge_id) { - CancelPendingInfoBar(render_process_id, render_view_id, bridge_id); -} - -void GeolocationPermissionContext::OnInfoBarClosed( - TabContents* tab_contents, int render_process_id, int render_view_id, - int bridge_id) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); - i != pending_infobar_requests_.end(); ++i) { - if (i->Equals(render_process_id, render_view_id, bridge_id)) { - pending_infobar_requests_.erase(i); - break; - } - } - // Now process the queued infobars, if any. - ShowQueuedInfoBar(tab_contents, render_process_id, render_view_id); -} - -void GeolocationPermissionContext::RequestPermissionFromUI( - TabContents* tab_contents, int render_process_id, int render_view_id, - int bridge_id, const GURL& requesting_frame) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - PendingInfoBarRequest pending_infobar_request; - pending_infobar_request.render_process_id = render_process_id; - pending_infobar_request.render_view_id = render_view_id; - pending_infobar_request.bridge_id = bridge_id; - pending_infobar_request.requesting_frame = requesting_frame; - pending_infobar_request.infobar_delegate = NULL; - pending_infobar_requests_.push_back(pending_infobar_request); - ShowQueuedInfoBar(tab_contents, render_process_id, render_view_id); + CancelPendingInfoBarRequest(render_process_id, render_view_id, bridge_id); } void GeolocationPermissionContext::NotifyPermissionSet( @@ -311,49 +452,17 @@ void GeolocationPermissionContext::NotifyArbitratorPermissionGranted( GeolocationArbitrator::GetInstance()->OnPermissionGranted(requesting_frame); } -void GeolocationPermissionContext::ShowQueuedInfoBar( - TabContents* tab_contents, int render_process_id, int render_view_id) { - for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); - i != pending_infobar_requests_.end(); ++i) { - if (i->IsForTab(render_process_id, render_view_id)) { - // Check if already displayed. - if (i->infobar_delegate) - break; - i->infobar_delegate = - new GeolocationConfirmInfoBarDelegate( - tab_contents, this, render_process_id, render_view_id, - i->bridge_id, i->requesting_frame, - profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); - tab_contents->AddInfoBar(i->infobar_delegate); - break; - } - } -} - -void GeolocationPermissionContext::CancelPendingInfoBar( +void GeolocationPermissionContext::CancelPendingInfoBarRequest( int render_process_id, int render_view_id, int bridge_id) { if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { ChromeThread::PostTask( ChromeThread::UI, FROM_HERE, NewRunnableMethod(this, - &GeolocationPermissionContext::CancelPendingInfoBar, + &GeolocationPermissionContext::CancelPendingInfoBarRequest, render_process_id, render_view_id, bridge_id)); - return; + return; } DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); - i != pending_infobar_requests_.end(); ++i) { - if (i->Equals(render_process_id, render_view_id, bridge_id)) { - TabContents* tab_contents = - tab_util::GetTabContentsByID(render_process_id, render_view_id); - if (tab_contents && i->infobar_delegate) { - // Removing an infobar will remove it from the pending vector. - tab_contents->RemoveInfoBar(i->infobar_delegate); - } else { - // Remove it directly from the pending vector. - pending_infobar_requests_.erase(i); - } - break; - } - } + geolocation_infobar_queue_controller_->CancelInfoBarRequest( + render_process_id, render_view_id, bridge_id); } diff --git a/chrome/browser/geolocation/geolocation_permission_context.h b/chrome/browser/geolocation/geolocation_permission_context.h index d8b5fa3..d3f3e37 100644 --- a/chrome/browser/geolocation/geolocation_permission_context.h +++ b/chrome/browser/geolocation/geolocation_permission_context.h @@ -9,8 +9,11 @@ #include "base/basictypes.h" #include "base/file_path.h" #include "base/ref_counted.h" +#include "base/scoped_ptr.h" class GeolocationDispatcherHost; +class GeolocationInfoBarQueueController; +class GeolocationPermissionContext; class GURL; class GeolocationArbitrator; class InfoBarDelegate; @@ -19,7 +22,7 @@ class RenderViewHost; class TabContents; // GeolocationPermissionContext manages Geolocation permissions flow, -// creating UI elements to ask the user for permission when necessary. +// and delegates UI handling via GeolocationInfoBarQueueController. // It always notifies the requesting render_view asynchronously via // ViewMsg_Geolocation_PermissionSet. class GeolocationPermissionContext @@ -38,9 +41,9 @@ class GeolocationPermissionContext int render_process_id, int render_view_id, int bridge_id, const GURL& requesting_frame); - // Called once the user sets the geolocation permission. - // It'll notify the render via ViewMsg_Geolocation_PermissionSet. - void SetPermission( + // Notifies whether or not the corresponding bridge is allowed to use + // geolocation via ViewMsg_Geolocation_PermissionSet. + void NotifyPermissionSet( int render_process_id, int render_view_id, int bridge_id, const GURL& requesting_frame, bool allowed); @@ -62,42 +65,22 @@ class GeolocationPermissionContext void StopUpdatingRequested( int render_process_id, int render_view_id, int bridge_id); - // Called by the InfoBarDelegate to notify it's closed. - void OnInfoBarClosed( - TabContents* tab_contents, int render_process_id, int render_view_id, - int bridge_id); - private: - struct PendingInfoBarRequest; friend class base::RefCountedThreadSafe<GeolocationPermissionContext>; virtual ~GeolocationPermissionContext(); - // Triggers (or queues) the associated UI element to request permission. - void RequestPermissionFromUI( - TabContents* tab_contents, int render_process_id, int render_view_id, - int bridge_id, const GURL& requesting_frame); - - // Notifies whether or not the corresponding render is allowed to use - // geolocation. - void NotifyPermissionSet( - int render_process_id, int render_view_id, int bridge_id, - const GURL& requesting_frame, bool allowed); - // Calls GeolocationArbitrator::OnPermissionGranted. void NotifyArbitratorPermissionGranted(const GURL& requesting_frame); - // Shows an infobar if there's any pending for this tab. - void ShowQueuedInfoBar(TabContents* tab_contents, int render_process_id, - int render_view_id); - - void CancelPendingInfoBar( + // Removes any pending InfoBar request. + void CancelPendingInfoBarRequest( int render_process_id, int render_view_id, int bridge_id); // This should only be accessed from the UI thread. Profile* const profile_; - typedef std::vector<PendingInfoBarRequest> PendingInfoBarRequests; - PendingInfoBarRequests pending_infobar_requests_; + scoped_ptr<GeolocationInfoBarQueueController> + geolocation_infobar_queue_controller_; DISALLOW_COPY_AND_ASSIGN(GeolocationPermissionContext); }; diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc index b17f337..e8d631d 100644 --- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc +++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc @@ -4,6 +4,7 @@ #include "chrome/browser/geolocation/geolocation_permission_context.h" +#include "base/scoped_vector.h" #include "chrome/browser/geolocation/location_arbitrator.h" #include "chrome/browser/geolocation/location_provider.h" #include "chrome/browser/geolocation/mock_location_provider.h" @@ -76,10 +77,16 @@ class GeolocationPermissionContextTests : public RenderViewHostTestHarness { int process_id() { return contents()->render_view_host()->process()->id(); } + int process_id_for_tab(int tab) { + return extra_tabs_[tab]->render_view_host()->process()->id(); + } int render_id() { return contents()->render_view_host()->routing_id(); } + int render_id_for_tab(int tab) { + return extra_tabs_[tab]->render_view_host()->routing_id(); + } int bridge_id() { // Bridge id is not relevant at this level. @@ -87,17 +94,38 @@ class GeolocationPermissionContextTests : public RenderViewHostTestHarness { } void CheckPermissionMessageSent(int bridge_id, bool allowed) { + CheckPermissionMessageSentInternal(process(), bridge_id, allowed); + } + void CheckPermissionMessageSentForTab(int tab, int bridge_id, bool allowed) { + CheckPermissionMessageSentInternal( + static_cast<MockRenderProcessHost*>( + extra_tabs_[tab]->render_view_host()->process()), + bridge_id, allowed); + } + + void CheckPermissionMessageSentInternal(MockRenderProcessHost* process, + int bridge_id, + bool allowed) { MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); MessageLoop::current()->Run(); const IPC::Message* message = - process()->sink().GetFirstMessageMatching( + process->sink().GetFirstMessageMatching( ViewMsg_Geolocation_PermissionSet::ID); ASSERT_TRUE(message); ViewMsg_Geolocation_PermissionSet::Param param; ViewMsg_Geolocation_PermissionSet::Read(message, ¶m); EXPECT_EQ(bridge_id, param.a); EXPECT_EQ(allowed, param.b); - process()->sink().ClearMessages(); + process->sink().ClearMessages(); + } + + void AddNewTab(const GURL& url) { + TestTabContentsWithPendingInfoBar* new_tab = + new TestTabContentsWithPendingInfoBar(profile(), NULL); + new_tab->controller().LoadURL(url, GURL(), PageTransition::TYPED); + static_cast<TestRenderViewHost*>(new_tab->render_manager()-> + current_host())->SendNavigate(extra_tabs_.size() + 1, url); + extra_tabs_.push_back(new_tab); } void CheckTabContentsState(const GURL& requesting_frame, @@ -120,6 +148,7 @@ class GeolocationPermissionContextTests : public RenderViewHostTestHarness { ChromeThread ui_thread_; TestTabContentsWithPendingInfoBar* tab_contents_with_pending_infobar_; scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_; + ScopedVector<TestTabContentsWithPendingInfoBar> extra_tabs_; }; TEST_F(GeolocationPermissionContextTests, SinglePermission) { @@ -154,6 +183,7 @@ TEST_F(GeolocationPermissionContextTests, QueuedPermission) { EXPECT_EQ(1, contents()->infobar_delegate_count()); ConfirmInfoBarDelegate* infobar_0 = contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); + ASSERT_TRUE(infobar_0); std::wstring text_0 = infobar_0->GetMessageText(); // Accept the first frame. @@ -170,6 +200,7 @@ TEST_F(GeolocationPermissionContextTests, QueuedPermission) { ConfirmInfoBarDelegate* infobar_1 = contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); + ASSERT_TRUE(infobar_1); std::wstring text_1 = infobar_1->GetMessageText(); EXPECT_NE(text_0, text_1); @@ -216,6 +247,7 @@ TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) { ConfirmInfoBarDelegate* infobar_0 = contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); + ASSERT_TRUE(infobar_0); std::wstring text_0 = infobar_0->GetMessageText(); // Simulate the frame going away, ensure the infobar for this frame @@ -229,6 +261,7 @@ TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) { ConfirmInfoBarDelegate* infobar_1 = contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); + ASSERT_TRUE(infobar_1); std::wstring text_1 = infobar_1->GetMessageText(); EXPECT_NE(text_0, text_1); @@ -261,6 +294,7 @@ TEST_F(GeolocationPermissionContextTests, StopUpdating) { EXPECT_EQ(1, contents()->infobar_delegate_count()); ConfirmInfoBarDelegate* infobar_0 = contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); + ASSERT_TRUE(infobar_0); geolocation_permission_context_->StopUpdatingRequested( process_id(), render_id(), bridge_id()); @@ -284,3 +318,92 @@ TEST_F(GeolocationPermissionContextTests, InvalidURL) { EXPECT_EQ(0, contents()->infobar_delegate_count()); CheckPermissionMessageSent(bridge_id(), false); } + +TEST_F(GeolocationPermissionContextTests, SameOriginMultipleTabs) { + GURL url_a("http://www.example.com/geolocation"); + GURL url_b("http://www.example-2.com/geolocation"); + NavigateAndCommit(url_a); + AddNewTab(url_b); + AddNewTab(url_a); + + EXPECT_EQ(0, contents()->infobar_delegate_count()); + geolocation_permission_context_->RequestGeolocationPermission( + process_id(), render_id(), bridge_id(), url_a); + EXPECT_EQ(1, contents()->infobar_delegate_count()); + + geolocation_permission_context_->RequestGeolocationPermission( + process_id_for_tab(0), render_id_for_tab(0), bridge_id(), url_b); + EXPECT_EQ(1, extra_tabs_[0]->infobar_delegate_count()); + + geolocation_permission_context_->RequestGeolocationPermission( + process_id_for_tab(1), render_id_for_tab(1), bridge_id(), url_a); + EXPECT_EQ(1, extra_tabs_[1]->infobar_delegate_count()); + + // Accept the first tab. + ConfirmInfoBarDelegate* infobar_0 = + contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); + ASSERT_TRUE(infobar_0); + infobar_0->Accept(); + CheckPermissionMessageSent(bridge_id(), true); + contents()->RemoveInfoBar(infobar_0); + EXPECT_EQ(infobar_0, + tab_contents_with_pending_infobar_->removed_infobar_delegate_); + infobar_0->InfoBarClosed(); + // Now the infobar for the tab with the same origin should have gone. + EXPECT_EQ(0, extra_tabs_[1]->infobar_delegate_count()); + CheckPermissionMessageSentForTab(1, bridge_id(), true); + + // But the other tab should still have the info bar... + EXPECT_EQ(1, extra_tabs_[0]->infobar_delegate_count()); + extra_tabs_.reset(); +} + +TEST_F(GeolocationPermissionContextTests, QueuedOriginMultipleTabs) { + GURL url_a("http://www.example.com/geolocation"); + GURL url_b("http://www.example-2.com/geolocation"); + NavigateAndCommit(url_a); + AddNewTab(url_a); + + EXPECT_EQ(0, contents()->infobar_delegate_count()); + geolocation_permission_context_->RequestGeolocationPermission( + process_id(), render_id(), bridge_id(), url_a); + EXPECT_EQ(1, contents()->infobar_delegate_count()); + + geolocation_permission_context_->RequestGeolocationPermission( + process_id_for_tab(0), render_id_for_tab(0), bridge_id(), url_a); + EXPECT_EQ(1, extra_tabs_[0]->infobar_delegate_count()); + + geolocation_permission_context_->RequestGeolocationPermission( + process_id_for_tab(0), render_id_for_tab(0), bridge_id() + 1, url_b); + EXPECT_EQ(1, extra_tabs_[0]->infobar_delegate_count()); + + // Accept the second tab. + ConfirmInfoBarDelegate* infobar_0 = + extra_tabs_[0]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); + ASSERT_TRUE(infobar_0); + infobar_0->Accept(); + CheckPermissionMessageSentForTab(0, bridge_id(), true); + extra_tabs_[0]->RemoveInfoBar(infobar_0); + EXPECT_EQ(infobar_0, + extra_tabs_[0]->removed_infobar_delegate_); + infobar_0->InfoBarClosed(); + // Now the infobar for the tab with the same origin should have gone. + EXPECT_EQ(0, contents()->infobar_delegate_count()); + CheckPermissionMessageSent(bridge_id(), true); + + // And we should have the queued infobar displayed now. + EXPECT_EQ(1, extra_tabs_[0]->infobar_delegate_count()); + + // Accept the second infobar. + ConfirmInfoBarDelegate* infobar_1 = + extra_tabs_[0]->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); + ASSERT_TRUE(infobar_1); + infobar_1->Accept(); + CheckPermissionMessageSentForTab(0, bridge_id() + 1, true); + extra_tabs_[0]->RemoveInfoBar(infobar_1); + EXPECT_EQ(infobar_1, + extra_tabs_[0]->removed_infobar_delegate_); + infobar_1->InfoBarClosed(); + + extra_tabs_.reset(); +} diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index a5ade1e..be95189 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -33,6 +33,7 @@ #include "chrome/browser/favicon_service.h" #include "chrome/browser/find_bar_state.h" #include "chrome/browser/geolocation/geolocation_content_settings_map.h" +#include "chrome/browser/geolocation/geolocation_permission_context.h" #include "chrome/browser/spellcheck_host.h" #include "chrome/browser/transport_security_persister.h" #include "chrome/browser/history/history.h" @@ -454,6 +455,10 @@ class OffTheRecordProfileImpl : public Profile, return profile_->GetGeolocationContentSettingsMap(); } + virtual GeolocationPermissionContext* GetGeolocationPermissionContext() { + return profile_->GetGeolocationPermissionContext(); + } + virtual Blacklist* GetPrivacyBlacklist() { return profile_->GetPrivacyBlacklist(); } @@ -1116,6 +1121,12 @@ GeolocationContentSettingsMap* ProfileImpl::GetGeolocationContentSettingsMap() { return geolocation_content_settings_map_.get(); } +GeolocationPermissionContext* ProfileImpl::GetGeolocationPermissionContext() { + if (!geolocation_permission_context_.get()) + geolocation_permission_context_ = new GeolocationPermissionContext(this); + return geolocation_permission_context_.get(); +} + Blacklist* ProfileImpl::GetPrivacyBlacklist() { if (!CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnablePrivacyBlacklists)) diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 751d2e2..b7d5c24 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -45,6 +45,7 @@ class ExtensionsService; class FaviconService; class FindBarState; class GeolocationContentSettingsMap; +class GeolocationPermissionContext; class HistoryService; class HostContentSettingsMap; class HostZoomMap; @@ -315,6 +316,9 @@ class Profile { // Returns the geolocation settings map for this profile. virtual GeolocationContentSettingsMap* GetGeolocationContentSettingsMap() = 0; + // Returns the geolocation permission context for this profile. + virtual GeolocationPermissionContext* GetGeolocationPermissionContext() = 0; + // Returns the Privacy Blacklist for this profile. virtual Blacklist* GetPrivacyBlacklist() = 0; @@ -498,6 +502,7 @@ class ProfileImpl : public Profile, virtual HostContentSettingsMap* GetHostContentSettingsMap(); virtual HostZoomMap* GetHostZoomMap(); virtual GeolocationContentSettingsMap* GetGeolocationContentSettingsMap(); + virtual GeolocationPermissionContext* GetGeolocationPermissionContext(); virtual Blacklist* GetPrivacyBlacklist(); virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher(); virtual FindBarState* GetFindBarState(); @@ -591,6 +596,8 @@ class ProfileImpl : public Profile, scoped_refptr<HostZoomMap> host_zoom_map_; scoped_refptr<GeolocationContentSettingsMap> geolocation_content_settings_map_; + scoped_refptr<GeolocationPermissionContext> + geolocation_permission_context_; scoped_refptr<Blacklist> privacy_blacklist_; scoped_refptr<UserStyleSheetWatcher> user_style_sheet_watcher_; scoped_ptr<FindBarState> find_bar_state_; diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 9fa1197..bf79fa5 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -318,7 +318,7 @@ ResourceMessageFilter::ResourceMessageFilter( render_widget_helper, &RenderWidgetHelper::GetNextRoutingID)), ALLOW_THIS_IN_INITIALIZER_LIST(geolocation_dispatcher_host_( new GeolocationDispatcherHost( - this->id(), new GeolocationPermissionContext(profile)))) { + this->id(), profile->GetGeolocationPermissionContext()))) { DCHECK(request_context_); DCHECK(media_request_context_); DCHECK(audio_renderer_host_.get()); diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index 1edf867..7ceaec6 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -15,6 +15,7 @@ #include "chrome/browser/favicon_service.h" #include "chrome/browser/find_bar_state.h" #include "chrome/browser/geolocation/geolocation_content_settings_map.h" +#include "chrome/browser/geolocation/geolocation_permission_context.h" #include "chrome/browser/host_content_settings_map.h" #include "chrome/browser/history/history.h" #include "chrome/browser/in_process_webkit/webkit_context.h" @@ -205,6 +206,13 @@ class TestingProfile : public Profile { } return geolocation_content_settings_map_.get(); } + virtual GeolocationPermissionContext* GetGeolocationPermissionContext() { + if (!geolocation_permission_context_.get()) { + geolocation_permission_context_ = + new GeolocationPermissionContext(this); + } + return geolocation_permission_context_.get(); + } virtual HostZoomMap* GetHostZoomMap() { return NULL; } void set_session_service(SessionService* session_service); virtual SessionService* GetSessionService() { return session_service_.get(); } @@ -334,6 +342,7 @@ class TestingProfile : public Profile { scoped_refptr<HostContentSettingsMap> host_content_settings_map_; scoped_refptr<GeolocationContentSettingsMap> geolocation_content_settings_map_; + scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_; // Find bar state. Created lazily by GetFindBarState(). scoped_ptr<FindBarState> find_bar_state_; |