Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2c3d787

Browse filesBrowse files
committed
Bug 1715482 - Geolocation should gracefully handle Documents that are not fully active r=saschanaz
Spec change w3c/geolocation#97 Differential Revision: https://phabricator.services.mozilla.com/D117273
1 parent 0541a62 commit 2c3d787
Copy full SHA for 2c3d787

File tree

5 files changed

+174
-22
lines changed
Filter options

5 files changed

+174
-22
lines changed

‎dom/geolocation/Geolocation.cpp

Copy file name to clipboardExpand all lines: dom/geolocation/Geolocation.cpp
+26
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,16 @@ Geolocation::NotifyError(uint16_t aErrorCode) {
922922
return NS_OK;
923923
}
924924

925+
bool Geolocation::IsFullyActiveOrChrome() {
926+
// For regular content window, only allow this proceed if the window is "fully
927+
// active".
928+
if (nsPIDOMWindowInner* window = this->GetParentObject()) {
929+
return window->IsFullyActive();
930+
}
931+
// Calls coming from chrome code don't have window, so we can proceed.
932+
return true;
933+
}
934+
925935
bool Geolocation::IsAlreadyCleared(nsGeolocationRequest* aRequest) {
926936
for (uint32_t i = 0, length = mClearedWatchIDs.Length(); i < length; ++i) {
927937
if (mClearedWatchIDs[i] == aRequest->WatchId()) {
@@ -993,6 +1003,14 @@ nsresult Geolocation::GetCurrentPosition(GeoPositionCallback callback,
9931003
GeoPositionErrorCallback errorCallback,
9941004
UniquePtr<PositionOptions>&& options,
9951005
CallerType aCallerType) {
1006+
if (!IsFullyActiveOrChrome()) {
1007+
RefPtr<GeolocationPositionError> positionError =
1008+
new GeolocationPositionError(
1009+
this, GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
1010+
positionError->NotifyCallback(errorCallback);
1011+
return NS_OK;
1012+
}
1013+
9961014
if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
9971015
return NS_ERROR_NOT_AVAILABLE;
9981016
}
@@ -1059,6 +1077,14 @@ int32_t Geolocation::WatchPosition(GeoPositionCallback aCallback,
10591077
GeoPositionErrorCallback aErrorCallback,
10601078
UniquePtr<PositionOptions>&& aOptions,
10611079
CallerType aCallerType, ErrorResult& aRv) {
1080+
if (!IsFullyActiveOrChrome()) {
1081+
RefPtr<GeolocationPositionError> positionError =
1082+
new GeolocationPositionError(
1083+
this, GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
1084+
positionError->NotifyCallback(aErrorCallback);
1085+
return 0;
1086+
}
1087+
10621088
if (mWatchingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
10631089
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
10641090
return 0;

‎dom/geolocation/Geolocation.h

Copy file name to clipboardExpand all lines: dom/geolocation/Geolocation.h
+8
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
138138
PositionErrorCallback* aErrorCallback,
139139
const PositionOptions& aOptions, CallerType aCallerType,
140140
ErrorResult& aRv);
141+
142+
MOZ_CAN_RUN_SCRIPT
141143
void GetCurrentPosition(PositionCallback& aCallback,
142144
PositionErrorCallback* aErrorCallback,
143145
const PositionOptions& aOptions,
@@ -185,10 +187,12 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
185187
private:
186188
~Geolocation();
187189

190+
MOZ_CAN_RUN_SCRIPT
188191
nsresult GetCurrentPosition(GeoPositionCallback aCallback,
189192
GeoPositionErrorCallback aErrorCallback,
190193
UniquePtr<PositionOptions>&& aOptions,
191194
CallerType aCallerType);
195+
192196
MOZ_CAN_RUN_SCRIPT
193197
int32_t WatchPosition(GeoPositionCallback aCallback,
194198
GeoPositionErrorCallback aErrorCallback,
@@ -204,6 +208,10 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
204208
// within a context that is not secure.
205209
bool ShouldBlockInsecureRequests() const;
206210

211+
// Checks if the request is in a content window that is fully active, or the
212+
// request is coming from a chrome window.
213+
bool IsFullyActiveOrChrome();
214+
207215
// Two callback arrays. The first |mPendingCallbacks| holds objects for only
208216
// one callback and then they are released/removed from the array. The second
209217
// |mWatchingCallbacks| holds objects until the object is explictly removed or

‎dom/tests/mochitest/chrome/test_geolocation.xhtml

Copy file name to clipboardExpand all lines: dom/tests/mochitest/chrome/test_geolocation.xhtml
+44-22
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,51 @@
44
<!--
55
Test for Geolocation in chrome
66
-->
7-
<window id="sample-window" width="400" height="400"
8-
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
9-
<script type="application/javascript"
10-
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
7+
<window
8+
id="sample-window"
9+
width="400"
10+
height="400"
11+
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
12+
>
13+
<script
14+
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"
15+
></script>
1116

12-
<script>
13-
SimpleTest.waitForExplicitFinish();
17+
<script>
18+
SimpleTest.waitForExplicitFinish();
19+
async function test() {
20+
/** @type {Geolocation} */
21+
const geolocation = Cc["@mozilla.org/geolocation;1"].getService(
22+
Ci.nsISupports
23+
);
24+
try {
25+
// Watch position
26+
let watchId;
27+
let position = await new Promise((resolve, reject) => {
28+
watchId = geolocation.watchPosition(resolve, reject, { timeout: 0 });
29+
});
30+
ok(position, "watchPosition() callable from chrome");
31+
geolocation.clearWatch(watchId);
1432

15-
var geolocation = Cc["@mozilla.org/geolocation;1"].getService(Ci.nsISupports);
16-
geolocation.getCurrentPosition(done, error);
17-
18-
function error(error)
19-
{
20-
ok(0, "error occured trying to get geolocation from chrome");
21-
SimpleTest.finish();
22-
}
23-
function done(position)
24-
{
25-
ok(position, "geolocation was found from chrome");
26-
SimpleTest.finish();
27-
}
28-
</script>
29-
30-
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
33+
// Get position
34+
position = await new Promise((resolve, reject) =>
35+
geolocation.getCurrentPosition(resolve, reject)
36+
);
37+
ok(position, "getCurrentPosition() callable from chrome");
38+
} catch (err) {
39+
ok(
40+
false,
41+
"error occurred trying to get geolocation from chrome: " + err.message
42+
);
43+
} finally {
44+
SimpleTest.finish();
45+
}
46+
}
47+
</script>
3148

49+
<body
50+
xmlns="http://www.w3.org/1999/xhtml"
51+
style="height: 300px; overflow: auto;"
52+
onload="test()"
53+
/>
3254
</window>

‎dom/tests/mochitest/geolocation/mochitest.ini

Copy file name to clipboardExpand all lines: dom/tests/mochitest/geolocation/mochitest.ini
+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ skip-if = xorigin # Hangs
5757
[test_featurePolicy.html]
5858
support-files = file_featurePolicy.html
5959
fail-if = xorigin
60+
[test_not_fully_active.html]
61+
skip-if = xorigin # Hangs
62+
support-files = popup.html
6063

6164
# This test REQUIRES to run on HTTP (_NOT_ HTTPS).
6265
[test_geoWatchPositionBlockedInInsecureContext.html]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>
5+
Test for when geolocation is used on non fully active documents
6+
</title>
7+
<script src="/tests/SimpleTest/SimpleTest.js"></script>
8+
<script src="geolocation_common.js"></script>
9+
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
10+
</head>
11+
<body>
12+
<script>
13+
SimpleTest.waitForExplicitFinish();
14+
15+
async function runTest() {
16+
// Create the iframe, wait for it to load...
17+
const iframe = document.createElement("iframe");
18+
19+
// We rely on this popup.html to acquire prompt privileges.
20+
iframe.src = "popup.html";
21+
document.body.appendChild(iframe);
22+
iframe.contentWindow.opener = window;
23+
await new Promise(r => window.addEventListener("message", r, { once: true }));
24+
25+
// Steal geolocation.
26+
const geo = iframe.contentWindow.navigator.geolocation;
27+
28+
// No longer fully active.
29+
iframe.remove();
30+
31+
// Try to watch a position while not fully active...
32+
const watchError = await new Promise((resolve, reject) => {
33+
const result = geo.watchPosition(
34+
reject, // We don't want a position
35+
resolve // We want an error!
36+
);
37+
is(result, 0, "watchPosition returns 0 on non-fully-active document");
38+
});
39+
is(
40+
watchError.code,
41+
GeolocationPositionError.POSITION_UNAVAILABLE,
42+
"watchPosition returns an error on non-fully-active document"
43+
);
44+
45+
// Now try to get current position while not fully active...
46+
const positionError = await new Promise((resolve, reject) => {
47+
const result = geo.getCurrentPosition(
48+
reject, // We don't want a position
49+
resolve // We want an error!
50+
);
51+
});
52+
is(
53+
positionError.code,
54+
GeolocationPositionError.POSITION_UNAVAILABLE,
55+
"getCurrentPosition returns an error on non-fully-active document"
56+
);
57+
58+
// Re-attach, and go back to fully active.
59+
document.body.appendChild(iframe);
60+
iframe.contentWindow.opener = window;
61+
await new Promise(r => window.addEventListener("message", r, { once: true }));
62+
63+
// And we are back to fully active.
64+
let watchId;
65+
let position = await new Promise((resolve, reject) => {
66+
watchId = iframe.contentWindow.navigator.geolocation.watchPosition(
67+
resolve,
68+
reject
69+
);
70+
});
71+
ok(watchId > 0, "Expected anything greater than 0");
72+
ok(position, "Expected a position");
73+
74+
// Finally, let's get the position from the reattached document.
75+
position = await new Promise((resolve, reject) => {
76+
iframe.contentWindow.navigator.geolocation.getCurrentPosition(
77+
resolve,
78+
reject
79+
);
80+
});
81+
ok(position, "Expected a position");
82+
iframe.contentWindow.navigator.geolocation.clearWatch(watchId);
83+
iframe.remove();
84+
}
85+
86+
resume_geolocationProvider(async () => {
87+
await new Promise(r => force_prompt(true, r));
88+
await runTest();
89+
SimpleTest.finish();
90+
});
91+
</script>
92+
</body>
93+
</html>

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.