diff options
Diffstat (limited to 'WebCore/page')
-rw-r--r-- | WebCore/page/Geolocation.cpp | 136 | ||||
-rw-r--r-- | WebCore/page/Geolocation.h | 22 | ||||
-rw-r--r-- | WebCore/page/PositionError.h | 6 | ||||
-rw-r--r-- | WebCore/page/PositionOptions.h | 37 | ||||
-rw-r--r-- | WebCore/page/SecurityOrigin.cpp | 7 |
5 files changed, 155 insertions, 53 deletions
diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp index 5337bcc..e57a8b5 100644 --- a/WebCore/page/Geolocation.cpp +++ b/WebCore/page/Geolocation.cpp @@ -31,32 +31,56 @@ #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() +void Geolocation::GeoNotifier::startTimerIfNeeded() { - if (m_errorCallback && m_options) + if (m_options->hasTimeout()) m_timer.startOneShot(m_options->timeout() / 1000.0); } void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*) { - ASSERT(m_errorCallback); - m_timer.stop(); - RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timed out"); - m_errorCallback->handleEvent(error.get()); + 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; + } + + if (m_errorCallback) { + RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timed out"); + m_errorCallback->handleEvent(error.get()); + } + m_geolocation->requestTimedOut(this); } Geolocation::Geolocation(Frame* frame) @@ -81,29 +105,63 @@ 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())) + notifier->startTimerIfNeeded(); + else { + 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())) + notifier->startTimerIfNeeded(); + else { + 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; @@ -113,6 +171,15 @@ int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, Pas return sIdentifier; } +void Geolocation::requestTimedOut(GeoNotifier* notifier) +{ + // If this is a one-shot request, stop it. + m_oneShots.remove(notifier); + + if (!hasListeners()) + m_service->stopUpdating(); +} + void Geolocation::clearWatch(int watchId) { m_watchers.remove(watchId); @@ -138,10 +205,10 @@ void Geolocation::setIsAllowed(bool allowed) m_allowGeolocation = allowed ? Yes : No; if (isAllowed()) { - 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); + error->setIsFatal(true); handleError(error.get()); } } @@ -201,35 +268,35 @@ void Geolocation::sendPositionToWatchers(Geoposition* position) sendPosition(copy, position); } -void Geolocation::startTimer(Vector<RefPtr<GeoNotifier> >& notifiers) +void Geolocation::stopTimer(Vector<RefPtr<GeoNotifier> >& notifiers) { Vector<RefPtr<GeoNotifier> >::const_iterator end = notifiers.end(); for (Vector<RefPtr<GeoNotifier> >::const_iterator it = notifiers.begin(); it != end; ++it) { RefPtr<GeoNotifier> notifier = *it; - notifier->startTimer(); + notifier->m_timer.stop(); } } -void Geolocation::startTimersForOneShots() +void Geolocation::stopTimersForOneShots() { Vector<RefPtr<GeoNotifier> > copy; copyToVector(m_oneShots, copy); - startTimer(copy); + stopTimer(copy); } -void Geolocation::startTimersForWatchers() +void Geolocation::stopTimersForWatchers() { Vector<RefPtr<GeoNotifier> > copy; copyValuesToVector(m_watchers, copy); - startTimer(copy); + stopTimer(copy); } -void Geolocation::startTimers() +void Geolocation::stopTimers() { - startTimersForOneShots(); - startTimersForWatchers(); + stopTimersForOneShots(); + stopTimersForWatchers(); } void Geolocation::handleError(PositionError* error) @@ -240,6 +307,8 @@ void Geolocation::handleError(PositionError* error) sendErrorToWatchers(error); m_oneShots.clear(); + if (error->isFatal()) + m_watchers.clear(); if (!hasListeners()) m_service->stopUpdating(); @@ -267,6 +336,9 @@ void Geolocation::geolocationServicePositionChanged(GeolocationService*) { ASSERT(m_service->lastPosition()); + // Stop all currently running timers. + stopTimers(); + if (!isAllowed()) { // requestPermission() will ask the chrome for permission. This may be // implemented synchronously or asynchronously. In both cases, diff --git a/WebCore/page/Geolocation.h b/WebCore/page/Geolocation.h index a3fd5e8..6681592 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 startTimer(); + void setFatalError(PassRefPtr<PositionError> error); + void startTimerIfNeeded(); 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(); } @@ -97,10 +102,10 @@ private: void sendPositionToOneShots(Geoposition*); void sendPositionToWatchers(Geoposition*); - static void startTimer(Vector<RefPtr<GeoNotifier> >&); - void startTimersForOneShots(); - void startTimersForWatchers(); - void startTimers(); + static void stopTimer(Vector<RefPtr<GeoNotifier> >&); + void stopTimersForOneShots(); + void stopTimersForWatchers(); + void stopTimers(); void makeSuccessCallbacks(); void handleError(PositionError*); @@ -111,6 +116,9 @@ private: virtual void geolocationServicePositionChanged(GeolocationService*); virtual void geolocationServiceErrorOccurred(GeolocationService*); + void fatalErrorOccurred(GeoNotifier* notifier); + void requestTimedOut(GeoNotifier* notifier); + typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet; typedef HashMap<int, RefPtr<GeoNotifier> > GeoNotifierMap; diff --git a/WebCore/page/PositionError.h b/WebCore/page/PositionError.h index 1d31f3b..c309061 100644 --- a/WebCore/page/PositionError.h +++ b/WebCore/page/PositionError.h @@ -45,16 +45,22 @@ public: ErrorCode code() const { return m_code; } const String& message() const { return m_message; } + void setIsFatal(bool isFatal) { m_isFatal = isFatal; } + bool isFatal() { return m_isFatal; } private: PositionError(ErrorCode code, const String& message) : m_code(code) , m_message(message) + , m_isFatal(false) { } ErrorCode m_code; String m_message; + // Whether the error is fatal, such that no request can ever obtain a good + // position fix in the future. + bool m_isFatal; }; } // namespace WebCore diff --git a/WebCore/page/PositionOptions.h b/WebCore/page/PositionOptions.h index 10845d3..0a7f625 100644 --- a/WebCore/page/PositionOptions.h +++ b/WebCore/page/PositionOptions.h @@ -33,26 +33,41 @@ namespace WebCore { class PositionOptions : public RefCounted<PositionOptions> { public: - static PassRefPtr<PositionOptions> create(bool highAccuracy, unsigned timeout, unsigned maximumAge) { return adoptRef(new PositionOptions(highAccuracy, timeout, maximumAge)); } + static PassRefPtr<PositionOptions> create() { return adoptRef(new PositionOptions); } bool enableHighAccuracy() const { return m_highAccuracy; } void setEnableHighAccuracy(bool enable) { m_highAccuracy = enable; } - unsigned timeout() const { return m_timeout; } - void setTimeout(unsigned t) { m_timeout = t; } - unsigned maximumAge() const { return m_maximumAge; } - void setMaximumAge(unsigned a) { m_maximumAge = a; } + bool hasTimeout() { return m_hasTimeout; } + int timeout() const + { + ASSERT(hasTimeout()); + return m_timeout; + } + void setTimeout(int timeout) + { + ASSERT(timeout >= 0); + m_hasTimeout = true; + m_timeout = timeout; + } + int maximumAge() const { return m_maximumAge; } + void setMaximumAge(int age) + { + ASSERT(age >= 0); + m_maximumAge = age; + } private: - PositionOptions(bool highAccuracy, unsigned timeout, unsigned maximumAge) - : m_highAccuracy(highAccuracy) - , m_timeout(timeout) - , m_maximumAge(maximumAge) + PositionOptions() + : m_highAccuracy(false) + , m_hasTimeout(false) + , m_maximumAge(0) { } bool m_highAccuracy; - unsigned m_timeout; - unsigned m_maximumAge; + bool m_hasTimeout; + int m_timeout; + int m_maximumAge; }; } // namespace WebCore diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp index baafd4e..14a1b59 100644 --- a/WebCore/page/SecurityOrigin.cpp +++ b/WebCore/page/SecurityOrigin.cpp @@ -281,15 +281,16 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const St if (separator2 == -1) return create(KURL()); - // Ensure there were at least 2 seperator characters. Some hostnames on intranets have + // Ensure there were at least 2 separator characters. Some hostnames on intranets have // underscores in them, so we'll assume that any additional underscores are part of the host. - if (separator1 != separator2) + if (separator1 == separator2) return create(KURL()); // Make sure the port section is a valid port number or doesn't exist bool portOkay; int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay); - if (!portOkay && separator2 + 1 == static_cast<int>(databaseIdentifier.length())) + bool portAbsent = (separator2 == static_cast<int>(databaseIdentifier.length()) - 1); + if (!(portOkay || portAbsent)) return create(KURL()); if (port < 0 || port > 65535) |