Source code

Revision control

Other Tools

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