diff options
author | Steve Block <steveblock@google.com> | 2009-07-27 17:37:18 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2009-07-29 12:26:44 +0100 |
commit | fe55045391147883a38ed161b0c80f4e356bd9e0 (patch) | |
tree | 9d264668e28f0442b3b63a1049056cfbea985e8f | |
parent | cd942b3786cfce15a858784fb072c40e713c54cb (diff) | |
download | external_webkit-fe55045391147883a38ed161b0c80f4e356bd9e0.zip external_webkit-fe55045391147883a38ed161b0c80f4e356bd9e0.tar.gz external_webkit-fe55045391147883a38ed161b0c80f4e356bd9e0.tar.bz2 |
Adds a GeolocationPermissions class.
-rw-r--r-- | WebKit/Android.mk | 1 | ||||
-rw-r--r-- | WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp | 24 | ||||
-rw-r--r-- | WebKit/android/WebCoreSupport/ChromeClientAndroid.h | 15 | ||||
-rwxr-xr-x | WebKit/android/WebCoreSupport/GeolocationPermissions.cpp | 243 | ||||
-rwxr-xr-x | WebKit/android/WebCoreSupport/GeolocationPermissions.h | 135 | ||||
-rw-r--r-- | WebKit/android/jni/WebCoreFrameBridge.cpp | 11 | ||||
-rw-r--r-- | WebKit/android/jni/WebViewCore.cpp | 9 | ||||
-rw-r--r-- | WebKit/android/jni/WebViewCore.h | 12 |
8 files changed, 447 insertions, 3 deletions
diff --git a/WebKit/Android.mk b/WebKit/Android.mk index 5e79d5a..e4b739a 100644 --- a/WebKit/Android.mk +++ b/WebKit/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES := \ android/WebCoreSupport/EditorClientAndroid.cpp \ android/WebCoreSupport/FrameLoaderClientAndroid.cpp \ android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp \ + android/WebCoreSupport/GeolocationPermissions.cpp \ \ android/RenderSkinAndroid.cpp \ android/RenderSkinButton.cpp \ diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index a0f3f8d..ac70939 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp @@ -37,6 +37,7 @@ #include "Frame.h" #include "FrameLoader.h" #include "FrameView.h" +#include "Geolocation.h" #include "Page.h" #include "Screen.h" #include "ScriptController.h" @@ -326,7 +327,28 @@ void ChromeClientAndroid::reachedMaxAppCacheSize(int64_t spaceNeeded) } #endif -void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame*, Geolocation*) { notImplemented(); } +void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) +{ + ASSERT(geolocation); + if (!m_geolocationPermissions) { + m_geolocationPermissions = new GeolocationPermissions(android::WebViewCore::getWebViewCore(frame->view()), + m_webFrame->page()->mainFrame()); + } + m_geolocationPermissions->queryPermissionState(frame); +} + +void ChromeClientAndroid::provideGeolocationPermissions(const String &origin, bool allow, bool remember) +{ + ASSERT(m_geolocationPermissions); + m_geolocationPermissions->providePermissionState(origin, allow, remember); +} + +void ChromeClientAndroid::onMainFrameLoadStarted() +{ + if (m_geolocationPermissions.get()) + m_geolocationPermissions->resetTemporaryPermissionStates(); +} + void ChromeClientAndroid::runOpenPanel(Frame*, PassRefPtr<FileChooser>) { notImplemented(); } bool ChromeClientAndroid::setCursor(PlatformCursorHandle) { diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h index 93426b8..ded1ea9 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h @@ -28,7 +28,13 @@ #include "ChromeClient.h" +#include "GeolocationPermissions.h" #include "Threading.h" +#include "Timer.h" + +namespace WebCore { + class Geolocation; +} using namespace WebCore; @@ -37,7 +43,7 @@ namespace android { class ChromeClientAndroid : public ChromeClient { public: - ChromeClientAndroid() : m_webFrame(NULL) {} + ChromeClientAndroid() : m_webFrame(0), m_geolocationPermissions(0) { } virtual void chromeDestroyed(); virtual void setWindowRect(const FloatRect&); @@ -114,7 +120,12 @@ namespace android { #if ENABLE(OFFLINE_WEB_APPLICATIONS) virtual void reachedMaxAppCacheSize(int64_t spaceNeeded); #endif + // Methods used to request and provide Geolocation permissions. virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*); + // Android-specific + void provideGeolocationPermissions(const String &origin, bool allow, bool remember); + void onMainFrameLoadStarted(); + virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>); virtual bool setCursor(PlatformCursorHandle); @@ -132,6 +143,8 @@ namespace android { WTF::ThreadCondition m_quotaThreadCondition; WTF::Mutex m_quotaThreadLock; long m_newQuota; + // The Geolocation permissions manager. + RefPtr<GeolocationPermissions> m_geolocationPermissions; }; } diff --git a/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp b/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp new file mode 100755 index 0000000..7c0424b --- /dev/null +++ b/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp @@ -0,0 +1,243 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GeolocationPermissions.h" + +#include "Frame.h" +#include "Geolocation.h" +#include "Navigator.h" +#include "WebViewCore.h" + +using WebCore::Frame; +using WebCore::String; +using WebCore::Timer; + +namespace android { + +// TODO(steveblock): Write the permanent permissions to stable storage when +// the browser closes and read them on startup. +GeolocationPermissions::PermissionsMap GeolocationPermissions::s_permanentPermissions; +GeolocationPermissions::GeolocationPermissionsVector GeolocationPermissions::s_instances; + +GeolocationPermissions::GeolocationPermissions(WebViewCore* webViewCore, Frame* mainFrame) + : m_webViewCore(webViewCore) + , m_mainFrame(mainFrame) + , m_timer(this, &GeolocationPermissions::timerFired) + +{ + s_instances.append(this); + ASSERT(m_webViewCore); +} + +GeolocationPermissions::~GeolocationPermissions() +{ + size_t index = s_instances.find(this); + s_instances.remove(index); +} + +void GeolocationPermissions::queryPermissionState(Frame* frame) +{ + // We use SecurityOrigin::toString to key the map. Note that testing + // the SecurityOrigin pointer for equality is insufficient. + String originString = frame->document()->securityOrigin()->toString(); + + // See if we have a record for this origin in the temporary permissions for + // this tab. These take precedence over permanent permissions. + PermissionsMap::const_iterator iter = m_temporaryPermissions.find(originString); + PermissionsMap::const_iterator end = m_temporaryPermissions.end(); + if (iter != end) { + bool allow = iter->second; + makeAsynchronousCallbackToGeolocation(originString, allow); + return; + } + + // Check the permanent permisions. + iter = s_permanentPermissions.find(originString); + end = s_permanentPermissions.end(); + if (iter != end) { + bool allow = iter->second; + makeAsynchronousCallbackToGeolocation(originString, allow); + return; + } + + // If there's no pending request, prompt the user. + if (m_originInProgress.isEmpty()) { + m_originInProgress = originString; + + // 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; + } + + // If the request in progress is not for this origin, queue this request. + if ((m_originInProgress != originString) + && (m_queuedOrigins.find(originString) != WTF::notFound)) + m_queuedOrigins.append(originString); +} + +void GeolocationPermissions::makeAsynchronousCallbackToGeolocation(String origin, bool allow) +{ + m_callbackData.origin = origin; + m_callbackData.allow = allow; + m_timer.startOneShot(0); +} + +void GeolocationPermissions::providePermissionState(String origin, bool allow, bool remember) +{ + // It's possible that this method is called with an origin that doesn't + // match m_originInProgress. This can occur if this object is reset + // 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) + return; + + maybeCallbackFrames(m_originInProgress, 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); + + // 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); + } + + m_originInProgress = ""; +} + +void GeolocationPermissions::recordPermissionState(String origin, bool allow, bool remember) +{ + if (remember) { + s_permanentPermissions.set(m_originInProgress, allow); + // If we already have a temporary permission for this origin, remove it, + // so that later clearing the permanent permission works as expected. + m_temporaryPermissions.remove(origin); + } 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); + } +} + +void GeolocationPermissions::cancelPendingRequestsInOtherTabs(String origin) +{ + for (GeolocationPermissionsVector::const_iterator iter = s_instances.begin(); + iter != s_instances.end(); + ++iter) + (*iter)->cancelPendingRequests(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); + ASSERT(iter != (PermissionsMap::const_iterator end = s_permanentPermissions.end())); + bool allow = iter->second; + + maybeCallbackFrames(origin, allow); + + m_queuedOrigins.remove(index); + } +} + +void GeolocationPermissions::timerFired(Timer<GeolocationPermissions>* timer) +{ + ASSERT(timer == m_timer); + maybeCallbackFrames(m_callbackData.origin, m_callbackData.allow); +} + +void GeolocationPermissions::resetTemporaryPermissionStates() +{ + m_originInProgress = ""; + m_queuedOrigins.clear(); + m_temporaryPermissions.clear(); + // If any permission results are being marshalled back to this thread, this + // will render them inefective. + m_timer.stop(); + + m_webViewCore->geolocationPermissionsHidePrompt(); +} + +void GeolocationPermissions::maybeCallbackFrames(String origin, bool allow) +{ + // We can't track which frame issued the request, as frames can be deleted + // or have their contents replaced. Even uniqueChildName is not unique when + // frames are dynamically deleted and created. Instead, we simply call back + // to the Geolocation object in all frames from the correct origin. + for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { + if (origin == frame->document()->securityOrigin()->toString()) { + // If the page has changed, it may no longer have a Geolocation + // object. + Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); + if (geolocation) + geolocation->setIsAllowed(allow); + } + } +} + +GeolocationPermissions::OriginSet GeolocationPermissions::getOrigins() +{ + OriginSet origins; + PermissionsMap::const_iterator end = s_permanentPermissions.end(); + for (PermissionsMap::const_iterator iter = s_permanentPermissions.begin(); iter != end; ++iter) + origins.add(iter->first); + return origins; +} + +bool GeolocationPermissions::getAllowed(String origin) +{ + bool allowed = false; + PermissionsMap::const_iterator iter = s_permanentPermissions.find(origin); + PermissionsMap::const_iterator end = s_permanentPermissions.end(); + if (iter != end) + allowed = iter->second; + return allowed; +} + +void GeolocationPermissions::clear(String origin) +{ + PermissionsMap::iterator iter = s_permanentPermissions.find(origin); + if (iter != s_permanentPermissions.end()) + s_permanentPermissions.remove(iter); +} + +void GeolocationPermissions::clearAll() +{ + s_permanentPermissions.clear(); +} + +} // namespace android diff --git a/WebKit/android/WebCoreSupport/GeolocationPermissions.h b/WebKit/android/WebCoreSupport/GeolocationPermissions.h new file mode 100755 index 0000000..1dbc3da --- /dev/null +++ b/WebKit/android/WebCoreSupport/GeolocationPermissions.h @@ -0,0 +1,135 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GeolocationPermissions_h +#define GeolocationPermissions_h + +#include "PlatformString.h" +// We must include this before before HashMap.h, as it provides specalizations +// for String hash types instantiated there. +#include "StringHash.h" +#include "HashMap.h" +#include "HashSet.h" +#include "Timer.h" +#include "Vector.h" +#include "wtf/RefCounted.h" + +namespace WebCore { + class Frame; + class Geolocation; +} + +namespace android { + + class WebViewCore; + + // The GeolocationPermissions class manages permissions for the browser. + // Each instance handles permissions for a given main frame. The class + // enforces the following policy. + // - Non-remembered permissions last for the dureation of the main frame. + // - Remembered permissions last indefinitely. + // - All permissions are shared between child frames of a main frame. + // - Only remembered permissions are shared between main frames. + // - Remembered permissions are made available for use in the browser + // settings menu. + class GeolocationPermissions : public RefCounted<GeolocationPermissions> { + public: + // Creates the GeolocationPermissions object to manage permissions for + // the specified main frame (i.e. tab). The WebViewCore is used to + // communicate with the browser to display UI. + GeolocationPermissions(WebViewCore* webViewCore, WebCore::Frame* mainFrame); + virtual ~GeolocationPermissions(); + + // Queries the permission state for the specified frame. If the + // permission state has not yet been set, prompts the user. Once the + // permission state has been determined, asynchronously calls back to + // the Geolocation objects in all frames in this WebView that are from + // the same origin as the requesting frame. + void queryPermissionState(WebCore::Frame* frame); + + // Provides this object the given permission state from the user. The + // new permission state is recorded and will trigger callbacks to + // geolocation objects as described above. If any other permission + // requests are queued, the next is started. + void providePermissionState(WebCore::String origin, bool allow, bool remember); + + // Clears the temporary permission state and any pending requests. Used + // when the main frame is refreshed or navigated to a new URL. + void resetTemporaryPermissionStates(); + + // Static methods for use from Java. These are used to interact with the + // browser settings menu. + typedef HashSet<WebCore::String> OriginSet; + static OriginSet getOrigins(); + static bool getAllowed(WebCore::String origin); + static void clear(WebCore::String origin); + static void clearAll(); + + private: + // Records the permission state for the specified origin. + void recordPermissionState(WebCore::String origin, bool allow, bool remember); + + // Used to make an asynchronous callback to the Geolocation objects. + void makeAsynchronousCallbackToGeolocation(WebCore::String origin, bool allow); + void timerFired(WebCore::Timer<GeolocationPermissions>* timer); + + // Calls back to the Geolocation objects in all frames from the + // specified origin. There may be no such objects, as the frames using + // Geolocation from the specified origin may no longer use Geolocation, + // or may have been navigated to a different origin.. + void maybeCallbackFrames(WebCore::String origin, bool allow); + + // Cancels pending permission requests for the specified origin in + // other main frames (ie browser tabs). This is used when the user + // specifies permission to be remembered. + static void cancelPendingRequestsInOtherTabs(WebCore::String origin); + void cancelPendingRequests(WebCore::String origin); + + WebViewCore* m_webViewCore; + WebCore::Frame* m_mainFrame; + WebCore::String m_originInProgress; + typedef Vector<WebCore::String> OriginVector; + OriginVector m_queuedOrigins; + + typedef WTF::HashMap<WebCore::String, bool> PermissionsMap; + PermissionsMap m_temporaryPermissions; + static PermissionsMap s_permanentPermissions; + + typedef WTF::Vector<GeolocationPermissions*> GeolocationPermissionsVector; + static GeolocationPermissionsVector s_instances; + + WebCore::Timer<GeolocationPermissions> m_timer; + + struct CallbackData { + WebCore::String origin; + bool allow; + }; + CallbackData m_callbackData; + + }; + +} // namespace android + +#endif diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp index 46e1fdc..b856e10 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -426,6 +426,16 @@ WebFrame::loadStarted(WebCore::Frame* frame) env->DeleteLocalRef(urlStr); if (favicon) env->DeleteLocalRef(favicon); + + // Inform the client that the main frame has started a new load. + if (isMainFrame && mPage) { + Chrome* chrome = mPage->chrome(); + if (chrome) { + ChromeClientAndroid* client = static_cast<ChromeClientAndroid*>(chrome->client()); + if (client) + client->onMainFrameLoadStarted(); + } + } } void @@ -1358,4 +1368,3 @@ int register_webframe(JNIEnv* env) } } /* namespace android */ - diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index f46759a..0bcb80b 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -1950,6 +1950,15 @@ void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); checkException(env); #endif + +void WebViewCore::geolocationPermissionsShowPrompt(const WebCore::String& origin) +{ + // FIXME: Implement. +} + +void WebViewCore::geolocationPermissionsHidePrompt() +{ + // FIXME: Implement. } bool WebViewCore::jsConfirm(const WebCore::String& url, const WebCore::String& text) diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index 8fbe934..c47be86 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -199,6 +199,18 @@ namespace android { */ void reachedMaxAppCacheSize(const unsigned long long spaceNeeded); + /** + * Instruct the browser to show a Geolocation permission prompt for the + * specified origin. + * @param origin The origin of the frame requesting Geolocation + * permissions. + */ + void geolocationPermissionsShowPrompt(const WebCore::String& origin); + /** + * Instruct the browser to hide the Geolocation permission prompt. + */ + void geolocationPermissionsHidePrompt(); + void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID); // |