/src/mozilla-central/dom/base/Navigator.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | // Needs to be first. |
8 | | #include "base/basictypes.h" |
9 | | |
10 | | #include "Navigator.h" |
11 | | #include "nsIXULAppInfo.h" |
12 | | #include "nsPluginArray.h" |
13 | | #include "nsMimeTypeArray.h" |
14 | | #include "mozilla/AntiTrackingCommon.h" |
15 | | #include "mozilla/MemoryReporting.h" |
16 | | #include "mozilla/dom/BodyExtractor.h" |
17 | | #include "mozilla/dom/FetchBinding.h" |
18 | | #include "mozilla/dom/File.h" |
19 | | #include "nsGeolocation.h" |
20 | | #include "nsIClassOfService.h" |
21 | | #include "nsIHttpProtocolHandler.h" |
22 | | #include "nsIContentPolicy.h" |
23 | | #include "nsIContentSecurityPolicy.h" |
24 | | #include "nsContentPolicyUtils.h" |
25 | | #include "nsISupportsPriority.h" |
26 | | #include "nsICachingChannel.h" |
27 | | #include "nsIWebContentHandlerRegistrar.h" |
28 | | #include "nsICookiePermission.h" |
29 | | #include "nsIScriptSecurityManager.h" |
30 | | #include "nsCharSeparatedTokenizer.h" |
31 | | #include "nsContentUtils.h" |
32 | | #include "nsUnicharUtils.h" |
33 | | #include "mozilla/Preferences.h" |
34 | | #include "mozilla/StaticPrefs.h" |
35 | | #include "mozilla/Telemetry.h" |
36 | | #include "BatteryManager.h" |
37 | | #include "mozilla/dom/CredentialsContainer.h" |
38 | | #include "mozilla/dom/Clipboard.h" |
39 | | #include "mozilla/dom/GamepadServiceTest.h" |
40 | | #include "mozilla/dom/MediaCapabilities.h" |
41 | | #include "mozilla/dom/WakeLock.h" |
42 | | #include "mozilla/dom/power/PowerManagerService.h" |
43 | | #include "mozilla/dom/MIDIAccessManager.h" |
44 | | #include "mozilla/dom/MIDIOptionsBinding.h" |
45 | | #include "mozilla/dom/Permissions.h" |
46 | | #include "mozilla/dom/Presentation.h" |
47 | | #include "mozilla/dom/ServiceWorkerContainer.h" |
48 | | #include "mozilla/dom/StorageManager.h" |
49 | | #include "mozilla/dom/TCPSocket.h" |
50 | | #include "mozilla/dom/URLSearchParams.h" |
51 | | #include "mozilla/dom/VRDisplay.h" |
52 | | #include "mozilla/dom/VRDisplayEvent.h" |
53 | | #include "mozilla/dom/VRServiceTest.h" |
54 | | #include "mozilla/dom/workerinternals/RuntimeService.h" |
55 | | #include "mozilla/Hal.h" |
56 | | #include "mozilla/ClearOnShutdown.h" |
57 | | #include "mozilla/StaticPtr.h" |
58 | | #include "Connection.h" |
59 | | #include "mozilla/dom/Event.h" // for Event |
60 | | #include "nsGlobalWindow.h" |
61 | | #include "nsIPermissionManager.h" |
62 | | #include "nsMimeTypes.h" |
63 | | #include "nsNetUtil.h" |
64 | | #include "nsRFPService.h" |
65 | | #include "nsStringStream.h" |
66 | | #include "nsComponentManagerUtils.h" |
67 | | #include "nsICookieService.h" |
68 | | #include "nsIStringStream.h" |
69 | | #include "nsIHttpChannel.h" |
70 | | #include "nsIHttpChannelInternal.h" |
71 | | #include "nsStreamUtils.h" |
72 | | #include "WidgetUtils.h" |
73 | | #include "nsIPresentationService.h" |
74 | | #include "nsIScriptError.h" |
75 | | |
76 | | #include "mozilla/dom/MediaDevices.h" |
77 | | #include "MediaManager.h" |
78 | | |
79 | | #include "nsIDOMGlobalPropertyInitializer.h" |
80 | | #include "nsJSUtils.h" |
81 | | |
82 | | #include "mozilla/dom/NavigatorBinding.h" |
83 | | #include "mozilla/dom/Promise.h" |
84 | | |
85 | | #include "nsIUploadChannel2.h" |
86 | | #include "mozilla/dom/FormData.h" |
87 | | #include "nsIDocShell.h" |
88 | | |
89 | | #include "mozilla/dom/WorkerPrivate.h" |
90 | | #include "mozilla/dom/WorkerRunnable.h" |
91 | | |
92 | | #if defined(XP_LINUX) |
93 | | #include "mozilla/Hal.h" |
94 | | #endif |
95 | | #include "mozilla/dom/ContentChild.h" |
96 | | |
97 | | #include "mozilla/EMEUtils.h" |
98 | | #include "mozilla/DetailedPromise.h" |
99 | | #include "mozilla/Unused.h" |
100 | | |
101 | | namespace mozilla { |
102 | | namespace dom { |
103 | | |
104 | | static bool sVibratorEnabled = false; |
105 | | static uint32_t sMaxVibrateMS = 0; |
106 | | static uint32_t sMaxVibrateListLen = 0; |
107 | | static const char* kVibrationPermissionType = "vibration"; |
108 | | |
109 | | /* static */ |
110 | | void |
111 | | Navigator::Init() |
112 | 3 | { |
113 | 3 | Preferences::AddBoolVarCache(&sVibratorEnabled, |
114 | 3 | "dom.vibrator.enabled", true); |
115 | 3 | Preferences::AddUintVarCache(&sMaxVibrateMS, |
116 | 3 | "dom.vibrator.max_vibrate_ms", 10000); |
117 | 3 | Preferences::AddUintVarCache(&sMaxVibrateListLen, |
118 | 3 | "dom.vibrator.max_vibrate_list_len", 128); |
119 | 3 | } |
120 | | |
121 | | Navigator::Navigator(nsPIDOMWindowInner* aWindow) |
122 | | : mWindow(aWindow) |
123 | 0 | { |
124 | 0 | } |
125 | | |
126 | | Navigator::~Navigator() |
127 | 0 | { |
128 | 0 | Invalidate(); |
129 | 0 | } |
130 | | |
131 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Navigator) |
132 | 0 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
133 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupports) |
134 | 0 | NS_INTERFACE_MAP_END |
135 | | |
136 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(Navigator) |
137 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(Navigator) |
138 | | |
139 | | NS_IMPL_CYCLE_COLLECTION_CLASS(Navigator) |
140 | | |
141 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator) |
142 | 0 | tmp->Invalidate(); |
143 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) |
144 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
145 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
146 | | |
147 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator) |
148 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes) |
149 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins) |
150 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions) |
151 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation) |
152 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager) |
153 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise) |
154 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection) |
155 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager) |
156 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCredentials) |
157 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices) |
158 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer) |
159 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaCapabilities) |
160 | 0 |
|
161 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) |
162 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager) |
163 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresentation) |
164 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepadServiceTest) |
165 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRGetDisplaysPromises) |
166 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRServiceTest) |
167 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
168 | | |
169 | | NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Navigator) |
170 | | |
171 | | void |
172 | | Navigator::Invalidate() |
173 | 0 | { |
174 | 0 | // Don't clear mWindow here so we know we've got a non-null mWindow |
175 | 0 | // until we're unlinked. |
176 | 0 |
|
177 | 0 | mMimeTypes = nullptr; |
178 | 0 |
|
179 | 0 | if (mPlugins) { |
180 | 0 | mPlugins->Invalidate(); |
181 | 0 | mPlugins = nullptr; |
182 | 0 | } |
183 | 0 |
|
184 | 0 | mPermissions = nullptr; |
185 | 0 |
|
186 | 0 | mStorageManager = nullptr; |
187 | 0 |
|
188 | 0 | // If there is a page transition, make sure delete the geolocation object. |
189 | 0 | if (mGeolocation) { |
190 | 0 | mGeolocation->Shutdown(); |
191 | 0 | mGeolocation = nullptr; |
192 | 0 | } |
193 | 0 |
|
194 | 0 | if (mBatteryManager) { |
195 | 0 | mBatteryManager->Shutdown(); |
196 | 0 | mBatteryManager = nullptr; |
197 | 0 | } |
198 | 0 |
|
199 | 0 | mBatteryPromise = nullptr; |
200 | 0 |
|
201 | 0 | if (mConnection) { |
202 | 0 | mConnection->Shutdown(); |
203 | 0 | mConnection = nullptr; |
204 | 0 | } |
205 | 0 |
|
206 | 0 | mMediaDevices = nullptr; |
207 | 0 |
|
208 | 0 | if (mPresentation) { |
209 | 0 | mPresentation = nullptr; |
210 | 0 | } |
211 | 0 |
|
212 | 0 | mServiceWorkerContainer = nullptr; |
213 | 0 |
|
214 | 0 | if (mMediaKeySystemAccessManager) { |
215 | 0 | mMediaKeySystemAccessManager->Shutdown(); |
216 | 0 | mMediaKeySystemAccessManager = nullptr; |
217 | 0 | } |
218 | 0 |
|
219 | 0 | if (mGamepadServiceTest) { |
220 | 0 | mGamepadServiceTest->Shutdown(); |
221 | 0 | mGamepadServiceTest = nullptr; |
222 | 0 | } |
223 | 0 |
|
224 | 0 | mVRGetDisplaysPromises.Clear(); |
225 | 0 |
|
226 | 0 | if (mVRServiceTest) { |
227 | 0 | mVRServiceTest->Shutdown(); |
228 | 0 | mVRServiceTest = nullptr; |
229 | 0 | } |
230 | 0 |
|
231 | 0 | mMediaCapabilities = nullptr; |
232 | 0 | } |
233 | | |
234 | | void |
235 | | Navigator::GetUserAgent(nsAString& aUserAgent, CallerType aCallerType, |
236 | | ErrorResult& aRv) const |
237 | 0 | { |
238 | 0 | nsCOMPtr<nsPIDOMWindowInner> window; |
239 | 0 |
|
240 | 0 | if (mWindow) { |
241 | 0 | window = mWindow; |
242 | 0 | nsIDocShell* docshell = window->GetDocShell(); |
243 | 0 | nsString customUserAgent; |
244 | 0 | if (docshell) { |
245 | 0 | docshell->GetCustomUserAgent(customUserAgent); |
246 | 0 |
|
247 | 0 | if (!customUserAgent.IsEmpty()) { |
248 | 0 | aUserAgent = customUserAgent; |
249 | 0 | return; |
250 | 0 | } |
251 | 0 | } |
252 | 0 | } |
253 | 0 | |
254 | 0 | nsresult rv = GetUserAgent(window, |
255 | 0 | aCallerType == CallerType::System, |
256 | 0 | aUserAgent); |
257 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
258 | 0 | aRv.Throw(rv); |
259 | 0 | } |
260 | 0 | } |
261 | | |
262 | | void |
263 | | Navigator::GetAppCodeName(nsAString& aAppCodeName, ErrorResult& aRv) |
264 | 0 | { |
265 | 0 | nsresult rv; |
266 | 0 |
|
267 | 0 | nsCOMPtr<nsIHttpProtocolHandler> |
268 | 0 | service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); |
269 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
270 | 0 | aRv.Throw(rv); |
271 | 0 | return; |
272 | 0 | } |
273 | 0 | |
274 | 0 | nsAutoCString appName; |
275 | 0 | rv = service->GetAppName(appName); |
276 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
277 | 0 | aRv.Throw(rv); |
278 | 0 | return; |
279 | 0 | } |
280 | 0 | |
281 | 0 | CopyASCIItoUTF16(appName, aAppCodeName); |
282 | 0 | } |
283 | | |
284 | | void |
285 | | Navigator::GetAppVersion(nsAString& aAppVersion, CallerType aCallerType, |
286 | | ErrorResult& aRv) const |
287 | 0 | { |
288 | 0 | nsresult rv = GetAppVersion(aAppVersion, |
289 | 0 | /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System); |
290 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
291 | 0 | aRv.Throw(rv); |
292 | 0 | } |
293 | 0 | } |
294 | | |
295 | | void |
296 | | Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const |
297 | 0 | { |
298 | 0 | AppName(aAppName, |
299 | 0 | /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System); |
300 | 0 | } |
301 | | |
302 | | /** |
303 | | * Returns the value of Accept-Languages (HTTP header) as a nsTArray of |
304 | | * languages. The value is set in the preference by the user ("Content |
305 | | * Languages"). |
306 | | * |
307 | | * "en", "en-US" and "i-cherokee" and "" are valid languages tokens. |
308 | | * |
309 | | * An empty array will be returned if there is no valid languages. |
310 | | */ |
311 | | /* static */ void |
312 | | Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages) |
313 | 0 | { |
314 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
315 | 0 |
|
316 | 0 | aLanguages.Clear(); |
317 | 0 |
|
318 | 0 | // E.g. "de-de, en-us,en". |
319 | 0 | nsAutoString acceptLang; |
320 | 0 | Preferences::GetLocalizedString("intl.accept_languages", acceptLang); |
321 | 0 |
|
322 | 0 | // Split values on commas. |
323 | 0 | nsCharSeparatedTokenizer langTokenizer(acceptLang, ','); |
324 | 0 | while (langTokenizer.hasMoreTokens()) { |
325 | 0 | nsDependentSubstring lang = langTokenizer.nextToken(); |
326 | 0 |
|
327 | 0 | // Replace "_" with "-" to avoid POSIX/Windows "en_US" notation. |
328 | 0 | // NOTE: we should probably rely on the pref being set correctly. |
329 | 0 | if (lang.Length() > 2 && lang[2] == char16_t('_')) { |
330 | 0 | lang.Replace(2, 1, char16_t('-')); |
331 | 0 | } |
332 | 0 |
|
333 | 0 | // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47 |
334 | 0 | // only uppercase 2-letter country codes, not "zh-Hant", "de-DE-x-goethe". |
335 | 0 | // NOTE: we should probably rely on the pref being set correctly. |
336 | 0 | if (lang.Length() > 2) { |
337 | 0 | nsCharSeparatedTokenizer localeTokenizer(lang, '-'); |
338 | 0 | int32_t pos = 0; |
339 | 0 | bool first = true; |
340 | 0 | while (localeTokenizer.hasMoreTokens()) { |
341 | 0 | const nsAString& code = localeTokenizer.nextToken(); |
342 | 0 |
|
343 | 0 | if (code.Length() == 2 && !first) { |
344 | 0 | nsAutoString upper(code); |
345 | 0 | ToUpperCase(upper); |
346 | 0 | lang.Replace(pos, code.Length(), upper); |
347 | 0 | } |
348 | 0 |
|
349 | 0 | pos += code.Length() + 1; // 1 is the separator |
350 | 0 | first = false; |
351 | 0 | } |
352 | 0 | } |
353 | 0 |
|
354 | 0 | aLanguages.AppendElement(lang); |
355 | 0 | } |
356 | 0 | } |
357 | | |
358 | | /** |
359 | | * Do not use UI language (chosen app locale) here but the first value set in |
360 | | * the Accept Languages header, see ::GetAcceptLanguages(). |
361 | | * |
362 | | * See RFC 2616, Section 15.1.4 "Privacy Issues Connected to Accept Headers" for |
363 | | * the reasons why. |
364 | | */ |
365 | | void |
366 | | Navigator::GetLanguage(nsAString& aLanguage) |
367 | 0 | { |
368 | 0 | nsTArray<nsString> languages; |
369 | 0 | GetLanguages(languages); |
370 | 0 | if (languages.Length() >= 1) { |
371 | 0 | aLanguage.Assign(languages[0]); |
372 | 0 | } else { |
373 | 0 | aLanguage.Truncate(); |
374 | 0 | } |
375 | 0 | } |
376 | | |
377 | | void |
378 | | Navigator::GetLanguages(nsTArray<nsString>& aLanguages) |
379 | 0 | { |
380 | 0 | GetAcceptLanguages(aLanguages); |
381 | 0 |
|
382 | 0 | // The returned value is cached by the binding code. The window listen to the |
383 | 0 | // accept languages change and will clear the cache when needed. It has to |
384 | 0 | // take care of dispatching the DOM event already and the invalidation and the |
385 | 0 | // event has to be timed correctly. |
386 | 0 | } |
387 | | |
388 | | void |
389 | | Navigator::GetPlatform(nsAString& aPlatform, CallerType aCallerType, |
390 | | ErrorResult& aRv) const |
391 | 0 | { |
392 | 0 | nsresult rv = GetPlatform(aPlatform, |
393 | 0 | /* aUsePrefOverriddenValue = */ aCallerType != CallerType::System); |
394 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
395 | 0 | aRv.Throw(rv); |
396 | 0 | } |
397 | 0 | } |
398 | | |
399 | | void |
400 | | Navigator::GetOscpu(nsAString& aOSCPU, CallerType aCallerType, |
401 | | ErrorResult& aRv) const |
402 | 0 | { |
403 | 0 | if (aCallerType != CallerType::System) { |
404 | 0 | // If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h |
405 | 0 | // for details about spoofed values. |
406 | 0 | if (nsContentUtils::ShouldResistFingerprinting()) { |
407 | 0 | aOSCPU.AssignLiteral(SPOOFED_OSCPU); |
408 | 0 | return; |
409 | 0 | } |
410 | 0 |
|
411 | 0 | nsAutoString override; |
412 | 0 | nsresult rv = Preferences::GetString("general.oscpu.override", override); |
413 | 0 | if (NS_SUCCEEDED(rv)) { |
414 | 0 | aOSCPU = override; |
415 | 0 | return; |
416 | 0 | } |
417 | 0 | } |
418 | 0 | |
419 | 0 | nsresult rv; |
420 | 0 | nsCOMPtr<nsIHttpProtocolHandler> |
421 | 0 | service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); |
422 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
423 | 0 | aRv.Throw(rv); |
424 | 0 | return; |
425 | 0 | } |
426 | 0 | |
427 | 0 | nsAutoCString oscpu; |
428 | 0 | rv = service->GetOscpu(oscpu); |
429 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
430 | 0 | aRv.Throw(rv); |
431 | 0 | return; |
432 | 0 | } |
433 | 0 | |
434 | 0 | CopyASCIItoUTF16(oscpu, aOSCPU); |
435 | 0 | } |
436 | | |
437 | | void |
438 | | Navigator::GetVendor(nsAString& aVendor) |
439 | 0 | { |
440 | 0 | aVendor.Truncate(); |
441 | 0 | } |
442 | | |
443 | | void |
444 | | Navigator::GetVendorSub(nsAString& aVendorSub) |
445 | 0 | { |
446 | 0 | aVendorSub.Truncate(); |
447 | 0 | } |
448 | | |
449 | | void |
450 | | Navigator::GetProduct(nsAString& aProduct) |
451 | 0 | { |
452 | 0 | aProduct.AssignLiteral("Gecko"); |
453 | 0 | } |
454 | | |
455 | | void |
456 | | Navigator::GetProductSub(nsAString& aProductSub) |
457 | 0 | { |
458 | 0 | // Legacy build ID hardcoded for backward compatibility (bug 776376) |
459 | 0 | aProductSub.AssignLiteral(LEGACY_BUILD_ID); |
460 | 0 | } |
461 | | |
462 | | nsMimeTypeArray* |
463 | | Navigator::GetMimeTypes(ErrorResult& aRv) |
464 | 0 | { |
465 | 0 | if (!mMimeTypes) { |
466 | 0 | if (!mWindow) { |
467 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
468 | 0 | return nullptr; |
469 | 0 | } |
470 | 0 | mMimeTypes = new nsMimeTypeArray(mWindow); |
471 | 0 | } |
472 | 0 |
|
473 | 0 | return mMimeTypes; |
474 | 0 | } |
475 | | |
476 | | nsPluginArray* |
477 | | Navigator::GetPlugins(ErrorResult& aRv) |
478 | 0 | { |
479 | 0 | if (!mPlugins) { |
480 | 0 | if (!mWindow) { |
481 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
482 | 0 | return nullptr; |
483 | 0 | } |
484 | 0 | mPlugins = new nsPluginArray(mWindow); |
485 | 0 | mPlugins->Init(); |
486 | 0 | } |
487 | 0 |
|
488 | 0 | return mPlugins; |
489 | 0 | } |
490 | | |
491 | | Permissions* |
492 | | Navigator::GetPermissions(ErrorResult& aRv) |
493 | 0 | { |
494 | 0 | if (!mWindow) { |
495 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
496 | 0 | return nullptr; |
497 | 0 | } |
498 | 0 | |
499 | 0 | if (!mPermissions) { |
500 | 0 | mPermissions = new Permissions(mWindow); |
501 | 0 | } |
502 | 0 |
|
503 | 0 | return mPermissions; |
504 | 0 | } |
505 | | |
506 | | StorageManager* |
507 | | Navigator::Storage() |
508 | 0 | { |
509 | 0 | MOZ_ASSERT(mWindow); |
510 | 0 |
|
511 | 0 | if(!mStorageManager) { |
512 | 0 | mStorageManager = new StorageManager(mWindow->AsGlobal()); |
513 | 0 | } |
514 | 0 |
|
515 | 0 | return mStorageManager; |
516 | 0 | } |
517 | | |
518 | | bool |
519 | | Navigator::CookieEnabled() |
520 | 0 | { |
521 | 0 | bool cookieEnabled = (StaticPrefs::network_cookie_cookieBehavior() != |
522 | 0 | nsICookieService::BEHAVIOR_REJECT); |
523 | 0 |
|
524 | 0 | // Check whether an exception overrides the global cookie behavior |
525 | 0 | // Note that the code for getting the URI here matches that in |
526 | 0 | // nsHTMLDocument::SetCookie. |
527 | 0 | if (!mWindow || !mWindow->GetDocShell()) { |
528 | 0 | return cookieEnabled; |
529 | 0 | } |
530 | 0 | |
531 | 0 | nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc(); |
532 | 0 | if (!doc) { |
533 | 0 | return cookieEnabled; |
534 | 0 | } |
535 | 0 | |
536 | 0 | nsCOMPtr<nsIURI> codebaseURI; |
537 | 0 | doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI)); |
538 | 0 |
|
539 | 0 | if (!codebaseURI) { |
540 | 0 | // Not a codebase, so technically can't set cookies, but let's |
541 | 0 | // just return the default value. |
542 | 0 | return cookieEnabled; |
543 | 0 | } |
544 | 0 | |
545 | 0 | uint32_t rejectedReason = 0; |
546 | 0 | if (AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(mWindow, |
547 | 0 | codebaseURI, |
548 | 0 | &rejectedReason)) { |
549 | 0 | return true; |
550 | 0 | } |
551 | 0 | |
552 | 0 | if (rejectedReason) { |
553 | 0 | AntiTrackingCommon::NotifyRejection(mWindow, rejectedReason); |
554 | 0 | } |
555 | 0 | return false; |
556 | 0 | } |
557 | | |
558 | | bool |
559 | | Navigator::OnLine() |
560 | 0 | { |
561 | 0 | return !NS_IsOffline(); |
562 | 0 | } |
563 | | |
564 | | void |
565 | | Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType, |
566 | | ErrorResult& aRv) const |
567 | 0 | { |
568 | 0 | if (aCallerType != CallerType::System) { |
569 | 0 | // If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h |
570 | 0 | // for details about spoofed values. |
571 | 0 | if (nsContentUtils::ShouldResistFingerprinting()) { |
572 | 0 | aBuildID.AssignLiteral(LEGACY_BUILD_ID); |
573 | 0 | return; |
574 | 0 | } |
575 | 0 | nsAutoString override; |
576 | 0 | nsresult rv = Preferences::GetString("general.buildID.override", override); |
577 | 0 | if (NS_SUCCEEDED(rv)) { |
578 | 0 | aBuildID = override; |
579 | 0 | return; |
580 | 0 | } |
581 | 0 | } |
582 | 0 | |
583 | 0 | nsCOMPtr<nsIXULAppInfo> appInfo = |
584 | 0 | do_GetService("@mozilla.org/xre/app-info;1"); |
585 | 0 | if (!appInfo) { |
586 | 0 | aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); |
587 | 0 | return; |
588 | 0 | } |
589 | 0 | |
590 | 0 | nsAutoCString buildID; |
591 | 0 | nsresult rv = appInfo->GetAppBuildID(buildID); |
592 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
593 | 0 | aRv.Throw(rv); |
594 | 0 | return; |
595 | 0 | } |
596 | 0 | |
597 | 0 | aBuildID.Truncate(); |
598 | 0 | AppendASCIItoUTF16(buildID, aBuildID); |
599 | 0 | } |
600 | | |
601 | | void |
602 | | Navigator::GetDoNotTrack(nsAString &aResult) |
603 | 0 | { |
604 | 0 | bool doNotTrack = nsContentUtils::DoNotTrackEnabled(); |
605 | 0 | if (!doNotTrack) { |
606 | 0 | nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow); |
607 | 0 | doNotTrack = loadContext && loadContext->UseTrackingProtection(); |
608 | 0 | } |
609 | 0 |
|
610 | 0 | if (doNotTrack) { |
611 | 0 | aResult.AssignLiteral("1"); |
612 | 0 | } else { |
613 | 0 | aResult.AssignLiteral("unspecified"); |
614 | 0 | } |
615 | 0 | } |
616 | | |
617 | | uint64_t |
618 | | Navigator::HardwareConcurrency() |
619 | 0 | { |
620 | 0 | workerinternals::RuntimeService* rts = |
621 | 0 | workerinternals::RuntimeService::GetOrCreateService(); |
622 | 0 | if (!rts) { |
623 | 0 | return 1; |
624 | 0 | } |
625 | 0 | |
626 | 0 | return rts->ClampedHardwareConcurrency(); |
627 | 0 | } |
628 | | |
629 | | void |
630 | | Navigator::RefreshMIMEArray() |
631 | 0 | { |
632 | 0 | if (mMimeTypes) { |
633 | 0 | mMimeTypes->Refresh(); |
634 | 0 | } |
635 | 0 | } |
636 | | |
637 | | namespace { |
638 | | |
639 | | class VibrateWindowListener : public nsIDOMEventListener |
640 | | { |
641 | | public: |
642 | | VibrateWindowListener(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument) |
643 | 0 | { |
644 | 0 | mWindow = do_GetWeakReference(aWindow); |
645 | 0 | mDocument = do_GetWeakReference(aDocument); |
646 | 0 |
|
647 | 0 | NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange"); |
648 | 0 | aDocument->AddSystemEventListener(visibilitychange, |
649 | 0 | this, /* listener */ |
650 | 0 | true, /* use capture */ |
651 | 0 | false /* wants untrusted */); |
652 | 0 | } |
653 | | |
654 | | void RemoveListener(); |
655 | | |
656 | | NS_DECL_ISUPPORTS |
657 | | NS_DECL_NSIDOMEVENTLISTENER |
658 | | |
659 | | private: |
660 | | virtual ~VibrateWindowListener() |
661 | 0 | { |
662 | 0 | } |
663 | | |
664 | | nsWeakPtr mWindow; |
665 | | nsWeakPtr mDocument; |
666 | | }; |
667 | | |
668 | | NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener) |
669 | | |
670 | | StaticRefPtr<VibrateWindowListener> gVibrateWindowListener; |
671 | | |
672 | | static bool |
673 | 0 | MayVibrate(nsIDocument* doc) { |
674 | 0 | // Hidden documents cannot start or stop a vibration. |
675 | 0 | return (doc && !doc->Hidden()); |
676 | 0 | } |
677 | | |
678 | | NS_IMETHODIMP |
679 | | VibrateWindowListener::HandleEvent(Event* aEvent) |
680 | 0 | { |
681 | 0 | nsCOMPtr<nsIDocument> doc = |
682 | 0 | do_QueryInterface(aEvent->GetTarget()); |
683 | 0 |
|
684 | 0 | if (!MayVibrate(doc)) { |
685 | 0 | // It's important that we call CancelVibrate(), not Vibrate() with an |
686 | 0 | // empty list, because Vibrate() will fail if we're no longer focused, but |
687 | 0 | // CancelVibrate() will succeed, so long as nobody else has started a new |
688 | 0 | // vibration pattern. |
689 | 0 | nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow); |
690 | 0 | hal::CancelVibrate(window); |
691 | 0 | RemoveListener(); |
692 | 0 | gVibrateWindowListener = nullptr; |
693 | 0 | // Careful: The line above might have deleted |this|! |
694 | 0 | } |
695 | 0 |
|
696 | 0 | return NS_OK; |
697 | 0 | } |
698 | | |
699 | | void |
700 | | VibrateWindowListener::RemoveListener() |
701 | 0 | { |
702 | 0 | nsCOMPtr<EventTarget> target = do_QueryReferent(mDocument); |
703 | 0 | if (!target) { |
704 | 0 | return; |
705 | 0 | } |
706 | 0 | NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange"); |
707 | 0 | target->RemoveSystemEventListener(visibilitychange, this, |
708 | 0 | true /* use capture */); |
709 | 0 | } |
710 | | |
711 | | } // namespace |
712 | | |
713 | | void |
714 | | Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv) |
715 | 0 | { |
716 | 0 | if (!mWindow) { |
717 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
718 | 0 | return; |
719 | 0 | } |
720 | 0 | if (NS_FAILED(mWindow->RegisterIdleObserver(aIdleObserver))) { |
721 | 0 | NS_WARNING("Failed to add idle observer."); |
722 | 0 | } |
723 | 0 | } |
724 | | |
725 | | void |
726 | | Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv) |
727 | 0 | { |
728 | 0 | if (!mWindow) { |
729 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
730 | 0 | return; |
731 | 0 | } |
732 | 0 | if (NS_FAILED(mWindow->UnregisterIdleObserver(aIdleObserver))) { |
733 | 0 | NS_WARNING("Failed to remove idle observer."); |
734 | 0 | } |
735 | 0 | } |
736 | | |
737 | | void |
738 | | Navigator::SetVibrationPermission(bool aPermitted, bool aPersistent) |
739 | 0 | { |
740 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
741 | 0 |
|
742 | 0 | nsTArray<uint32_t> pattern; |
743 | 0 | pattern.SwapElements(mRequestedVibrationPattern); |
744 | 0 |
|
745 | 0 | if (!mWindow) { |
746 | 0 | return; |
747 | 0 | } |
748 | 0 | |
749 | 0 | nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc(); |
750 | 0 |
|
751 | 0 | if (!MayVibrate(doc)) { |
752 | 0 | return; |
753 | 0 | } |
754 | 0 | |
755 | 0 | if (aPermitted) { |
756 | 0 | // Add a listener to cancel the vibration if the document becomes hidden, |
757 | 0 | // and remove the old visibility listener, if there was one. |
758 | 0 | if (!gVibrateWindowListener) { |
759 | 0 | // If gVibrateWindowListener is null, this is the first time we've vibrated, |
760 | 0 | // and we need to register a listener to clear gVibrateWindowListener on |
761 | 0 | // shutdown. |
762 | 0 | ClearOnShutdown(&gVibrateWindowListener); |
763 | 0 | } else { |
764 | 0 | gVibrateWindowListener->RemoveListener(); |
765 | 0 | } |
766 | 0 | gVibrateWindowListener = new VibrateWindowListener(mWindow, doc); |
767 | 0 | hal::Vibrate(pattern, mWindow); |
768 | 0 | } |
769 | 0 |
|
770 | 0 | if (aPersistent) { |
771 | 0 | nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager(); |
772 | 0 | if (!permMgr) { |
773 | 0 | return; |
774 | 0 | } |
775 | 0 | permMgr->AddFromPrincipal(doc->NodePrincipal(), kVibrationPermissionType, |
776 | 0 | aPermitted ? nsIPermissionManager::ALLOW_ACTION : |
777 | 0 | nsIPermissionManager::DENY_ACTION, |
778 | 0 | nsIPermissionManager::EXPIRE_SESSION, 0); |
779 | 0 | } |
780 | 0 | } |
781 | | |
782 | | bool |
783 | | Navigator::Vibrate(uint32_t aDuration) |
784 | 0 | { |
785 | 0 | AutoTArray<uint32_t, 1> pattern; |
786 | 0 | pattern.AppendElement(aDuration); |
787 | 0 | return Vibrate(pattern); |
788 | 0 | } |
789 | | |
790 | | bool |
791 | | Navigator::Vibrate(const nsTArray<uint32_t>& aPattern) |
792 | 0 | { |
793 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
794 | 0 |
|
795 | 0 | if (!mWindow) { |
796 | 0 | return false; |
797 | 0 | } |
798 | 0 | |
799 | 0 | nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc(); |
800 | 0 |
|
801 | 0 | if (!MayVibrate(doc)) { |
802 | 0 | return false; |
803 | 0 | } |
804 | 0 | |
805 | 0 | nsTArray<uint32_t> pattern(aPattern); |
806 | 0 |
|
807 | 0 | if (pattern.Length() > sMaxVibrateListLen) { |
808 | 0 | pattern.SetLength(sMaxVibrateListLen); |
809 | 0 | } |
810 | 0 |
|
811 | 0 | for (size_t i = 0; i < pattern.Length(); ++i) { |
812 | 0 | pattern[i] = std::min(sMaxVibrateMS, pattern[i]); |
813 | 0 | } |
814 | 0 |
|
815 | 0 | // The spec says we check sVibratorEnabled after we've done the sanity |
816 | 0 | // checking on the pattern. |
817 | 0 | if (!sVibratorEnabled) { |
818 | 0 | return true; |
819 | 0 | } |
820 | 0 | |
821 | 0 | mRequestedVibrationPattern.SwapElements(pattern); |
822 | 0 | nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager(); |
823 | 0 | if (!permMgr) { |
824 | 0 | return false; |
825 | 0 | } |
826 | 0 | |
827 | 0 | uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION; |
828 | 0 |
|
829 | 0 | permMgr->TestPermissionFromPrincipal(doc->NodePrincipal(), kVibrationPermissionType, |
830 | 0 | &permission); |
831 | 0 |
|
832 | 0 | if (permission == nsIPermissionManager::ALLOW_ACTION || |
833 | 0 | mRequestedVibrationPattern.IsEmpty() || |
834 | 0 | (mRequestedVibrationPattern.Length() == 1 && |
835 | 0 | mRequestedVibrationPattern[0] == 0)) { |
836 | 0 | // Always allow cancelling vibration and respect session permissions. |
837 | 0 | SetVibrationPermission(true /* permitted */, false /* persistent */); |
838 | 0 | return true; |
839 | 0 | } |
840 | 0 | |
841 | 0 | nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
842 | 0 | if (!obs || permission == nsIPermissionManager::DENY_ACTION) { |
843 | 0 | // Abort without observer service or on denied session permission. |
844 | 0 | SetVibrationPermission(false /* permitted */, false /* persistent */); |
845 | 0 | return true; |
846 | 0 | } |
847 | 0 | |
848 | 0 | // Request user permission. |
849 | 0 | obs->NotifyObservers(ToSupports(this), "Vibration:Request", nullptr); |
850 | 0 |
|
851 | 0 | return true; |
852 | 0 | } |
853 | | |
854 | | //***************************************************************************** |
855 | | // Pointer Events interface |
856 | | //***************************************************************************** |
857 | | |
858 | | uint32_t |
859 | | Navigator::MaxTouchPoints() |
860 | 0 | { |
861 | 0 | nsCOMPtr<nsIWidget> widget = widget::WidgetUtils::DOMWindowToWidget(mWindow->GetOuterWindow()); |
862 | 0 |
|
863 | 0 | NS_ENSURE_TRUE(widget, 0); |
864 | 0 | return widget->GetMaxTouchPoints(); |
865 | 0 | } |
866 | | |
867 | | //***************************************************************************** |
868 | | // Navigator::nsIDOMClientInformation |
869 | | //***************************************************************************** |
870 | | |
871 | | void |
872 | | Navigator::RegisterContentHandler(const nsAString& aMIMEType, |
873 | | const nsAString& aURI, |
874 | | const nsAString& aTitle, |
875 | | ErrorResult& aRv) |
876 | 0 | { |
877 | 0 | } |
878 | | |
879 | | void |
880 | | Navigator::RegisterProtocolHandler(const nsAString& aProtocol, |
881 | | const nsAString& aURI, |
882 | | const nsAString& aTitle, |
883 | | ErrorResult& aRv) |
884 | 0 | { |
885 | 0 | if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) { |
886 | 0 | return; |
887 | 0 | } |
888 | 0 | |
889 | 0 | if (!mWindow->IsSecureContext() && mWindow->GetDoc()) { |
890 | 0 | mWindow->GetDoc()->WarnOnceAbout(nsIDocument::eRegisterProtocolHandlerInsecure); |
891 | 0 | } |
892 | 0 |
|
893 | 0 | nsCOMPtr<nsIWebContentHandlerRegistrar> registrar = |
894 | 0 | do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID); |
895 | 0 | if (!registrar) { |
896 | 0 | return; |
897 | 0 | } |
898 | 0 | |
899 | 0 | aRv = registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle, |
900 | 0 | mWindow->GetOuterWindow()); |
901 | 0 | } |
902 | | |
903 | | Geolocation* |
904 | | Navigator::GetGeolocation(ErrorResult& aRv) |
905 | 0 | { |
906 | 0 | if (mGeolocation) { |
907 | 0 | return mGeolocation; |
908 | 0 | } |
909 | 0 | |
910 | 0 | if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) { |
911 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
912 | 0 | return nullptr; |
913 | 0 | } |
914 | 0 | |
915 | 0 | mGeolocation = new Geolocation(); |
916 | 0 | if (NS_FAILED(mGeolocation->Init(mWindow))) { |
917 | 0 | mGeolocation = nullptr; |
918 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
919 | 0 | return nullptr; |
920 | 0 | } |
921 | 0 | |
922 | 0 | return mGeolocation; |
923 | 0 | } |
924 | | |
925 | | class BeaconStreamListener final : public nsIStreamListener |
926 | | { |
927 | 0 | ~BeaconStreamListener() {} |
928 | | |
929 | | public: |
930 | 0 | BeaconStreamListener() : mLoadGroup(nullptr) {} |
931 | | |
932 | 0 | void SetLoadGroup(nsILoadGroup* aLoadGroup) { |
933 | 0 | mLoadGroup = aLoadGroup; |
934 | 0 | } |
935 | | |
936 | | NS_DECL_ISUPPORTS |
937 | | NS_DECL_NSISTREAMLISTENER |
938 | | NS_DECL_NSIREQUESTOBSERVER |
939 | | |
940 | | private: |
941 | | nsCOMPtr<nsILoadGroup> mLoadGroup; |
942 | | |
943 | | }; |
944 | | |
945 | | NS_IMPL_ISUPPORTS(BeaconStreamListener, |
946 | | nsIStreamListener, |
947 | | nsIRequestObserver) |
948 | | |
949 | | NS_IMETHODIMP |
950 | | BeaconStreamListener::OnStartRequest(nsIRequest *aRequest, |
951 | | nsISupports *aContext) |
952 | 0 | { |
953 | 0 | // release the loadgroup first |
954 | 0 | mLoadGroup = nullptr; |
955 | 0 |
|
956 | 0 | aRequest->Cancel(NS_ERROR_NET_INTERRUPT); |
957 | 0 | return NS_BINDING_ABORTED; |
958 | 0 | } |
959 | | |
960 | | NS_IMETHODIMP |
961 | | BeaconStreamListener::OnStopRequest(nsIRequest *aRequest, |
962 | | nsISupports *aContext, |
963 | | nsresult aStatus) |
964 | 0 | { |
965 | 0 | return NS_OK; |
966 | 0 | } |
967 | | |
968 | | NS_IMETHODIMP |
969 | | BeaconStreamListener::OnDataAvailable(nsIRequest *aRequest, |
970 | | nsISupports *ctxt, |
971 | | nsIInputStream *inStr, |
972 | | uint64_t sourceOffset, |
973 | | uint32_t count) |
974 | 0 | { |
975 | 0 | MOZ_ASSERT(false); |
976 | 0 | return NS_OK; |
977 | 0 | } |
978 | | |
979 | | bool |
980 | | Navigator::SendBeacon(const nsAString& aUrl, |
981 | | const Nullable<fetch::BodyInit>& aData, |
982 | | ErrorResult& aRv) |
983 | 0 | { |
984 | 0 | if (aData.IsNull()) { |
985 | 0 | return SendBeaconInternal(aUrl, nullptr, eBeaconTypeOther, aRv); |
986 | 0 | } |
987 | 0 | |
988 | 0 | if (aData.Value().IsArrayBuffer()) { |
989 | 0 | BodyExtractor<const ArrayBuffer> body(&aData.Value().GetAsArrayBuffer()); |
990 | 0 | return SendBeaconInternal(aUrl, &body, eBeaconTypeArrayBuffer, aRv); |
991 | 0 | } |
992 | 0 | |
993 | 0 | if (aData.Value().IsArrayBufferView()) { |
994 | 0 | BodyExtractor<const ArrayBufferView> body(&aData.Value().GetAsArrayBufferView()); |
995 | 0 | return SendBeaconInternal(aUrl, &body, eBeaconTypeArrayBuffer, aRv); |
996 | 0 | } |
997 | 0 | |
998 | 0 | if (aData.Value().IsBlob()) { |
999 | 0 | BodyExtractor<const Blob> body(&aData.Value().GetAsBlob()); |
1000 | 0 | return SendBeaconInternal(aUrl, &body, eBeaconTypeBlob, aRv); |
1001 | 0 | } |
1002 | 0 | |
1003 | 0 | if (aData.Value().IsFormData()) { |
1004 | 0 | BodyExtractor<const FormData> body(&aData.Value().GetAsFormData()); |
1005 | 0 | return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv); |
1006 | 0 | } |
1007 | 0 | |
1008 | 0 | if (aData.Value().IsUSVString()) { |
1009 | 0 | BodyExtractor<const nsAString> body(&aData.Value().GetAsUSVString()); |
1010 | 0 | return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv); |
1011 | 0 | } |
1012 | 0 | |
1013 | 0 | if (aData.Value().IsURLSearchParams()) { |
1014 | 0 | BodyExtractor<const URLSearchParams> body(&aData.Value().GetAsURLSearchParams()); |
1015 | 0 | return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv); |
1016 | 0 | } |
1017 | 0 | |
1018 | 0 | MOZ_CRASH("Invalid data type."); |
1019 | 0 | return false; |
1020 | 0 | } |
1021 | | |
1022 | | bool |
1023 | | Navigator::SendBeaconInternal(const nsAString& aUrl, |
1024 | | BodyExtractorBase* aBody, |
1025 | | BeaconType aType, |
1026 | | ErrorResult& aRv) |
1027 | 0 | { |
1028 | 0 | if (!mWindow) { |
1029 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); |
1030 | 0 | return false; |
1031 | 0 | } |
1032 | 0 | |
1033 | 0 | nsCOMPtr<nsIDocument> doc = mWindow->GetDoc(); |
1034 | 0 | if (!doc) { |
1035 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); |
1036 | 0 | return false; |
1037 | 0 | } |
1038 | 0 | |
1039 | 0 | nsIURI* documentURI = doc->GetDocumentURI(); |
1040 | 0 | if (!documentURI) { |
1041 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); |
1042 | 0 | return false; |
1043 | 0 | } |
1044 | 0 | |
1045 | 0 | nsCOMPtr<nsIURI> uri; |
1046 | 0 | nsresult rv = nsContentUtils::NewURIWithDocumentCharset( |
1047 | 0 | getter_AddRefs(uri), |
1048 | 0 | aUrl, |
1049 | 0 | doc, |
1050 | 0 | doc->GetDocBaseURI()); |
1051 | 0 | if (NS_FAILED(rv)) { |
1052 | 0 | aRv.ThrowTypeError<MSG_INVALID_URL>(aUrl); |
1053 | 0 | return false; |
1054 | 0 | } |
1055 | 0 | |
1056 | 0 | // Spec disallows any schemes save for HTTP/HTTPs |
1057 | 0 | bool isValidScheme; |
1058 | 0 | if (!(NS_SUCCEEDED(uri->SchemeIs("http", &isValidScheme)) && isValidScheme) && |
1059 | 0 | !(NS_SUCCEEDED(uri->SchemeIs("https", &isValidScheme)) && isValidScheme)) { |
1060 | 0 | aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>( NS_LITERAL_STRING("Beacon"), aUrl); |
1061 | 0 | return false; |
1062 | 0 | } |
1063 | 0 |
|
1064 | 0 | nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL | |
1065 | 0 | nsIChannel::LOAD_CLASSIFY_URI; |
1066 | 0 |
|
1067 | 0 | // No need to use CORS for sendBeacon unless it's a BLOB |
1068 | 0 | nsSecurityFlags securityFlags = aType == eBeaconTypeBlob |
1069 | 0 | ? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS |
1070 | 0 | : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS; |
1071 | 0 | securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE; |
1072 | 0 |
|
1073 | 0 | nsCOMPtr<nsIChannel> channel; |
1074 | 0 | rv = NS_NewChannel(getter_AddRefs(channel), |
1075 | 0 | uri, |
1076 | 0 | doc, |
1077 | 0 | securityFlags, |
1078 | 0 | nsIContentPolicy::TYPE_BEACON, |
1079 | 0 | nullptr, // aPerformanceStorage |
1080 | 0 | nullptr, // aLoadGroup |
1081 | 0 | nullptr, // aCallbacks |
1082 | 0 | loadFlags); |
1083 | 0 |
|
1084 | 0 | if (NS_FAILED(rv)) { |
1085 | 0 | aRv.Throw(rv); |
1086 | 0 | return false; |
1087 | 0 | } |
1088 | 0 | |
1089 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel); |
1090 | 0 | if (!httpChannel) { |
1091 | 0 | // Beacon spec only supports HTTP requests at this time |
1092 | 0 | aRv.Throw(NS_ERROR_DOM_BAD_URI); |
1093 | 0 | return false; |
1094 | 0 | } |
1095 | 0 | mozilla::net::ReferrerPolicy referrerPolicy = doc->GetReferrerPolicy(); |
1096 | 0 | rv = httpChannel->SetReferrerWithPolicy(documentURI, referrerPolicy); |
1097 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
1098 | 0 |
|
1099 | 0 | nsCOMPtr<nsIInputStream> in; |
1100 | 0 | nsAutoCString contentTypeWithCharset; |
1101 | 0 | nsAutoCString charset; |
1102 | 0 | uint64_t length = 0; |
1103 | 0 |
|
1104 | 0 | if (aBody) { |
1105 | 0 | aRv = aBody->GetAsStream(getter_AddRefs(in), &length, |
1106 | 0 | contentTypeWithCharset, charset); |
1107 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
1108 | 0 | return false; |
1109 | 0 | } |
1110 | 0 | |
1111 | 0 | nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel); |
1112 | 0 | if (!uploadChannel) { |
1113 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
1114 | 0 | return false; |
1115 | 0 | } |
1116 | 0 | |
1117 | 0 | uploadChannel->ExplicitSetUploadStream(in, contentTypeWithCharset, length, |
1118 | 0 | NS_LITERAL_CSTRING("POST"), |
1119 | 0 | false); |
1120 | 0 | } else { |
1121 | 0 | rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST")); |
1122 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
1123 | 0 | } |
1124 | 0 |
|
1125 | 0 | nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel); |
1126 | 0 | if (p) { |
1127 | 0 | p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST); |
1128 | 0 | } |
1129 | 0 |
|
1130 | 0 | nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel)); |
1131 | 0 | if (cos) { |
1132 | 0 | cos->AddClassFlags(nsIClassOfService::Background); |
1133 | 0 | } |
1134 | 0 |
|
1135 | 0 | // The channel needs to have a loadgroup associated with it, so that we can |
1136 | 0 | // cancel the channel and any redirected channels it may create. |
1137 | 0 | nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID); |
1138 | 0 | nsCOMPtr<nsIInterfaceRequestor> callbacks = |
1139 | 0 | do_QueryInterface(mWindow->GetDocShell()); |
1140 | 0 | loadGroup->SetNotificationCallbacks(callbacks); |
1141 | 0 | channel->SetLoadGroup(loadGroup); |
1142 | 0 |
|
1143 | 0 | RefPtr<BeaconStreamListener> beaconListener = new BeaconStreamListener(); |
1144 | 0 | rv = channel->AsyncOpen2(beaconListener); |
1145 | 0 | // do not throw if security checks fail within asyncOpen2 |
1146 | 0 | NS_ENSURE_SUCCESS(rv, false); |
1147 | 0 |
|
1148 | 0 | // make the beaconListener hold a strong reference to the loadgroup |
1149 | 0 | // which is released in ::OnStartRequest |
1150 | 0 | beaconListener->SetLoadGroup(loadGroup); |
1151 | 0 |
|
1152 | 0 | return true; |
1153 | 0 | } |
1154 | | |
1155 | | MediaDevices* |
1156 | | Navigator::GetMediaDevices(ErrorResult& aRv) |
1157 | 0 | { |
1158 | 0 | if (!mMediaDevices) { |
1159 | 0 | if (!mWindow || |
1160 | 0 | !mWindow->GetOuterWindow() || |
1161 | 0 | mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) { |
1162 | 0 | aRv.Throw(NS_ERROR_NOT_AVAILABLE); |
1163 | 0 | return nullptr; |
1164 | 0 | } |
1165 | 0 | mMediaDevices = new MediaDevices(mWindow); |
1166 | 0 | } |
1167 | 0 | return mMediaDevices; |
1168 | 0 | } |
1169 | | |
1170 | | void |
1171 | | Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints, |
1172 | | NavigatorUserMediaSuccessCallback& aOnSuccess, |
1173 | | NavigatorUserMediaErrorCallback& aOnError, |
1174 | | CallerType aCallerType, |
1175 | | ErrorResult& aRv) |
1176 | 0 | { |
1177 | 0 | if (!mWindow || !mWindow->GetOuterWindow() || |
1178 | 0 | mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) { |
1179 | 0 | aRv.Throw(NS_ERROR_NOT_AVAILABLE); |
1180 | 0 | return; |
1181 | 0 | } |
1182 | 0 | |
1183 | 0 | MediaManager::GetUserMediaSuccessCallback onsuccess(&aOnSuccess); |
1184 | 0 | MediaManager::GetUserMediaErrorCallback onerror(&aOnError); |
1185 | 0 |
|
1186 | 0 | MediaManager* manager = MediaManager::Get(); |
1187 | 0 | aRv = manager->GetUserMedia(mWindow, aConstraints, std::move(onsuccess), |
1188 | 0 | std::move(onerror), aCallerType); |
1189 | 0 | } |
1190 | | |
1191 | | void |
1192 | | Navigator::MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints, |
1193 | | MozGetUserMediaDevicesSuccessCallback& aOnSuccess, |
1194 | | NavigatorUserMediaErrorCallback& aOnError, |
1195 | | uint64_t aInnerWindowID, |
1196 | | const nsAString& aCallID, |
1197 | | ErrorResult& aRv) |
1198 | 0 | { |
1199 | 0 | if (!mWindow || !mWindow->GetOuterWindow() || |
1200 | 0 | mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) { |
1201 | 0 | aRv.Throw(NS_ERROR_NOT_AVAILABLE); |
1202 | 0 | return; |
1203 | 0 | } |
1204 | 0 | |
1205 | 0 | MediaManager* manager = MediaManager::Get(); |
1206 | 0 | // XXXbz aOnError seems to be unused? |
1207 | 0 | aRv = manager->GetUserMediaDevices(mWindow, aConstraints, aOnSuccess, |
1208 | 0 | aInnerWindowID, aCallID); |
1209 | 0 | } |
1210 | | |
1211 | | //***************************************************************************** |
1212 | | // Navigator::nsINavigatorBattery |
1213 | | //***************************************************************************** |
1214 | | |
1215 | | Promise* |
1216 | | Navigator::GetBattery(ErrorResult& aRv) |
1217 | 0 | { |
1218 | 0 | if (mBatteryPromise) { |
1219 | 0 | return mBatteryPromise; |
1220 | 0 | } |
1221 | 0 | |
1222 | 0 | if (!mWindow || !mWindow->GetDocShell()) { |
1223 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
1224 | 0 | return nullptr; |
1225 | 0 | } |
1226 | 0 | |
1227 | 0 | RefPtr<Promise> batteryPromise = Promise::Create(mWindow->AsGlobal(), aRv); |
1228 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
1229 | 0 | return nullptr; |
1230 | 0 | } |
1231 | 0 | mBatteryPromise = batteryPromise; |
1232 | 0 |
|
1233 | 0 | if (!mBatteryManager) { |
1234 | 0 | mBatteryManager = new battery::BatteryManager(mWindow); |
1235 | 0 | mBatteryManager->Init(); |
1236 | 0 | } |
1237 | 0 |
|
1238 | 0 | mBatteryPromise->MaybeResolve(mBatteryManager); |
1239 | 0 |
|
1240 | 0 | return mBatteryPromise; |
1241 | 0 | } |
1242 | | |
1243 | | already_AddRefed<LegacyMozTCPSocket> |
1244 | | Navigator::MozTCPSocket() |
1245 | 0 | { |
1246 | 0 | RefPtr<LegacyMozTCPSocket> socket = new LegacyMozTCPSocket(GetWindow()); |
1247 | 0 | return socket.forget(); |
1248 | 0 | } |
1249 | | |
1250 | | void |
1251 | | Navigator::GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads, |
1252 | | ErrorResult& aRv) |
1253 | 0 | { |
1254 | 0 | if (!mWindow) { |
1255 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
1256 | 0 | return; |
1257 | 0 | } |
1258 | 0 | NS_ENSURE_TRUE_VOID(mWindow->GetDocShell()); |
1259 | 0 | nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow); |
1260 | 0 | win->SetHasGamepadEventListener(true); |
1261 | 0 | win->GetGamepads(aGamepads); |
1262 | 0 | } |
1263 | | |
1264 | | GamepadServiceTest* |
1265 | | Navigator::RequestGamepadServiceTest() |
1266 | 0 | { |
1267 | 0 | if (!mGamepadServiceTest) { |
1268 | 0 | mGamepadServiceTest = GamepadServiceTest::CreateTestService(mWindow); |
1269 | 0 | } |
1270 | 0 | return mGamepadServiceTest; |
1271 | 0 | } |
1272 | | |
1273 | | already_AddRefed<Promise> |
1274 | | Navigator::GetVRDisplays(ErrorResult& aRv) |
1275 | 0 | { |
1276 | 0 | if (!mWindow || !mWindow->GetDocShell()) { |
1277 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
1278 | 0 | return nullptr; |
1279 | 0 | } |
1280 | 0 | |
1281 | 0 | nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow); |
1282 | 0 | win->NotifyVREventListenerAdded(); |
1283 | 0 |
|
1284 | 0 | RefPtr<Promise> p = Promise::Create(mWindow->AsGlobal(), aRv); |
1285 | 0 | if (aRv.Failed()) { |
1286 | 0 | return nullptr; |
1287 | 0 | } |
1288 | 0 | |
1289 | 0 | // We pass mWindow's id to RefreshVRDisplays, so NotifyVRDisplaysUpdated will |
1290 | 0 | // be called asynchronously, resolving the promises in mVRGetDisplaysPromises. |
1291 | 0 | if (!VRDisplay::RefreshVRDisplays(win->WindowID())) { |
1292 | 0 | p->MaybeReject(NS_ERROR_FAILURE); |
1293 | 0 | return p.forget(); |
1294 | 0 | } |
1295 | 0 | |
1296 | 0 | mVRGetDisplaysPromises.AppendElement(p); |
1297 | 0 | return p.forget(); |
1298 | 0 | } |
1299 | | |
1300 | | void |
1301 | | Navigator::GetActiveVRDisplays(nsTArray<RefPtr<VRDisplay>>& aDisplays) const |
1302 | 0 | { |
1303 | 0 | /** |
1304 | 0 | * Get only the active VR displays. |
1305 | 0 | * GetActiveVRDisplays should only enumerate displays that |
1306 | 0 | * are already active without causing any other hardware to be |
1307 | 0 | * activated. |
1308 | 0 | * We must not call nsGlobalWindow::NotifyVREventListenerAdded here, |
1309 | 0 | * as that would cause enumeration and activation of other VR hardware. |
1310 | 0 | * Activating VR hardware is intrusive to the end user, as it may |
1311 | 0 | * involve physically powering on devices that the user did not |
1312 | 0 | * intend to use. |
1313 | 0 | */ |
1314 | 0 | if (!mWindow || !mWindow->GetDocShell()) { |
1315 | 0 | return; |
1316 | 0 | } |
1317 | 0 | nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow); |
1318 | 0 | nsTArray<RefPtr<VRDisplay>> displays; |
1319 | 0 | if (win->UpdateVRDisplays(displays)) { |
1320 | 0 | for (auto display : displays) { |
1321 | 0 | if (display->IsPresenting()) { |
1322 | 0 | aDisplays.AppendElement(display); |
1323 | 0 | } |
1324 | 0 | } |
1325 | 0 | } |
1326 | 0 | } |
1327 | | |
1328 | | void |
1329 | | Navigator::NotifyVRDisplaysUpdated() |
1330 | 0 | { |
1331 | 0 | // Synchronize the VR devices and resolve the promises in |
1332 | 0 | // mVRGetDisplaysPromises |
1333 | 0 | nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow); |
1334 | 0 |
|
1335 | 0 | nsTArray<RefPtr<VRDisplay>> vrDisplays; |
1336 | 0 | if (win->UpdateVRDisplays(vrDisplays)) { |
1337 | 0 | for (auto p : mVRGetDisplaysPromises) { |
1338 | 0 | p->MaybeResolve(vrDisplays); |
1339 | 0 | } |
1340 | 0 | } else { |
1341 | 0 | for (auto p : mVRGetDisplaysPromises) { |
1342 | 0 | p->MaybeReject(NS_ERROR_FAILURE); |
1343 | 0 | } |
1344 | 0 | } |
1345 | 0 | mVRGetDisplaysPromises.Clear(); |
1346 | 0 | } |
1347 | | |
1348 | | void |
1349 | | Navigator::NotifyActiveVRDisplaysChanged() |
1350 | 0 | { |
1351 | 0 | Navigator_Binding::ClearCachedActiveVRDisplaysValue(this); |
1352 | 0 | } |
1353 | | |
1354 | | VRServiceTest* |
1355 | | Navigator::RequestVRServiceTest() |
1356 | 0 | { |
1357 | 0 | // Ensure that the Mock VR devices are not released prematurely |
1358 | 0 | nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow); |
1359 | 0 | win->NotifyVREventListenerAdded(); |
1360 | 0 |
|
1361 | 0 | if (!mVRServiceTest) { |
1362 | 0 | mVRServiceTest = VRServiceTest::CreateTestService(mWindow); |
1363 | 0 | } |
1364 | 0 | return mVRServiceTest; |
1365 | 0 | } |
1366 | | |
1367 | | bool |
1368 | | Navigator::IsWebVRContentDetected() const |
1369 | 0 | { |
1370 | 0 | nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow); |
1371 | 0 | return win->IsVRContentDetected(); |
1372 | 0 | } |
1373 | | |
1374 | | bool |
1375 | | Navigator::IsWebVRContentPresenting() const |
1376 | 0 | { |
1377 | 0 | nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow); |
1378 | 0 | return win->IsVRContentPresenting(); |
1379 | 0 | } |
1380 | | |
1381 | | void |
1382 | | Navigator::RequestVRPresentation(VRDisplay& aDisplay) |
1383 | 0 | { |
1384 | 0 | nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(mWindow); |
1385 | 0 | win->DispatchVRDisplayActivate(aDisplay.DisplayId(), VRDisplayEventReason::Requested); |
1386 | 0 | } |
1387 | | |
1388 | | already_AddRefed<Promise> |
1389 | | Navigator::RequestMIDIAccess(const MIDIOptions& aOptions, |
1390 | | ErrorResult& aRv) |
1391 | 0 | { |
1392 | 0 | if (!mWindow) { |
1393 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
1394 | 0 | return nullptr; |
1395 | 0 | } |
1396 | 0 | MIDIAccessManager* accessMgr = MIDIAccessManager::Get(); |
1397 | 0 | return accessMgr->RequestMIDIAccess(mWindow, aOptions, aRv); |
1398 | 0 | } |
1399 | | |
1400 | | nsINetworkProperties* |
1401 | | Navigator::GetNetworkProperties() |
1402 | 0 | { |
1403 | 0 | return GetConnection(IgnoreErrors()); |
1404 | 0 | } |
1405 | | |
1406 | | network::Connection* |
1407 | | Navigator::GetConnection(ErrorResult& aRv) |
1408 | 0 | { |
1409 | 0 | if (!mConnection) { |
1410 | 0 | if (!mWindow) { |
1411 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
1412 | 0 | return nullptr; |
1413 | 0 | } |
1414 | 0 | mConnection = network::Connection::CreateForWindow(mWindow); |
1415 | 0 | } |
1416 | 0 |
|
1417 | 0 | return mConnection; |
1418 | 0 | } |
1419 | | |
1420 | | already_AddRefed<ServiceWorkerContainer> |
1421 | | Navigator::ServiceWorker() |
1422 | 0 | { |
1423 | 0 | MOZ_ASSERT(mWindow); |
1424 | 0 |
|
1425 | 0 | if (!mServiceWorkerContainer) { |
1426 | 0 | mServiceWorkerContainer = ServiceWorkerContainer::Create(mWindow->AsGlobal()); |
1427 | 0 | } |
1428 | 0 |
|
1429 | 0 | RefPtr<ServiceWorkerContainer> ref = mServiceWorkerContainer; |
1430 | 0 | return ref.forget(); |
1431 | 0 | } |
1432 | | |
1433 | | size_t |
1434 | | Navigator::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const |
1435 | 0 | { |
1436 | 0 | size_t n = aMallocSizeOf(this); |
1437 | 0 |
|
1438 | 0 | // TODO: add SizeOfIncludingThis() to nsMimeTypeArray, bug 674113. |
1439 | 0 | // TODO: add SizeOfIncludingThis() to nsPluginArray, bug 674114. |
1440 | 0 | // TODO: add SizeOfIncludingThis() to Geolocation, bug 674115. |
1441 | 0 | // TODO: add SizeOfIncludingThis() to DesktopNotificationCenter, bug 674116. |
1442 | 0 |
|
1443 | 0 | return n; |
1444 | 0 | } |
1445 | | |
1446 | | void |
1447 | | Navigator::SetWindow(nsPIDOMWindowInner *aInnerWindow) |
1448 | 0 | { |
1449 | 0 | mWindow = aInnerWindow; |
1450 | 0 | } |
1451 | | |
1452 | | void |
1453 | | Navigator::OnNavigation() |
1454 | 0 | { |
1455 | 0 | if (!mWindow) { |
1456 | 0 | return; |
1457 | 0 | } |
1458 | 0 | |
1459 | 0 | // If MediaManager is open let it inform any live streams or pending callbacks |
1460 | 0 | MediaManager *manager = MediaManager::GetIfExists(); |
1461 | 0 | if (manager) { |
1462 | 0 | manager->OnNavigation(mWindow->WindowID()); |
1463 | 0 | } |
1464 | 0 | } |
1465 | | |
1466 | | JSObject* |
1467 | | Navigator::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) |
1468 | 0 | { |
1469 | 0 | return Navigator_Binding::Wrap(cx, this, aGivenProto); |
1470 | 0 | } |
1471 | | |
1472 | | /* static */ |
1473 | | bool |
1474 | | Navigator::HasUserMediaSupport(JSContext* /* unused */, |
1475 | | JSObject* /* unused */) |
1476 | 0 | { |
1477 | 0 | // Make enabling peerconnection enable getUserMedia() as well |
1478 | 0 | return Preferences::GetBool("media.navigator.enabled", false) || |
1479 | 0 | Preferences::GetBool("media.peerconnection.enabled", false); |
1480 | 0 | } |
1481 | | |
1482 | | /* static */ |
1483 | | already_AddRefed<nsPIDOMWindowInner> |
1484 | | Navigator::GetWindowFromGlobal(JSObject* aGlobal) |
1485 | 0 | { |
1486 | 0 | nsCOMPtr<nsPIDOMWindowInner> win = xpc::WindowOrNull(aGlobal); |
1487 | 0 | return win.forget(); |
1488 | 0 | } |
1489 | | |
1490 | | nsresult |
1491 | | Navigator::GetPlatform(nsAString& aPlatform, bool aUsePrefOverriddenValue) |
1492 | 0 | { |
1493 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1494 | 0 |
|
1495 | 0 | if (aUsePrefOverriddenValue) { |
1496 | 0 | // If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h |
1497 | 0 | // for details about spoofed values. |
1498 | 0 | if (nsContentUtils::ShouldResistFingerprinting()) { |
1499 | 0 | aPlatform.AssignLiteral(SPOOFED_PLATFORM); |
1500 | 0 | return NS_OK; |
1501 | 0 | } |
1502 | 0 | nsAutoString override; |
1503 | 0 | nsresult rv = |
1504 | 0 | mozilla::Preferences::GetString("general.platform.override", override); |
1505 | 0 |
|
1506 | 0 | if (NS_SUCCEEDED(rv)) { |
1507 | 0 | aPlatform = override; |
1508 | 0 | return NS_OK; |
1509 | 0 | } |
1510 | 0 | } |
1511 | 0 | |
1512 | 0 | nsresult rv; |
1513 | 0 |
|
1514 | 0 | nsCOMPtr<nsIHttpProtocolHandler> |
1515 | 0 | service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); |
1516 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1517 | 0 |
|
1518 | 0 | // Sorry for the #if platform ugliness, but Communicator is likewise |
1519 | 0 | // hardcoded and we are seeking backward compatibility here (bug 47080). |
1520 | | #if defined(WIN32) |
1521 | | aPlatform.AssignLiteral("Win32"); |
1522 | | #elif defined(XP_MACOSX) && defined(__ppc__) |
1523 | | aPlatform.AssignLiteral("MacPPC"); |
1524 | | #elif defined(XP_MACOSX) && defined(__i386__) |
1525 | | aPlatform.AssignLiteral("MacIntel"); |
1526 | | #elif defined(XP_MACOSX) && defined(__x86_64__) |
1527 | | aPlatform.AssignLiteral("MacIntel"); |
1528 | | #else |
1529 | | // XXX Communicator uses compiled-in build-time string defines |
1530 | 0 | // to indicate the platform it was compiled *for*, not what it is |
1531 | 0 | // currently running *on* which is what this does. |
1532 | 0 | nsAutoCString plat; |
1533 | 0 | rv = service->GetOscpu(plat); |
1534 | 0 | CopyASCIItoUTF16(plat, aPlatform); |
1535 | 0 | #endif |
1536 | 0 |
|
1537 | 0 | return rv; |
1538 | 0 | } |
1539 | | |
1540 | | /* static */ nsresult |
1541 | | Navigator::GetAppVersion(nsAString& aAppVersion, bool aUsePrefOverriddenValue) |
1542 | 0 | { |
1543 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1544 | 0 |
|
1545 | 0 | if (aUsePrefOverriddenValue) { |
1546 | 0 | // If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h |
1547 | 0 | // for details about spoofed values. |
1548 | 0 | if (nsContentUtils::ShouldResistFingerprinting()) { |
1549 | 0 | aAppVersion.AssignLiteral(SPOOFED_APPVERSION); |
1550 | 0 | return NS_OK; |
1551 | 0 | } |
1552 | 0 | nsAutoString override; |
1553 | 0 | nsresult rv = |
1554 | 0 | mozilla::Preferences::GetString("general.appversion.override", override); |
1555 | 0 |
|
1556 | 0 | if (NS_SUCCEEDED(rv)) { |
1557 | 0 | aAppVersion = override; |
1558 | 0 | return NS_OK; |
1559 | 0 | } |
1560 | 0 | } |
1561 | 0 | |
1562 | 0 | nsresult rv; |
1563 | 0 |
|
1564 | 0 | nsCOMPtr<nsIHttpProtocolHandler> |
1565 | 0 | service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); |
1566 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1567 | 0 |
|
1568 | 0 | nsAutoCString str; |
1569 | 0 | rv = service->GetAppVersion(str); |
1570 | 0 | CopyASCIItoUTF16(str, aAppVersion); |
1571 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1572 | 0 |
|
1573 | 0 | aAppVersion.AppendLiteral(" ("); |
1574 | 0 |
|
1575 | 0 | rv = service->GetPlatform(str); |
1576 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1577 | 0 |
|
1578 | 0 | AppendASCIItoUTF16(str, aAppVersion); |
1579 | 0 | aAppVersion.Append(char16_t(')')); |
1580 | 0 |
|
1581 | 0 | return rv; |
1582 | 0 | } |
1583 | | |
1584 | | /* static */ void |
1585 | | Navigator::AppName(nsAString& aAppName, bool aUsePrefOverriddenValue) |
1586 | 0 | { |
1587 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1588 | 0 |
|
1589 | 0 | if (aUsePrefOverriddenValue) { |
1590 | 0 | // If fingerprinting resistance is on, we will spoof this value. See nsRFPService.h |
1591 | 0 | // for details about spoofed values. |
1592 | 0 | if (nsContentUtils::ShouldResistFingerprinting()) { |
1593 | 0 | aAppName.AssignLiteral(SPOOFED_APPNAME); |
1594 | 0 | return; |
1595 | 0 | } |
1596 | 0 |
|
1597 | 0 | nsAutoString override; |
1598 | 0 | nsresult rv = |
1599 | 0 | mozilla::Preferences::GetString("general.appname.override", override); |
1600 | 0 |
|
1601 | 0 | if (NS_SUCCEEDED(rv)) { |
1602 | 0 | aAppName = override; |
1603 | 0 | return; |
1604 | 0 | } |
1605 | 0 | } |
1606 | 0 | |
1607 | 0 | aAppName.AssignLiteral("Netscape"); |
1608 | 0 | } |
1609 | | |
1610 | | void |
1611 | | Navigator::ClearUserAgentCache() |
1612 | 0 | { |
1613 | 0 | Navigator_Binding::ClearCachedUserAgentValue(this); |
1614 | 0 | } |
1615 | | |
1616 | | nsresult |
1617 | | Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow, |
1618 | | bool aIsCallerChrome, |
1619 | | nsAString& aUserAgent) |
1620 | 0 | { |
1621 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1622 | 0 |
|
1623 | 0 | // We will skip the override and pass to httpHandler to get spoofed userAgent |
1624 | 0 | // when 'privacy.resistFingerprinting' is true. |
1625 | 0 | if (!aIsCallerChrome && |
1626 | 0 | !nsContentUtils::ShouldResistFingerprinting()) { |
1627 | 0 | nsAutoString override; |
1628 | 0 | nsresult rv = |
1629 | 0 | mozilla::Preferences::GetString("general.useragent.override", override); |
1630 | 0 |
|
1631 | 0 | if (NS_SUCCEEDED(rv)) { |
1632 | 0 | aUserAgent = override; |
1633 | 0 | return NS_OK; |
1634 | 0 | } |
1635 | 0 | } |
1636 | 0 | |
1637 | 0 | nsresult rv; |
1638 | 0 | nsCOMPtr<nsIHttpProtocolHandler> |
1639 | 0 | service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); |
1640 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1641 | 0 | return rv; |
1642 | 0 | } |
1643 | 0 | |
1644 | 0 | nsAutoCString ua; |
1645 | 0 | rv = service->GetUserAgent(ua); |
1646 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1647 | 0 | return rv; |
1648 | 0 | } |
1649 | 0 | |
1650 | 0 | CopyASCIItoUTF16(ua, aUserAgent); |
1651 | 0 |
|
1652 | 0 | // When the caller is content, we will always return spoofed userAgent and |
1653 | 0 | // ignore the User-Agent header from the document channel when |
1654 | 0 | // 'privacy.resistFingerprinting' is true. |
1655 | 0 | if (!aWindow || |
1656 | 0 | (nsContentUtils::ShouldResistFingerprinting() && !aIsCallerChrome)) { |
1657 | 0 | return NS_OK; |
1658 | 0 | } |
1659 | 0 | |
1660 | 0 | // Copy the User-Agent header from the document channel which has already been |
1661 | 0 | // subject to UA overrides. |
1662 | 0 | nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc(); |
1663 | 0 | if (!doc) { |
1664 | 0 | return NS_OK; |
1665 | 0 | } |
1666 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = |
1667 | 0 | do_QueryInterface(doc->GetChannel()); |
1668 | 0 | if (httpChannel) { |
1669 | 0 | nsAutoCString userAgent; |
1670 | 0 | rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("User-Agent"), |
1671 | 0 | userAgent); |
1672 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1673 | 0 | return rv; |
1674 | 0 | } |
1675 | 0 | CopyASCIItoUTF16(userAgent, aUserAgent); |
1676 | 0 | } |
1677 | 0 | return NS_OK; |
1678 | 0 | } |
1679 | | |
1680 | | static nsCString |
1681 | | RequestKeySystemAccessLogString( |
1682 | | const nsAString& aKeySystem, |
1683 | | const Sequence<MediaKeySystemConfiguration>& aConfigs, |
1684 | | bool aIsSecureContext) |
1685 | 0 | { |
1686 | 0 | nsCString str; |
1687 | 0 | str.AppendPrintf("Navigator::RequestMediaKeySystemAccess(keySystem='%s' options=", |
1688 | 0 | NS_ConvertUTF16toUTF8(aKeySystem).get()); |
1689 | 0 | str.Append(MediaKeySystemAccess::ToCString(aConfigs)); |
1690 | 0 | str.AppendLiteral(") secureContext="); |
1691 | 0 | str.AppendInt(aIsSecureContext); |
1692 | 0 | return str; |
1693 | 0 | } |
1694 | | |
1695 | | already_AddRefed<Promise> |
1696 | | Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem, |
1697 | | const Sequence<MediaKeySystemConfiguration>& aConfigs, |
1698 | | ErrorResult& aRv) |
1699 | 0 | { |
1700 | 0 | EME_LOG("%s", |
1701 | 0 | RequestKeySystemAccessLogString( |
1702 | 0 | aKeySystem, aConfigs, mWindow->IsSecureContext()) |
1703 | 0 | .get()); |
1704 | 0 |
|
1705 | 0 | Telemetry::Accumulate(Telemetry::MEDIA_EME_SECURE_CONTEXT, |
1706 | 0 | mWindow->IsSecureContext()); |
1707 | 0 |
|
1708 | 0 | if (!mWindow->IsSecureContext()) { |
1709 | 0 | nsIDocument* doc = mWindow->GetExtantDoc(); |
1710 | 0 | nsString uri; |
1711 | 0 | if (doc) { |
1712 | 0 | Unused << doc->GetDocumentURI(uri); |
1713 | 0 | } |
1714 | 0 | const char16_t* params[] = { uri.get() }; |
1715 | 0 | nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, |
1716 | 0 | NS_LITERAL_CSTRING("Media"), |
1717 | 0 | doc, |
1718 | 0 | nsContentUtils::eDOM_PROPERTIES, |
1719 | 0 | "MediaEMEInsecureContextDeprecatedWarning", |
1720 | 0 | params, |
1721 | 0 | ArrayLength(params)); |
1722 | 0 | } |
1723 | 0 |
|
1724 | 0 | RefPtr<DetailedPromise> promise = |
1725 | 0 | DetailedPromise::Create(mWindow->AsGlobal(), aRv, |
1726 | 0 | NS_LITERAL_CSTRING("navigator.requestMediaKeySystemAccess"), |
1727 | 0 | Telemetry::VIDEO_EME_REQUEST_SUCCESS_LATENCY_MS, |
1728 | 0 | Telemetry::VIDEO_EME_REQUEST_FAILURE_LATENCY_MS); |
1729 | 0 | if (aRv.Failed()) { |
1730 | 0 | return nullptr; |
1731 | 0 | } |
1732 | 0 | |
1733 | 0 | if (!mMediaKeySystemAccessManager) { |
1734 | 0 | mMediaKeySystemAccessManager = new MediaKeySystemAccessManager(mWindow); |
1735 | 0 | } |
1736 | 0 |
|
1737 | 0 | mMediaKeySystemAccessManager->Request(promise, aKeySystem, aConfigs); |
1738 | 0 | return promise.forget(); |
1739 | 0 | } |
1740 | | |
1741 | | Presentation* |
1742 | | Navigator::GetPresentation(ErrorResult& aRv) |
1743 | 0 | { |
1744 | 0 | if (!mPresentation) { |
1745 | 0 | if (!mWindow) { |
1746 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
1747 | 0 | return nullptr; |
1748 | 0 | } |
1749 | 0 | mPresentation = Presentation::Create(mWindow); |
1750 | 0 | } |
1751 | 0 |
|
1752 | 0 | return mPresentation; |
1753 | 0 | } |
1754 | | |
1755 | | CredentialsContainer* |
1756 | | Navigator::Credentials() |
1757 | 0 | { |
1758 | 0 | if (!mCredentials) { |
1759 | 0 | mCredentials = new CredentialsContainer(GetWindow()); |
1760 | 0 | } |
1761 | 0 | return mCredentials; |
1762 | 0 | } |
1763 | | |
1764 | | dom::MediaCapabilities* |
1765 | | Navigator::MediaCapabilities() |
1766 | 0 | { |
1767 | 0 | if (!mMediaCapabilities) { |
1768 | 0 | mMediaCapabilities = |
1769 | 0 | new dom::MediaCapabilities(GetWindow()->AsGlobal()); |
1770 | 0 | } |
1771 | 0 | return mMediaCapabilities; |
1772 | 0 | } |
1773 | | |
1774 | | Clipboard* |
1775 | | Navigator::Clipboard() |
1776 | 0 | { |
1777 | 0 | if (!mClipboard) { |
1778 | 0 | mClipboard = new dom::Clipboard(GetWindow()); |
1779 | 0 | } |
1780 | 0 | return mClipboard; |
1781 | 0 | } |
1782 | | |
1783 | | /* static */ |
1784 | | bool |
1785 | | Navigator::Webdriver() |
1786 | 0 | { |
1787 | 0 | return Preferences::GetBool("marionette.enabled", false); |
1788 | 0 | } |
1789 | | |
1790 | | } // namespace dom |
1791 | | } // namespace mozilla |