summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-02-12 16:33:50 +0000
committerSteve Block <steveblock@google.com>2010-02-23 17:58:43 +0000
commit3429efc308249172d26d6c9edb5e2d36c1c5855a (patch)
tree7b3a14865f7fa66557037fbae0de02313282d374
parent0619f0601ffda6f9b1e7ef9870de4a6d14defbd1 (diff)
downloadexternal_webkit-3429efc308249172d26d6c9edb5e2d36c1c5855a.zip
external_webkit-3429efc308249172d26d6c9edb5e2d36c1c5855a.tar.gz
external_webkit-3429efc308249172d26d6c9edb5e2d36c1c5855a.tar.bz2
Fixes a bug with showing the Geolocation permissions prompt
Currently, if an iframe causes the Geolocation permissions prompt to be shown, but the frame is navigated away before the user responds to the permissions prompt, the prompt is not removed from the screen. This change fixes that bug. It uses the new ChromeClient::cancelGeolocationPermissionRequestForFrame() method, which was cherry-picked from WebKit in https://android-git.corp.google.com/g/#change,41747 The logic is complicated by the fact that multiple iframes may have requested Geolocation permissions for the same origin. In this case, we should not hide the prompt until the last such frame is navigated away. Bug: 2463551 Change-Id: I1e4de05586150c7a94bc8343f6e56e4a4870cd3b
-rw-r--r--WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp6
-rw-r--r--WebKit/android/WebCoreSupport/ChromeClientAndroid.h2
-rwxr-xr-xWebKit/android/WebCoreSupport/GeolocationPermissions.cpp108
-rw-r--r--[-rwxr-xr-x]WebKit/android/WebCoreSupport/GeolocationPermissions.h11
4 files changed, 93 insertions, 34 deletions
diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
index 9102395..e9e77e9 100644
--- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
@@ -479,6 +479,12 @@ void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame* frame, Geo
m_geolocationPermissions->queryPermissionState(frame);
}
+void ChromeClientAndroid::cancelGeolocationPermissionRequestForFrame(Frame* frame)
+{
+ if (m_geolocationPermissions)
+ m_geolocationPermissions->cancelPermissionStateQuery(frame);
+}
+
void ChromeClientAndroid::provideGeolocationPermissions(const String &origin, bool allow, bool remember)
{
ASSERT(m_geolocationPermissions);
diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
index 15473ca..2c061b2 100644
--- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
+++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
@@ -143,7 +143,7 @@ namespace android {
// Methods used to request and provide Geolocation permissions.
virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*);
- virtual void cancelGeolocationPermissionRequestForFrame(Frame*) { }
+ virtual void cancelGeolocationPermissionRequestForFrame(Frame*);
// Android-specific
void provideGeolocationPermissions(const String &origin, bool allow, bool remember);
void storeGeolocationPermissions();
diff --git a/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp b/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp
index aeee017..b630f66 100755
--- a/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp
+++ b/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp
@@ -100,21 +100,56 @@ void GeolocationPermissions::queryPermissionState(Frame* frame)
}
// If there's no pending request, prompt the user.
- if (m_originInProgress.isEmpty()) {
- m_originInProgress = originString;
-
+ if (nextOriginInQueue().isEmpty()) {
// Although multiple tabs may request permissions for the same origin
// simultaneously, the routing in WebViewCore/CallbackProxy ensures that
// the result of the request will make it back to this object, so
// there's no need for a globally unique ID for the request.
- m_webViewCore->geolocationPermissionsShowPrompt(m_originInProgress);
- return;
+ m_webViewCore->geolocationPermissionsShowPrompt(originString);
}
- // If the request in progress is not for this origin, queue this request.
- if ((m_originInProgress != originString)
- && (m_queuedOrigins.find(originString) == WTF::notFound))
+ // Add this request to the queue so we can track which frames requested it.
+ if (m_queuedOrigins.find(originString) == WTF::notFound) {
m_queuedOrigins.append(originString);
+ FrameSet frameSet;
+ frameSet.add(frame);
+ m_queuedOriginsToFramesMap.add(originString, frameSet);
+ } else {
+ ASSERT(m_queuedOriginsToFramesMap.contains(originString));
+ m_queuedOriginsToFramesMap.find(originString)->second.add(frame);
+ }
+}
+
+void GeolocationPermissions::cancelPermissionStateQuery(WebCore::Frame* frame)
+{
+ // We cancel any queued request for the given frame. There can be at most
+ // one of these, since each frame maps to a single origin. We only cancel
+ // the request if this frame is the only one reqesting permission for this
+ // origin.
+ //
+ // We can use the origin string to avoid searching the map.
+ String originString = frame->document()->securityOrigin()->toString();
+ size_t index = m_queuedOrigins.find(originString);
+ if (index == WTF::notFound)
+ return;
+
+ ASSERT(m_queuedOriginsToFramesMap.contains(originString));
+ OriginToFramesMap::iterator iter = m_queuedOriginsToFramesMap.find(originString);
+ ASSERT(iter->second.contains(frame));
+ iter->second.remove(frame);
+ if (!iter->second.isEmpty())
+ return;
+
+ m_queuedOrigins.remove(index);
+ m_queuedOriginsToFramesMap.remove(iter);
+
+ // If this is the origin currently being shown, cancel the prompt
+ // and show the next in the queue, if present.
+ if (index == 0) {
+ m_webViewCore->geolocationPermissionsHidePrompt();
+ if (!nextOriginInQueue().isEmpty())
+ m_webViewCore->geolocationPermissionsShowPrompt(nextOriginInQueue());
+ }
}
void GeolocationPermissions::makeAsynchronousCallbackToGeolocation(String origin, bool allow)
@@ -133,38 +168,38 @@ void GeolocationPermissions::providePermissionState(String origin, bool allow, b
// while a permission result is in the process of being marshalled back to
// the WebCore thread from the browser. In this case, we simply ignore the
// call.
- if (origin != m_originInProgress)
+ if (origin != nextOriginInQueue())
return;
- maybeCallbackFrames(m_originInProgress, allow);
+ maybeCallbackFrames(origin, allow);
recordPermissionState(origin, allow, remember);
// If the permissions are set to be remembered, cancel any queued requests
// for this domain in other tabs.
if (remember)
- cancelPendingRequestsInOtherTabs(m_originInProgress);
+ cancelPendingRequestsInOtherTabs(origin);
- // Clear the origin in progress to signal that this request is done.
- m_originInProgress = "";
+ // Clear the origin from the queue.
+ ASSERT(!m_queuedOrigins.isEmpty());
+ m_queuedOrigins.remove(0);
+ ASSERT(m_queuedOriginsToFramesMap.contains(origin));
+ m_queuedOriginsToFramesMap.remove(origin);
// If there are other requests queued, start the next one.
- if (!m_queuedOrigins.isEmpty()) {
- m_originInProgress = m_queuedOrigins.first();
- m_queuedOrigins.remove(0);
- m_webViewCore->geolocationPermissionsShowPrompt(m_originInProgress);
- }
+ if (!nextOriginInQueue().isEmpty())
+ m_webViewCore->geolocationPermissionsShowPrompt(nextOriginInQueue());
}
void GeolocationPermissions::recordPermissionState(String origin, bool allow, bool remember)
{
if (remember) {
- s_permanentPermissions.set(m_originInProgress, allow);
+ s_permanentPermissions.set(origin, allow);
s_permanentPermissionsModified = true;
} else {
// It's possible that another tab recorded a permanent permission for
// this origin while our request was in progress, but we record it
// anyway.
- m_temporaryPermissions.set(m_originInProgress, allow);
+ m_temporaryPermissions.set(origin, allow);
}
}
@@ -179,19 +214,22 @@ void GeolocationPermissions::cancelPendingRequestsInOtherTabs(String origin)
void GeolocationPermissions::cancelPendingRequests(String origin)
{
size_t index = m_queuedOrigins.find(origin);
- if (index != WTF::notFound) {
- // Get the permission from the permanent list.
- PermissionsMap::const_iterator iter = s_permanentPermissions.find(origin);
-#ifndef NDEBUG
- PermissionsMap::const_iterator end = s_permanentPermissions.end();
- ASSERT(iter != end);
-#endif
- bool allow = iter->second;
- maybeCallbackFrames(origin, allow);
+ // Don't cancel the request if it's currently being shown, in which case
+ // it's at index 0.
+ if (index == WTF::notFound || !index)
+ return;
- m_queuedOrigins.remove(index);
- }
+ // Get the permission from the permanent list.
+ ASSERT(s_permanentPermissions.contains(origin));
+ PermissionsMap::const_iterator iter = s_permanentPermissions.find(origin);
+ bool allow = iter->second;
+
+ maybeCallbackFrames(origin, allow);
+
+ m_queuedOrigins.remove(index);
+ ASSERT(m_queuedOriginsToFramesMap.contains(origin));
+ m_queuedOriginsToFramesMap.remove(origin);
}
void GeolocationPermissions::timerFired(Timer<GeolocationPermissions>* timer)
@@ -203,8 +241,8 @@ void GeolocationPermissions::timerFired(Timer<GeolocationPermissions>* timer)
void GeolocationPermissions::resetTemporaryPermissionStates()
{
ASSERT(s_permanentPermissionsLoaded);
- m_originInProgress = "";
m_queuedOrigins.clear();
+ m_queuedOriginsToFramesMap.clear();
m_temporaryPermissions.clear();
// If any permission results are being marshalled back to this thread, this
// will render them inefective.
@@ -213,6 +251,12 @@ void GeolocationPermissions::resetTemporaryPermissionStates()
m_webViewCore->geolocationPermissionsHidePrompt();
}
+const WebCore::String& GeolocationPermissions::nextOriginInQueue()
+{
+ static const String emptyString = "";
+ return m_queuedOrigins.isEmpty() ? emptyString : m_queuedOrigins[0];
+}
+
void GeolocationPermissions::maybeCallbackFrames(String origin, bool allow)
{
// We can't track which frame issued the request, as frames can be deleted
diff --git a/WebKit/android/WebCoreSupport/GeolocationPermissions.h b/WebKit/android/WebCoreSupport/GeolocationPermissions.h
index 33434b9..e59c11b 100755..100644
--- a/WebKit/android/WebCoreSupport/GeolocationPermissions.h
+++ b/WebKit/android/WebCoreSupport/GeolocationPermissions.h
@@ -74,6 +74,7 @@ namespace android {
// the Geolocation objects in all frames in this WebView that are from
// the same origin as the requesting frame.
void queryPermissionState(WebCore::Frame* frame);
+ void cancelPermissionStateQuery(WebCore::Frame*);
// Provides this object with a permission state set by the user. The
// permission is specified by 'allow' and applied to 'origin'. If
@@ -135,11 +136,19 @@ namespace android {
static void maybeLoadPermanentPermissions();
+ const WebCore::String& nextOriginInQueue();
+
WebViewCore* m_webViewCore;
WebCore::Frame* m_mainFrame;
- WebCore::String m_originInProgress;
+ // A vector of the origins queued to make a permission request.
+ // The first in the vector is the origin currently making the request.
typedef Vector<WebCore::String> OriginVector;
OriginVector m_queuedOrigins;
+ // A map from a queued origin to the set of frames that have requested
+ // permission for that origin.
+ typedef HashSet<WebCore::Frame*> FrameSet;
+ typedef HashMap<WebCore::String, FrameSet> OriginToFramesMap;
+ OriginToFramesMap m_queuedOriginsToFramesMap;
typedef WTF::HashMap<WebCore::String, bool> PermissionsMap;
PermissionsMap m_temporaryPermissions;