summaryrefslogtreecommitdiffstats
path: root/WebCore/page
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/page')
-rw-r--r--WebCore/page/Geolocation.cpp136
-rw-r--r--WebCore/page/Geolocation.h22
-rw-r--r--WebCore/page/PositionError.h6
-rw-r--r--WebCore/page/PositionOptions.h37
-rw-r--r--WebCore/page/SecurityOrigin.cpp7
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)