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