diff options
author | Steve Block <steveblock@google.com> | 2009-08-12 10:03:06 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2009-08-12 17:28:18 +0100 |
commit | 0c97c982f069c9d9eee236d7f8461710d2e1d078 (patch) | |
tree | 1a0ee3d1a84a12121ba0801847faaeed1f9a6f03 /WebCore | |
parent | fa9da1d0abed2fcdb5ff1d38f47a97190fb769a5 (diff) | |
download | external_webkit-0c97c982f069c9d9eee236d7f8461710d2e1d078.zip external_webkit-0c97c982f069c9d9eee236d7f8461710d2e1d078.tar.gz external_webkit-0c97c982f069c9d9eee236d7f8461710d2e1d078.tar.bz2 |
Fail fast if Geolocation permissions have already been denied.
Diffstat (limited to 'WebCore')
-rw-r--r-- | WebCore/page/Geolocation.cpp | 83 | ||||
-rw-r--r-- | WebCore/page/Geolocation.h | 11 |
2 files changed, 74 insertions, 20 deletions
diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp index fd429c4..5421eaa 100644 --- a/WebCore/page/Geolocation.cpp +++ b/WebCore/page/Geolocation.cpp @@ -30,22 +30,32 @@ #include "Document.h" #include "Frame.h" #include "Page.h" -#include "PositionError.h" namespace WebCore { -Geolocation::GeoNotifier::GeoNotifier(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) - : m_successCallback(successCallback) +static const char* permissionDeniedErrorMessage = "User denied Geolocation"; + +Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) + : m_geolocation(geolocation) + , m_successCallback(successCallback) , m_errorCallback(errorCallback) , m_options(options) , m_timer(this, &Geolocation::GeoNotifier::timerFired) + , m_fatalError(0) { + ASSERT(m_geolocation); ASSERT(m_successCallback); // If no options were supplied from JS, we should have created a default set // of options in JSGeolocationCustom.cpp. ASSERT(m_options); } +void Geolocation::GeoNotifier::setFatalError(PassRefPtr<PositionError> error) +{ + m_fatalError = error; + m_timer.startOneShot(0); +} + void Geolocation::GeoNotifier::startTimer() { if (m_errorCallback && m_options->hasTimeout()) @@ -54,10 +64,17 @@ void Geolocation::GeoNotifier::startTimer() void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*) { - ASSERT(m_errorCallback); - m_timer.stop(); + if (m_fatalError) { + if (m_errorCallback) { + m_errorCallback->handleEvent(m_fatalError.get()); + } + // This will cause this notifier to be deleted. + m_geolocation->fatalErrorOccurred(this); + return; + } + RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timed out"); m_errorCallback->handleEvent(error.get()); } @@ -82,29 +99,59 @@ void Geolocation::disconnectFrame() void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) { - RefPtr<GeoNotifier> notifier = GeoNotifier::create(successCallback, errorCallback, options); + RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options); - if (!m_service->startUpdating(notifier->m_options.get())) { - if (notifier->m_errorCallback) { - RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start"); - notifier->m_errorCallback->handleEvent(error.get()); + // Check whether permissions have already been denied. Note that if this is the case, + // the permission state can not change again in the lifetime of this page. + if (isDenied()) { + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage); + notifier->setFatalError(error.release()); + } else { + if (!m_service->startUpdating(notifier->m_options.get())) { + if (notifier->m_errorCallback) { + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start"); + notifier->m_errorCallback->handleEvent(error.get()); + } + return; } - return; } m_oneShots.add(notifier); + +} + +void Geolocation::fatalErrorOccurred(Geolocation::GeoNotifier* notifier) +{ + // This request has failed fatally. Remove it from our lists. + m_oneShots.remove(notifier); + for (GeoNotifierMap::iterator iter = m_watchers.begin(); iter != m_watchers.end(); ++iter) { + if (iter->second == notifier) { + m_watchers.remove(iter); + break; + } + } + + if (!hasListeners()) + m_service->stopUpdating(); } int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) { - RefPtr<GeoNotifier> notifier = GeoNotifier::create(successCallback, errorCallback, options); + RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options); - if (!m_service->startUpdating(notifier->m_options.get())) { - if (notifier->m_errorCallback) { - RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start"); - notifier->m_errorCallback->handleEvent(error.get()); + // Check whether permissions have already been denied. Note that if this is the case, + // the permission state can not change again in the lifetime of this page. + if (isDenied()) { + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage); + notifier->setFatalError(error.release()); + } else { + if (!m_service->startUpdating(notifier->m_options.get())) { + if (notifier->m_errorCallback) { + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start"); + notifier->m_errorCallback->handleEvent(error.get()); + } + return 0; } - return 0; } static int sIdentifier = 0; @@ -142,7 +189,7 @@ void Geolocation::setIsAllowed(bool allowed) startTimers(); makeSuccessCallbacks(); } else { - WTF::RefPtr<WebCore::PositionError> error = WebCore::PositionError::create(PositionError::PERMISSION_DENIED, "User disallowed GeoLocation"); + WTF::RefPtr<WebCore::PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage); handleError(error.get()); } } diff --git a/WebCore/page/Geolocation.h b/WebCore/page/Geolocation.h index 44a7fe0..547d284 100644 --- a/WebCore/page/Geolocation.h +++ b/WebCore/page/Geolocation.h @@ -28,6 +28,7 @@ #include "GeolocationService.h" #include "PositionCallback.h" +#include "PositionError.h" #include "PositionErrorCallback.h" #include "PositionOptions.h" #include "Timer.h" @@ -64,6 +65,7 @@ public: void setIsAllowed(bool); bool isAllowed() const { return m_allowGeolocation == Yes; } + bool isDenied() const { return m_allowGeolocation == No; } void setShouldClearCache(bool shouldClearCache) { m_shouldClearCache = shouldClearCache; } bool shouldClearCache() const { return m_shouldClearCache; } @@ -73,18 +75,21 @@ private: class GeoNotifier : public RefCounted<GeoNotifier> { public: - static PassRefPtr<GeoNotifier> create(PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PassRefPtr<PositionOptions> options) { return adoptRef(new GeoNotifier(positionCallback, positionErrorCallback, options)); } + static PassRefPtr<GeoNotifier> create(Geolocation* geolocation, PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PassRefPtr<PositionOptions> options) { return adoptRef(new GeoNotifier(geolocation, positionCallback, positionErrorCallback, options)); } + void setFatalError(PassRefPtr<PositionError> error); void startTimer(); void timerFired(Timer<GeoNotifier>*); + Geolocation* m_geolocation; RefPtr<PositionCallback> m_successCallback; RefPtr<PositionErrorCallback> m_errorCallback; RefPtr<PositionOptions> m_options; Timer<GeoNotifier> m_timer; + RefPtr<PositionError> m_fatalError; private: - GeoNotifier(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>); + GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>); }; bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); } @@ -108,6 +113,8 @@ private: virtual void geolocationServicePositionChanged(GeolocationService*); virtual void geolocationServiceErrorOccurred(GeolocationService*); + void fatalErrorOccurred(GeoNotifier* notifier); + typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet; typedef HashMap<int, RefPtr<GeoNotifier> > GeoNotifierMap; |