зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1715482 - Geolocation should gracefully handle Documents that are not fully active r=saschanaz
Spec change https://github.com/w3c/geolocation-api/pull/97 Differential Revision: https://phabricator.services.mozilla.com/D117273
This commit is contained in:
Родитель
24feffa455
Коммит
fc57eb2e71
|
@ -922,6 +922,16 @@ Geolocation::NotifyError(uint16_t aErrorCode) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool Geolocation::IsFullyActiveOrChrome() {
|
||||
// For regular content window, only allow this proceed if the window is "fully
|
||||
// active".
|
||||
if (nsPIDOMWindowInner* window = this->GetParentObject()) {
|
||||
return window->IsFullyActive();
|
||||
}
|
||||
// Calls coming from chrome code don't have window, so we can proceed.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Geolocation::IsAlreadyCleared(nsGeolocationRequest* aRequest) {
|
||||
for (uint32_t i = 0, length = mClearedWatchIDs.Length(); i < length; ++i) {
|
||||
if (mClearedWatchIDs[i] == aRequest->WatchId()) {
|
||||
|
@ -993,6 +1003,14 @@ nsresult Geolocation::GetCurrentPosition(GeoPositionCallback callback,
|
|||
GeoPositionErrorCallback errorCallback,
|
||||
UniquePtr<PositionOptions>&& options,
|
||||
CallerType aCallerType) {
|
||||
if (!IsFullyActiveOrChrome()) {
|
||||
RefPtr<GeolocationPositionError> positionError =
|
||||
new GeolocationPositionError(
|
||||
this, GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
|
||||
positionError->NotifyCallback(errorCallback);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
@ -1059,6 +1077,14 @@ int32_t Geolocation::WatchPosition(GeoPositionCallback aCallback,
|
|||
GeoPositionErrorCallback aErrorCallback,
|
||||
UniquePtr<PositionOptions>&& aOptions,
|
||||
CallerType aCallerType, ErrorResult& aRv) {
|
||||
if (!IsFullyActiveOrChrome()) {
|
||||
RefPtr<GeolocationPositionError> positionError =
|
||||
new GeolocationPositionError(
|
||||
this, GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
|
||||
positionError->NotifyCallback(aErrorCallback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mWatchingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return 0;
|
||||
|
|
|
@ -138,6 +138,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
|
|||
PositionErrorCallback* aErrorCallback,
|
||||
const PositionOptions& aOptions, CallerType aCallerType,
|
||||
ErrorResult& aRv);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
void GetCurrentPosition(PositionCallback& aCallback,
|
||||
PositionErrorCallback* aErrorCallback,
|
||||
const PositionOptions& aOptions,
|
||||
|
@ -185,10 +187,12 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
|
|||
private:
|
||||
~Geolocation();
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsresult GetCurrentPosition(GeoPositionCallback aCallback,
|
||||
GeoPositionErrorCallback aErrorCallback,
|
||||
UniquePtr<PositionOptions>&& aOptions,
|
||||
CallerType aCallerType);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
int32_t WatchPosition(GeoPositionCallback aCallback,
|
||||
GeoPositionErrorCallback aErrorCallback,
|
||||
|
@ -204,6 +208,10 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
|
|||
// within a context that is not secure.
|
||||
bool ShouldBlockInsecureRequests() const;
|
||||
|
||||
// Checks if the request is in a content window that is fully active, or the
|
||||
// request is coming from a chrome window.
|
||||
bool IsFullyActiveOrChrome();
|
||||
|
||||
// Two callback arrays. The first |mPendingCallbacks| holds objects for only
|
||||
// one callback and then they are released/removed from the array. The second
|
||||
// |mWatchingCallbacks| holds objects until the object is explictly removed or
|
||||
|
|
|
@ -4,29 +4,51 @@
|
|||
<!--
|
||||
Test for Geolocation in chrome
|
||||
-->
|
||||
<window id="sample-window" width="400" height="400"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<window
|
||||
id="sample-window"
|
||||
width="400"
|
||||
height="400"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
>
|
||||
<script
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"
|
||||
></script>
|
||||
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
async function test() {
|
||||
/** @type {Geolocation} */
|
||||
const geolocation = Cc["@mozilla.org/geolocation;1"].getService(
|
||||
Ci.nsISupports
|
||||
);
|
||||
try {
|
||||
// Watch position
|
||||
let watchId;
|
||||
let position = await new Promise((resolve, reject) => {
|
||||
watchId = geolocation.watchPosition(resolve, reject, { timeout: 0 });
|
||||
});
|
||||
ok(position, "watchPosition() callable from chrome");
|
||||
geolocation.clearWatch(watchId);
|
||||
|
||||
var geolocation = Cc["@mozilla.org/geolocation;1"].getService(Ci.nsISupports);
|
||||
geolocation.getCurrentPosition(done, error);
|
||||
|
||||
function error(error)
|
||||
{
|
||||
ok(0, "error occured trying to get geolocation from chrome");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
function done(position)
|
||||
{
|
||||
ok(position, "geolocation was found from chrome");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
|
||||
// Get position
|
||||
position = await new Promise((resolve, reject) =>
|
||||
geolocation.getCurrentPosition(resolve, reject)
|
||||
);
|
||||
ok(position, "getCurrentPosition() callable from chrome");
|
||||
} catch (err) {
|
||||
ok(
|
||||
false,
|
||||
"error occurred trying to get geolocation from chrome: " + err.message
|
||||
);
|
||||
} finally {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<body
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
style="height: 300px; overflow: auto;"
|
||||
onload="test()"
|
||||
/>
|
||||
</window>
|
||||
|
|
|
@ -57,6 +57,9 @@ skip-if = xorigin # Hangs
|
|||
[test_featurePolicy.html]
|
||||
support-files = file_featurePolicy.html
|
||||
fail-if = xorigin
|
||||
[test_not_fully_active.html]
|
||||
skip-if = xorigin # Hangs
|
||||
support-files = popup.html
|
||||
|
||||
# This test REQUIRES to run on HTTP (_NOT_ HTTPS).
|
||||
[test_geoWatchPositionBlockedInInsecureContext.html]
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test for when geolocation is used on non fully active documents
|
||||
</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="geolocation_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
async function runTest() {
|
||||
// Create the iframe, wait for it to load...
|
||||
const iframe = document.createElement("iframe");
|
||||
|
||||
// We rely on this popup.html to acquire prompt privileges.
|
||||
iframe.src = "popup.html";
|
||||
document.body.appendChild(iframe);
|
||||
iframe.contentWindow.opener = window;
|
||||
await new Promise(r => window.addEventListener("message", r, { once: true }));
|
||||
|
||||
// Steal geolocation.
|
||||
const geo = iframe.contentWindow.navigator.geolocation;
|
||||
|
||||
// No longer fully active.
|
||||
iframe.remove();
|
||||
|
||||
// Try to watch a position while not fully active...
|
||||
const watchError = await new Promise((resolve, reject) => {
|
||||
const result = geo.watchPosition(
|
||||
reject, // We don't want a position
|
||||
resolve // We want an error!
|
||||
);
|
||||
is(result, 0, "watchPosition returns 0 on non-fully-active document");
|
||||
});
|
||||
is(
|
||||
watchError.code,
|
||||
GeolocationPositionError.POSITION_UNAVAILABLE,
|
||||
"watchPosition returns an error on non-fully-active document"
|
||||
);
|
||||
|
||||
// Now try to get current position while not fully active...
|
||||
const positionError = await new Promise((resolve, reject) => {
|
||||
const result = geo.getCurrentPosition(
|
||||
reject, // We don't want a position
|
||||
resolve // We want an error!
|
||||
);
|
||||
});
|
||||
is(
|
||||
positionError.code,
|
||||
GeolocationPositionError.POSITION_UNAVAILABLE,
|
||||
"getCurrentPosition returns an error on non-fully-active document"
|
||||
);
|
||||
|
||||
// Re-attach, and go back to fully active.
|
||||
document.body.appendChild(iframe);
|
||||
iframe.contentWindow.opener = window;
|
||||
await new Promise(r => window.addEventListener("message", r, { once: true }));
|
||||
|
||||
// And we are back to fully active.
|
||||
let watchId;
|
||||
let position = await new Promise((resolve, reject) => {
|
||||
watchId = iframe.contentWindow.navigator.geolocation.watchPosition(
|
||||
resolve,
|
||||
reject
|
||||
);
|
||||
});
|
||||
ok(watchId > 0, "Expected anything greater than 0");
|
||||
ok(position, "Expected a position");
|
||||
|
||||
// Finally, let's get the position from the reattached document.
|
||||
position = await new Promise((resolve, reject) => {
|
||||
iframe.contentWindow.navigator.geolocation.getCurrentPosition(
|
||||
resolve,
|
||||
reject
|
||||
);
|
||||
});
|
||||
ok(position, "Expected a position");
|
||||
iframe.contentWindow.navigator.geolocation.clearWatch(watchId);
|
||||
iframe.remove();
|
||||
}
|
||||
|
||||
resume_geolocationProvider(async () => {
|
||||
await new Promise(r => force_prompt(true, r));
|
||||
await runTest();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче