summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context.cc305
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context.h39
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context_unittest.cc127
-rw-r--r--chrome/browser/profile.cc11
-rw-r--r--chrome/browser/profile.h7
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc2
-rw-r--r--chrome/test/testing_profile.h9
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, &param);
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_;