Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set ts=4 sw=2 cindent et: */
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
#include "mozilla/DebugOnly.h"
8
9
#include "nsIOService.h"
10
#include "nsIProtocolHandler.h"
11
#include "nsIFileProtocolHandler.h"
12
#include "nscore.h"
13
#include "nsIURI.h"
14
#include "prprf.h"
15
#include "nsErrorService.h"
16
#include "netCore.h"
17
#include "nsIObserverService.h"
18
#include "nsIPrefService.h"
19
#include "nsXPCOM.h"
20
#include "nsIProxiedProtocolHandler.h"
21
#include "nsIProxyInfo.h"
22
#include "nsEscape.h"
23
#include "nsNetUtil.h"
24
#include "nsNetCID.h"
25
#include "nsCRT.h"
26
#include "nsSimpleNestedURI.h"
27
#include "nsTArray.h"
28
#include "nsIConsoleService.h"
29
#include "nsIUploadChannel2.h"
30
#include "nsXULAppAPI.h"
31
#include "nsIScriptSecurityManager.h"
32
#include "nsIProtocolProxyCallback.h"
33
#include "nsICancelable.h"
34
#include "nsINetworkLinkService.h"
35
#include "nsPISocketTransportService.h"
36
#include "nsAsyncRedirectVerifyHelper.h"
37
#include "nsURLHelper.h"
38
#include "nsIProtocolProxyService2.h"
39
#include "MainThreadUtils.h"
40
#include "nsINode.h"
41
#include "nsIWidget.h"
42
#include "nsIHttpChannel.h"
43
#include "nsThreadUtils.h"
44
#include "mozilla/LoadInfo.h"
45
#include "mozilla/net/NeckoCommon.h"
46
#include "mozilla/Services.h"
47
#include "mozilla/Telemetry.h"
48
#include "mozilla/net/DNS.h"
49
#include "mozilla/ipc/URIUtils.h"
50
#include "mozilla/net/NeckoChild.h"
51
#include "mozilla/net/NeckoParent.h"
52
#include "mozilla/dom/ClientInfo.h"
53
#include "mozilla/dom/ContentParent.h"
54
#include "mozilla/dom/ServiceWorkerDescriptor.h"
55
#include "mozilla/net/CaptivePortalService.h"
56
#include "mozilla/net/NetworkConnectivityService.h"
57
#include "mozilla/net/SocketProcessHost.h"
58
#include "mozilla/net/SocketProcessParent.h"
59
#include "mozilla/net/SSLTokensCache.h"
60
#include "mozilla/Unused.h"
61
#include "nsContentSecurityManager.h"
62
#include "nsContentUtils.h"
63
#include "nsExceptionHandler.h"
64
#include "mozilla/StaticPrefs_network.h"
65
66
#ifdef MOZ_WIDGET_GTK
67
# include "nsGIOProtocolHandler.h"
68
#endif
69
70
namespace mozilla {
71
namespace net {
72
73
using mozilla::Maybe;
74
using mozilla::dom::ClientInfo;
75
using mozilla::dom::ServiceWorkerDescriptor;
76
77
#define PORT_PREF_PREFIX "network.security.ports."
78
#define PORT_PREF(x) PORT_PREF_PREFIX x
79
#define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status"
80
#define OFFLINE_MIRRORS_CONNECTIVITY "network.offline-mirrors-connectivity"
81
82
// Nb: these have been misnomers since bug 715770 removed the buffer cache.
83
// "network.segment.count" and "network.segment.size" would be better names,
84
// but the old names are still used to preserve backward compatibility.
85
#define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
86
#define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size"
87
#define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled"
88
#define WEBRTC_PREF_PREFIX "media.peerconnection."
89
#define NETWORK_DNS_PREF "network.dns."
90
91
#define MAX_RECURSION_COUNT 50
92
93
nsIOService* gIOService;
94
static bool gHasWarnedUploadChannel2;
95
static bool gCaptivePortalEnabled = false;
96
static LazyLogModule gIOServiceLog("nsIOService");
97
#undef LOG
98
#define LOG(args) MOZ_LOG(gIOServiceLog, LogLevel::Debug, args)
99
100
// A general port blacklist. Connections to these ports will not be allowed
101
// unless the protocol overrides.
102
//
103
// TODO: I am sure that there are more ports to be added.
104
// This cut is based on the classic mozilla codebase
105
106
int16_t gBadPortList[] = {
107
1, // tcpmux
108
7, // echo
109
9, // discard
110
11, // systat
111
13, // daytime
112
15, // netstat
113
17, // qotd
114
19, // chargen
115
20, // ftp-data
116
21, // ftp
117
22, // ssh
118
23, // telnet
119
25, // smtp
120
37, // time
121
42, // name
122
43, // nicname
123
53, // domain
124
77, // priv-rjs
125
79, // finger
126
87, // ttylink
127
95, // supdup
128
101, // hostriame
129
102, // iso-tsap
130
103, // gppitnp
131
104, // acr-nema
132
109, // pop2
133
110, // pop3
134
111, // sunrpc
135
113, // auth
136
115, // sftp
137
117, // uucp-path
138
119, // nntp
139
123, // ntp
140
135, // loc-srv / epmap
141
139, // netbios
142
143, // imap2
143
179, // bgp
144
389, // ldap
145
427, // afp (alternate)
146
465, // smtp (alternate)
147
512, // print / exec
148
513, // login
149
514, // shell
150
515, // printer
151
526, // tempo
152
530, // courier
153
531, // chat
154
532, // netnews
155
540, // uucp
156
548, // afp
157
556, // remotefs
158
563, // nntp+ssl
159
587, // smtp (outgoing)
160
601, // syslog-conn
161
636, // ldap+ssl
162
993, // imap+ssl
163
995, // pop3+ssl
164
2049, // nfs
165
3659, // apple-sasl
166
4045, // lockd
167
6000, // x11
168
6665, // irc (alternate)
169
6666, // irc (alternate)
170
6667, // irc (default)
171
6668, // irc (alternate)
172
6669, // irc (alternate)
173
6697, // irc+tls
174
0, // Sentinel value: This MUST be zero
175
};
176
177
static const char kProfileChangeNetTeardownTopic[] =
178
"profile-change-net-teardown";
179
static const char kProfileChangeNetRestoreTopic[] =
180
"profile-change-net-restore";
181
static const char kProfileDoChange[] = "profile-do-change";
182
183
// Necko buffer defaults
184
uint32_t nsIOService::gDefaultSegmentSize = 4096;
185
uint32_t nsIOService::gDefaultSegmentCount = 24;
186
187
bool nsIOService::sIsDataURIUniqueOpaqueOrigin = false;
188
bool nsIOService::sBlockToplevelDataUriNavigations = false;
189
190
////////////////////////////////////////////////////////////////////////////////
191
192
nsIOService::nsIOService()
193
: mOffline(true),
194
mOfflineForProfileChange(false),
195
mManageLinkStatus(false),
196
mConnectivity(true),
197
mOfflineMirrorsConnectivity(true),
198
mSettingOffline(false),
199
mSetOfflineValue(false),
200
mSocketProcessLaunchComplete(false),
201
mShutdown(false),
202
mHttpHandlerAlreadyShutingDown(false),
203
mNetworkLinkServiceInitialized(false),
204
mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY),
205
mTotalRequests(0),
206
mCacheWon(0),
207
mNetWon(0),
208
mLastOfflineStateChange(PR_IntervalNow()),
209
mLastConnectivityChange(PR_IntervalNow()),
210
mLastNetworkLinkChange(PR_IntervalNow()),
211
mNetTearingDownStarted(0),
212
mSocketProcess(nullptr) {}
213
214
static const char* gCallbackPrefs[] = {
215
PORT_PREF_PREFIX,
216
MANAGE_OFFLINE_STATUS_PREF,
217
NECKO_BUFFER_CACHE_COUNT_PREF,
218
NECKO_BUFFER_CACHE_SIZE_PREF,
219
NETWORK_CAPTIVE_PORTAL_PREF,
220
nullptr,
221
};
222
223
static const char* gCallbackPrefsForSocketProcess[] = {
224
WEBRTC_PREF_PREFIX,
225
NETWORK_DNS_PREF,
226
nullptr,
227
};
228
229
nsresult nsIOService::Init() {
230
// XXX hack until xpidl supports error info directly (bug 13423)
231
nsCOMPtr<nsIErrorService> errorService = nsErrorService::GetOrCreate();
232
MOZ_ALWAYS_TRUE(errorService);
233
errorService->RegisterErrorStringBundle(NS_ERROR_MODULE_NETWORK,
234
NECKO_MSGS_URL);
235
236
SSLTokensCache::Init();
237
238
InitializeCaptivePortalService();
239
240
// setup our bad port list stuff
241
for (int i = 0; gBadPortList[i]; i++)
242
mRestrictedPortList.AppendElement(gBadPortList[i]);
243
244
// Further modifications to the port list come from prefs
245
Preferences::RegisterPrefixCallbacks(nsIOService::PrefsChanged,
246
gCallbackPrefs, this);
247
PrefsChanged();
248
249
// Register for profile change notifications
250
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
251
if (observerService) {
252
observerService->AddObserver(this, kProfileChangeNetTeardownTopic, true);
253
observerService->AddObserver(this, kProfileChangeNetRestoreTopic, true);
254
observerService->AddObserver(this, kProfileDoChange, true);
255
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
256
observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
257
observerService->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, true);
258
observerService->AddObserver(this, NS_PREFSERVICE_READ_TOPIC_ID, true);
259
} else
260
NS_WARNING("failed to get observer service");
261
262
Preferences::AddBoolVarCache(&sIsDataURIUniqueOpaqueOrigin,
263
"security.data_uri.unique_opaque_origin", false);
264
Preferences::AddBoolVarCache(
265
&sBlockToplevelDataUriNavigations,
266
"security.data_uri.block_toplevel_data_uri_navigations", false);
267
Preferences::AddBoolVarCache(&mOfflineMirrorsConnectivity,
268
OFFLINE_MIRRORS_CONNECTIVITY, true);
269
270
gIOService = this;
271
272
InitializeNetworkLinkService();
273
InitializeProtocolProxyService();
274
275
SetOffline(false);
276
277
return NS_OK;
278
}
279
280
nsIOService::~nsIOService() {
281
if (gIOService) {
282
MOZ_ASSERT(gIOService == this);
283
gIOService = nullptr;
284
}
285
}
286
287
nsresult nsIOService::InitializeCaptivePortalService() {
288
if (XRE_GetProcessType() != GeckoProcessType_Default) {
289
// We only initalize a captive portal service in the main process
290
return NS_OK;
291
}
292
293
mCaptivePortalService = do_GetService(NS_CAPTIVEPORTAL_CID);
294
if (mCaptivePortalService) {
295
return static_cast<CaptivePortalService*>(mCaptivePortalService.get())
296
->Initialize();
297
}
298
299
// Instantiate and initialize the service
300
RefPtr<NetworkConnectivityService> ncs =
301
NetworkConnectivityService::GetSingleton();
302
303
return NS_OK;
304
}
305
306
nsresult nsIOService::InitializeSocketTransportService() {
307
nsresult rv = NS_OK;
308
309
if (!mSocketTransportService) {
310
mSocketTransportService =
311
do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
312
if (NS_FAILED(rv)) {
313
NS_WARNING("failed to get socket transport service");
314
}
315
}
316
317
if (mSocketTransportService) {
318
rv = mSocketTransportService->Init();
319
NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed");
320
mSocketTransportService->SetOffline(false);
321
}
322
323
return rv;
324
}
325
326
nsresult nsIOService::InitializeNetworkLinkService() {
327
nsresult rv = NS_OK;
328
329
if (mNetworkLinkServiceInitialized) return rv;
330
331
if (!NS_IsMainThread()) {
332
NS_WARNING("Network link service should be created on main thread");
333
return NS_ERROR_FAILURE;
334
}
335
336
// go into managed mode if we can, and chrome process
337
if (XRE_IsParentProcess()) {
338
mNetworkLinkService =
339
do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
340
}
341
342
if (mNetworkLinkService) {
343
mNetworkLinkServiceInitialized = true;
344
}
345
346
// After initializing the networkLinkService, query the connectivity state
347
OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
348
349
return rv;
350
}
351
352
nsresult nsIOService::InitializeProtocolProxyService() {
353
nsresult rv = NS_OK;
354
355
if (XRE_IsParentProcess()) {
356
// for early-initialization
357
Unused << do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
358
}
359
360
return rv;
361
}
362
363
already_AddRefed<nsIOService> nsIOService::GetInstance() {
364
if (!gIOService) {
365
RefPtr<nsIOService> ios = new nsIOService();
366
if (NS_SUCCEEDED(ios->Init())) {
367
MOZ_ASSERT(gIOService == ios.get());
368
return ios.forget();
369
}
370
}
371
return do_AddRef(gIOService);
372
}
373
374
class SocketProcessListenerProxy : public SocketProcessHost::Listener {
375
public:
376
SocketProcessListenerProxy() = default;
377
void OnProcessLaunchComplete(SocketProcessHost* aHost, bool aSucceeded) {
378
if (!gIOService) {
379
return;
380
}
381
382
gIOService->OnProcessLaunchComplete(aHost, aSucceeded);
383
}
384
385
void OnProcessUnexpectedShutdown(SocketProcessHost* aHost) {
386
if (!gIOService) {
387
return;
388
}
389
390
gIOService->OnProcessUnexpectedShutdown(aHost);
391
}
392
};
393
394
nsresult nsIOService::LaunchSocketProcess() {
395
MOZ_ASSERT(NS_IsMainThread());
396
397
if (XRE_GetProcessType() != GeckoProcessType_Default) {
398
return NS_OK;
399
}
400
401
if (mSocketProcess) {
402
return NS_OK;
403
}
404
405
if (!XRE_IsE10sParentProcess()) {
406
LOG(("nsIOService skipping LaunchSocketProcess because e10s is disabled"));
407
return NS_OK;
408
}
409
410
if (!Preferences::GetBool("network.process.enabled", true)) {
411
LOG(("nsIOService skipping LaunchSocketProcess because of the pref"));
412
return NS_OK;
413
}
414
415
Preferences::RegisterPrefixCallbacks(
416
nsIOService::NotifySocketProcessPrefsChanged,
417
gCallbackPrefsForSocketProcess, this);
418
419
// The subprocess is launched asynchronously, so we wait for a callback to
420
// acquire the IPDL actor.
421
mSocketProcess = new SocketProcessHost(new SocketProcessListenerProxy());
422
LOG(("nsIOService::LaunchSocketProcess"));
423
if (!mSocketProcess->Launch()) {
424
NS_WARNING("Failed to launch socket process!!");
425
DestroySocketProcess();
426
return NS_ERROR_FAILURE;
427
}
428
429
return NS_OK;
430
}
431
432
void nsIOService::DestroySocketProcess() {
433
MOZ_ASSERT(NS_IsMainThread());
434
435
if (XRE_GetProcessType() != GeckoProcessType_Default || !mSocketProcess) {
436
return;
437
}
438
439
Preferences::UnregisterPrefixCallbacks(
440
nsIOService::NotifySocketProcessPrefsChanged,
441
gCallbackPrefsForSocketProcess, this);
442
443
mSocketProcess->Shutdown();
444
mSocketProcess = nullptr;
445
}
446
447
bool nsIOService::SocketProcessReady() {
448
return mSocketProcess && mSocketProcess->IsConnected();
449
}
450
451
// static
452
void nsIOService::NotifySocketProcessPrefsChanged(const char* aName,
453
void* aSelf) {
454
static_cast<nsIOService*>(aSelf)->NotifySocketProcessPrefsChanged(aName);
455
}
456
457
void nsIOService::NotifySocketProcessPrefsChanged(const char* aName) {
458
MOZ_ASSERT(NS_IsMainThread());
459
460
if (!XRE_IsParentProcess()) {
461
return;
462
}
463
464
dom::Pref pref(nsCString(aName), /* isLocked */ false, Nothing(), Nothing());
465
Preferences::GetPreference(&pref);
466
auto sendPrefUpdate = [pref]() {
467
Unused << gIOService->mSocketProcess->GetActor()->SendPreferenceUpdate(
468
pref);
469
};
470
CallOrWaitForSocketProcess(sendPrefUpdate);
471
}
472
473
void nsIOService::OnProcessLaunchComplete(SocketProcessHost* aHost,
474
bool aSucceeded) {
475
MOZ_ASSERT(NS_IsMainThread());
476
477
LOG(("nsIOService::OnProcessLaunchComplete aSucceeded=%d\n", aSucceeded));
478
479
mSocketProcessLaunchComplete = true;
480
481
if (mShutdown || !SocketProcessReady()) {
482
return;
483
}
484
485
if (!mPendingEvents.IsEmpty()) {
486
nsTArray<std::function<void()>> pendingEvents;
487
mPendingEvents.SwapElements(pendingEvents);
488
for (auto& func : pendingEvents) {
489
func();
490
}
491
}
492
}
493
494
void nsIOService::CallOrWaitForSocketProcess(
495
const std::function<void()>& aFunc) {
496
MOZ_ASSERT(NS_IsMainThread());
497
if (IsSocketProcessLaunchComplete() && SocketProcessReady()) {
498
aFunc();
499
} else {
500
mPendingEvents.AppendElement(aFunc); // infallible
501
}
502
}
503
504
int32_t nsIOService::SocketProcessPid() {
505
if (!mSocketProcess) {
506
return 0;
507
}
508
if (SocketProcessParent* actor = mSocketProcess->GetActor()) {
509
return (int32_t)actor->OtherPid();
510
}
511
return 0;
512
}
513
514
bool nsIOService::IsSocketProcessLaunchComplete() {
515
MOZ_ASSERT(NS_IsMainThread());
516
return mSocketProcessLaunchComplete;
517
}
518
519
void nsIOService::OnProcessUnexpectedShutdown(SocketProcessHost* aHost) {
520
MOZ_ASSERT(NS_IsMainThread());
521
522
LOG(("nsIOService::OnProcessUnexpectedShutdown\n"));
523
DestroySocketProcess();
524
}
525
526
RefPtr<MemoryReportingProcess> nsIOService::GetSocketProcessMemoryReporter() {
527
// Check the prefs here again, since we don't want to create
528
// SocketProcessMemoryReporter for some tests.
529
if (!Preferences::GetBool("network.process.enabled") ||
530
!SocketProcessReady()) {
531
return nullptr;
532
}
533
534
return new SocketProcessMemoryReporter();
535
}
536
537
NS_IMETHODIMP
538
nsIOService::SocketProcessTelemetryPing() {
539
CallOrWaitForSocketProcess([]() {
540
Unused << gIOService->mSocketProcess->GetActor()
541
->SendSocketProcessTelemetryPing();
542
});
543
return NS_OK;
544
}
545
546
NS_IMPL_ISUPPORTS(nsIOService, nsIIOService, nsINetUtil, nsISpeculativeConnect,
547
nsIObserver, nsIIOServiceInternal, nsISupportsWeakReference)
548
549
////////////////////////////////////////////////////////////////////////////////
550
551
nsresult nsIOService::RecheckCaptivePortal() {
552
MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread");
553
if (!mCaptivePortalService) {
554
return NS_OK;
555
}
556
nsCOMPtr<nsIRunnable> task = NewRunnableMethod(
557
"nsIOService::RecheckCaptivePortal", mCaptivePortalService,
558
&nsICaptivePortalService::RecheckCaptivePortal);
559
return NS_DispatchToMainThread(task);
560
}
561
562
nsresult nsIOService::RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan) {
563
nsresult rv;
564
565
if (!mCaptivePortalService) {
566
return NS_OK;
567
}
568
569
nsCOMPtr<nsIURI> uri;
570
rv = newChan->GetURI(getter_AddRefs(uri));
571
if (NS_FAILED(rv)) {
572
return rv;
573
}
574
575
nsCString host;
576
rv = uri->GetHost(host);
577
if (NS_FAILED(rv)) {
578
return rv;
579
}
580
581
PRNetAddr prAddr;
582
if (PR_StringToNetAddr(host.BeginReading(), &prAddr) != PR_SUCCESS) {
583
// The redirect wasn't to an IP literal, so there's probably no need
584
// to trigger the captive portal detection right now. It can wait.
585
return NS_OK;
586
}
587
588
NetAddr netAddr;
589
PRNetAddrToNetAddr(&prAddr, &netAddr);
590
if (IsIPAddrLocal(&netAddr)) {
591
// Redirects to local IP addresses are probably captive portals
592
RecheckCaptivePortal();
593
}
594
595
return NS_OK;
596
}
597
598
nsresult nsIOService::AsyncOnChannelRedirect(
599
nsIChannel* oldChan, nsIChannel* newChan, uint32_t flags,
600
nsAsyncRedirectVerifyHelper* helper) {
601
// If a redirect to a local network address occurs, then chances are we
602
// are in a captive portal, so we trigger a recheck.
603
RecheckCaptivePortalIfLocalRedirect(newChan);
604
605
// This is silly. I wish there was a simpler way to get at the global
606
// reference of the contentSecurityManager. But it lives in the XPCOM
607
// service registry.
608
nsCOMPtr<nsIChannelEventSink> sink =
609
do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
610
if (sink) {
611
nsresult rv =
612
helper->DelegateOnChannelRedirect(sink, oldChan, newChan, flags);
613
if (NS_FAILED(rv)) return rv;
614
}
615
616
// Finally, our category
617
nsCOMArray<nsIChannelEventSink> entries;
618
mChannelEventSinks.GetEntries(entries);
619
int32_t len = entries.Count();
620
for (int32_t i = 0; i < len; ++i) {
621
nsresult rv =
622
helper->DelegateOnChannelRedirect(entries[i], oldChan, newChan, flags);
623
if (NS_FAILED(rv)) return rv;
624
}
625
return NS_OK;
626
}
627
628
nsresult nsIOService::CacheProtocolHandler(const char* scheme,
629
nsIProtocolHandler* handler) {
630
MOZ_ASSERT(NS_IsMainThread());
631
632
for (unsigned int i = 0; i < NS_N(gScheme); i++) {
633
if (!nsCRT::strcasecmp(scheme, gScheme[i])) {
634
nsresult rv;
635
NS_ASSERTION(!mWeakHandler[i], "Protocol handler already cached");
636
// Make sure the handler supports weak references.
637
nsCOMPtr<nsISupportsWeakReference> factoryPtr =
638
do_QueryInterface(handler, &rv);
639
if (!factoryPtr) {
640
// Don't cache handlers that don't support weak reference as
641
// there is real danger of a circular reference.
642
#ifdef DEBUG_dp
643
printf(
644
"DEBUG: %s protcol handler doesn't support weak ref. Not cached.\n",
645
scheme);
646
#endif /* DEBUG_dp */
647
return NS_ERROR_FAILURE;
648
}
649
mWeakHandler[i] = do_GetWeakReference(handler);
650
return NS_OK;
651
}
652
}
653
return NS_ERROR_FAILURE;
654
}
655
656
nsresult nsIOService::GetCachedProtocolHandler(const char* scheme,
657
nsIProtocolHandler** result,
658
uint32_t start, uint32_t end) {
659
MOZ_ASSERT(NS_IsMainThread());
660
661
uint32_t len = end - start - 1;
662
for (unsigned int i = 0; i < NS_N(gScheme); i++) {
663
if (!mWeakHandler[i]) continue;
664
665
// handle unterminated strings
666
// start is inclusive, end is exclusive, len = end - start - 1
667
if (end ? (!nsCRT::strncasecmp(scheme + start, gScheme[i], len) &&
668
gScheme[i][len] == '\0')
669
: (!nsCRT::strcasecmp(scheme, gScheme[i]))) {
670
return CallQueryReferent(mWeakHandler[i].get(), result);
671
}
672
}
673
return NS_ERROR_FAILURE;
674
}
675
676
static bool UsesExternalProtocolHandler(const char* aScheme) {
677
if (NS_LITERAL_CSTRING("file").Equals(aScheme) ||
678
NS_LITERAL_CSTRING("chrome").Equals(aScheme) ||
679
NS_LITERAL_CSTRING("resource").Equals(aScheme)) {
680
// Don't allow file:, chrome: or resource: URIs to be handled with
681
// nsExternalProtocolHandler, since internally we rely on being able to
682
// use and read from these URIs.
683
return false;
684
}
685
686
for (const auto& forcedExternalScheme : gForcedExternalSchemes) {
687
if (!nsCRT::strcasecmp(forcedExternalScheme, aScheme)) {
688
return true;
689
}
690
}
691
692
nsAutoCString pref("network.protocol-handler.external.");
693
pref += aScheme;
694
695
return Preferences::GetBool(pref.get(), false);
696
}
697
698
NS_IMETHODIMP
699
nsIOService::GetProtocolHandler(const char* scheme,
700
nsIProtocolHandler** result) {
701
nsresult rv;
702
703
NS_ENSURE_ARG_POINTER(scheme);
704
// XXX we may want to speed this up by introducing our own protocol
705
// scheme -> protocol handler mapping, avoiding the string manipulation
706
// and service manager stuff
707
708
rv = GetCachedProtocolHandler(scheme, result);
709
if (NS_SUCCEEDED(rv)) return rv;
710
711
if (scheme[0] != '\0' && !UsesExternalProtocolHandler(scheme)) {
712
nsAutoCString contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX);
713
contractID += scheme;
714
ToLowerCase(contractID);
715
716
rv = CallGetService(contractID.get(), result);
717
if (NS_SUCCEEDED(rv)) {
718
CacheProtocolHandler(scheme, *result);
719
return rv;
720
}
721
722
#ifdef MOZ_WIDGET_GTK
723
// check to see whether GVFS can handle this URI scheme. otherwise, we
724
// failover to using the default protocol handler.
725
726
RefPtr<nsGIOProtocolHandler> gioHandler =
727
nsGIOProtocolHandler::GetSingleton();
728
if (gioHandler->IsSupportedProtocol(nsCString(scheme))) {
729
gioHandler.forget(result);
730
return NS_OK;
731
}
732
#endif
733
}
734
735
// Okay we don't have a protocol handler to handle this url type, so use
736
// the default protocol handler. This will cause urls to get dispatched
737
// out to the OS ('cause we can't do anything with them) when we try to
738
// read from a channel created by the default protocol handler.
739
740
rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "default", result);
741
if (NS_FAILED(rv)) return NS_ERROR_UNKNOWN_PROTOCOL;
742
743
return rv;
744
}
745
746
NS_IMETHODIMP
747
nsIOService::ExtractScheme(const nsACString& inURI, nsACString& scheme) {
748
return net_ExtractURLScheme(inURI, scheme);
749
}
750
751
NS_IMETHODIMP
752
nsIOService::HostnameIsLocalIPAddress(nsIURI* aURI, bool* aResult) {
753
NS_ENSURE_ARG_POINTER(aURI);
754
755
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
756
NS_ENSURE_ARG_POINTER(innerURI);
757
758
nsAutoCString host;
759
nsresult rv = innerURI->GetAsciiHost(host);
760
if (NS_FAILED(rv)) {
761
return rv;
762
}
763
764
*aResult = false;
765
766
PRNetAddr addr;
767
PRStatus result = PR_StringToNetAddr(host.get(), &addr);
768
if (result == PR_SUCCESS) {
769
NetAddr netAddr;
770
PRNetAddrToNetAddr(&addr, &netAddr);
771
if (IsIPAddrLocal(&netAddr)) {
772
*aResult = true;
773
}
774
}
775
776
return NS_OK;
777
}
778
779
NS_IMETHODIMP
780
nsIOService::HostnameIsSharedIPAddress(nsIURI* aURI, bool* aResult) {
781
NS_ENSURE_ARG_POINTER(aURI);
782
783
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
784
NS_ENSURE_ARG_POINTER(innerURI);
785
786
nsAutoCString host;
787
nsresult rv = innerURI->GetAsciiHost(host);
788
if (NS_FAILED(rv)) {
789
return rv;
790
}
791
792
*aResult = false;
793
794
PRNetAddr addr;
795
PRStatus result = PR_StringToNetAddr(host.get(), &addr);
796
if (result == PR_SUCCESS) {
797
NetAddr netAddr;
798
PRNetAddrToNetAddr(&addr, &netAddr);
799
if (IsIPAddrShared(&netAddr)) {
800
*aResult = true;
801
}
802
}
803
804
return NS_OK;
805
}
806
807
NS_IMETHODIMP
808
nsIOService::GetProtocolFlags(const char* scheme, uint32_t* flags) {
809
nsCOMPtr<nsIProtocolHandler> handler;
810
nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler));
811
if (NS_FAILED(rv)) return rv;
812
813
// We can't call DoGetProtocolFlags here because we don't have a URI. This
814
// API is used by (and only used by) extensions, which is why it's still
815
// around. Calling this on a scheme with dynamic flags will throw.
816
rv = handler->GetProtocolFlags(flags);
817
#if !IS_ORIGIN_IS_FULL_SPEC_DEFINED
818
MOZ_RELEASE_ASSERT(!(*flags & nsIProtocolHandler::ORIGIN_IS_FULL_SPEC),
819
"ORIGIN_IS_FULL_SPEC is unsupported but used");
820
#endif
821
return rv;
822
}
823
824
class AutoIncrement {
825
public:
826
explicit AutoIncrement(uint32_t* var) : mVar(var) { ++*var; }
827
~AutoIncrement() { --*mVar; }
828
829
private:
830
uint32_t* mVar;
831
};
832
833
nsresult nsIOService::NewURI(const nsACString& aSpec, const char* aCharset,
834
nsIURI* aBaseURI, nsIURI** result) {
835
return NS_NewURI(result, aSpec, aCharset, aBaseURI);
836
}
837
838
NS_IMETHODIMP
839
nsIOService::NewFileURI(nsIFile* file, nsIURI** result) {
840
nsresult rv;
841
NS_ENSURE_ARG_POINTER(file);
842
843
nsCOMPtr<nsIProtocolHandler> handler;
844
845
rv = GetProtocolHandler("file", getter_AddRefs(handler));
846
if (NS_FAILED(rv)) return rv;
847
848
nsCOMPtr<nsIFileProtocolHandler> fileHandler(do_QueryInterface(handler, &rv));
849
if (NS_FAILED(rv)) return rv;
850
851
return fileHandler->NewFileURI(file, result);
852
}
853
854
NS_IMETHODIMP
855
nsIOService::NewChannelFromURI(nsIURI* aURI, nsINode* aLoadingNode,
856
nsIPrincipal* aLoadingPrincipal,
857
nsIPrincipal* aTriggeringPrincipal,
858
uint32_t aSecurityFlags,
859
uint32_t aContentPolicyType,
860
nsIChannel** result) {
861
return NewChannelFromURIWithProxyFlags(aURI,
862
nullptr, // aProxyURI
863
0, // aProxyFlags
864
aLoadingNode, aLoadingPrincipal,
865
aTriggeringPrincipal, aSecurityFlags,
866
aContentPolicyType, result);
867
}
868
nsresult nsIOService::NewChannelFromURIWithClientAndController(
869
nsIURI* aURI, nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
870
nsIPrincipal* aTriggeringPrincipal,
871
const Maybe<ClientInfo>& aLoadingClientInfo,
872
const Maybe<ServiceWorkerDescriptor>& aController, uint32_t aSecurityFlags,
873
uint32_t aContentPolicyType, nsIChannel** aResult) {
874
return NewChannelFromURIWithProxyFlagsInternal(
875
aURI,
876
nullptr, // aProxyURI
877
0, // aProxyFlags
878
aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal, aLoadingClientInfo,
879
aController, aSecurityFlags, aContentPolicyType, aResult);
880
}
881
882
NS_IMETHODIMP
883
nsIOService::NewChannelFromURIWithLoadInfo(nsIURI* aURI, nsILoadInfo* aLoadInfo,
884
nsIChannel** result) {
885
return NewChannelFromURIWithProxyFlagsInternal(aURI,
886
nullptr, // aProxyURI
887
0, // aProxyFlags
888
aLoadInfo, result);
889
}
890
891
nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal(
892
nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
893
nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
894
nsIPrincipal* aTriggeringPrincipal,
895
const Maybe<ClientInfo>& aLoadingClientInfo,
896
const Maybe<ServiceWorkerDescriptor>& aController, uint32_t aSecurityFlags,
897
uint32_t aContentPolicyType, nsIChannel** result) {
898
// Ideally all callers of NewChannelFromURIWithProxyFlagsInternal provide
899
// the necessary arguments to create a loadinfo.
900
//
901
// Note, historically this could be called with nullptr aLoadingNode,
902
// aLoadingPrincipal, and aTriggeringPrincipal from addons using
903
// newChannelFromURIWithProxyFlags(). This code tried to accomodate
904
// by not creating a LoadInfo in such cases. Now that both the legacy
905
// addons and that API are gone we could possibly require always creating a
906
// LoadInfo here. See bug 1432205.
907
nsCOMPtr<nsILoadInfo> loadInfo;
908
909
// TYPE_DOCUMENT loads don't require a loadingNode or principal, but other
910
// types do.
911
if (aLoadingNode || aLoadingPrincipal ||
912
aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
913
loadInfo = new LoadInfo(aLoadingPrincipal, aTriggeringPrincipal,
914
aLoadingNode, aSecurityFlags, aContentPolicyType,
915
aLoadingClientInfo, aController);
916
}
917
if (!loadInfo) {
918
JSContext* cx = nsContentUtils::GetCurrentJSContext();
919
// if coming from JS we like to know the JS stack, otherwise
920
// we just assert that we are able to create a valid loadinfo!
921
if (cx) {
922
JS::UniqueChars chars = xpc_PrintJSStack(cx,
923
/*showArgs=*/false,
924
/*showLocals=*/false,
925
/*showThisProps=*/false);
926
nsDependentCString stackTrace(chars.get());
927
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Bug_1541161,
928
stackTrace);
929
}
930
MOZ_DIAGNOSTIC_ASSERT(false,
931
"Please pass security info when creating a channel");
932
return NS_ERROR_INVALID_ARG;
933
}
934
return NewChannelFromURIWithProxyFlagsInternal(aURI, aProxyURI, aProxyFlags,
935
loadInfo, result);
936
}
937
938
nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal(
939
nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
940
nsILoadInfo* aLoadInfo, nsIChannel** result) {
941
nsresult rv;
942
NS_ENSURE_ARG_POINTER(aURI);
943
944
nsAutoCString scheme;
945
rv = aURI->GetScheme(scheme);
946
if (NS_FAILED(rv)) return rv;
947
948
nsCOMPtr<nsIProtocolHandler> handler;
949
rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
950
if (NS_FAILED(rv)) return rv;
951
952
uint32_t protoFlags;
953
rv = handler->DoGetProtocolFlags(aURI, &protoFlags);
954
if (NS_FAILED(rv)) return rv;
955
956
nsCOMPtr<nsIChannel> channel;
957
nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler);
958
if (pph) {
959
rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI,
960
aLoadInfo, getter_AddRefs(channel));
961
} else {
962
rv = handler->NewChannel(aURI, aLoadInfo, getter_AddRefs(channel));
963
}
964
if (NS_FAILED(rv)) return rv;
965
966
// Make sure that all the individual protocolhandlers attach a loadInfo.
967
if (aLoadInfo) {
968
// make sure we have the same instance of loadInfo on the newly created
969
// channel
970
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
971
if (aLoadInfo != loadInfo) {
972
MOZ_ASSERT(false, "newly created channel must have a loadinfo attached");
973
return NS_ERROR_UNEXPECTED;
974
}
975
976
// If we're sandboxed, make sure to clear any owner the channel
977
// might already have.
978
if (loadInfo->GetLoadingSandboxed()) {
979
channel->SetOwner(nullptr);
980
}
981
}
982
983
// Some extensions override the http protocol handler and provide their own
984
// implementation. The channels returned from that implementation doesn't
985
// seem to always implement the nsIUploadChannel2 interface, presumably
986
// because it's a new interface.
987
// Eventually we should remove this and simply require that http channels
988
// implement the new interface.
989
// See bug 529041
990
if (!gHasWarnedUploadChannel2 && scheme.EqualsLiteral("http")) {
991
nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(channel);
992
if (!uploadChannel2) {
993
nsCOMPtr<nsIConsoleService> consoleService =
994
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
995
if (consoleService) {
996
consoleService->LogStringMessage(
997
u"Http channel implementation "
998
"doesn't support nsIUploadChannel2. An extension has "
999
"supplied a non-functional http protocol handler. This will "
1000
"break behavior and in future releases not work at all.");
1001
}
1002
gHasWarnedUploadChannel2 = true;
1003
}
1004
}
1005
1006
channel.forget(result);
1007
return NS_OK;
1008
}
1009
1010
NS_IMETHODIMP
1011
nsIOService::NewChannelFromURIWithProxyFlags(
1012
nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
1013
nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
1014
nsIPrincipal* aTriggeringPrincipal, uint32_t aSecurityFlags,
1015
uint32_t aContentPolicyType, nsIChannel** result) {
1016
return NewChannelFromURIWithProxyFlagsInternal(
1017
aURI, aProxyURI, aProxyFlags, aLoadingNode, aLoadingPrincipal,
1018
aTriggeringPrincipal, Maybe<ClientInfo>(),
1019
Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
1020
result);
1021
}
1022
1023
NS_IMETHODIMP
1024
nsIOService::NewChannel(const nsACString& aSpec, const char* aCharset,
1025
nsIURI* aBaseURI, nsINode* aLoadingNode,
1026
nsIPrincipal* aLoadingPrincipal,
1027
nsIPrincipal* aTriggeringPrincipal,
1028
uint32_t aSecurityFlags, uint32_t aContentPolicyType,
1029
nsIChannel** result) {
1030
nsresult rv;
1031
nsCOMPtr<nsIURI> uri;
1032
rv = NewURI(aSpec, aCharset, aBaseURI, getter_AddRefs(uri));
1033
if (NS_FAILED(rv)) return rv;
1034
1035
return NewChannelFromURI(uri, aLoadingNode, aLoadingPrincipal,
1036
aTriggeringPrincipal, aSecurityFlags,
1037
aContentPolicyType, result);
1038
}
1039
1040
bool nsIOService::IsLinkUp() {
1041
InitializeNetworkLinkService();
1042
1043
if (!mNetworkLinkService) {
1044
// We cannot decide, assume the link is up
1045
return true;
1046
}
1047
1048
bool isLinkUp;
1049
nsresult rv;
1050
rv = mNetworkLinkService->GetIsLinkUp(&isLinkUp);
1051
if (NS_FAILED(rv)) {
1052
return true;
1053
}
1054
1055
return isLinkUp;
1056
}
1057
1058
NS_IMETHODIMP
1059
nsIOService::GetOffline(bool* offline) {
1060
if (mOfflineMirrorsConnectivity) {
1061
*offline = mOffline || !mConnectivity;
1062
} else {
1063
*offline = mOffline;
1064
}
1065
return NS_OK;
1066
}
1067
1068
NS_IMETHODIMP
1069
nsIOService::SetOffline(bool offline) {
1070
LOG(("nsIOService::SetOffline offline=%d\n", offline));
1071
// When someone wants to go online (!offline) after we got XPCOM shutdown
1072
// throw ERROR_NOT_AVAILABLE to prevent return to online state.
1073
if ((mShutdown || mOfflineForProfileChange) && !offline)
1074
return NS_ERROR_NOT_AVAILABLE;
1075
1076
// SetOffline() may re-enter while it's shutting down services.
1077
// If that happens, save the most recent value and it will be
1078
// processed when the first SetOffline() call is done bringing
1079
// down the service.
1080
mSetOfflineValue = offline;
1081
if (mSettingOffline) {
1082
return NS_OK;
1083
}
1084
1085
mSettingOffline = true;
1086
1087
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1088
1089
NS_ASSERTION(observerService, "The observer service should not be null");
1090
1091
if (XRE_IsParentProcess()) {
1092
if (observerService) {
1093
(void)observerService->NotifyObservers(nullptr,
1094
NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
1095
offline ? u"true" : u"false");
1096
}
1097
}
1098
1099
nsIIOService* subject = static_cast<nsIIOService*>(this);
1100
while (mSetOfflineValue != mOffline) {
1101
offline = mSetOfflineValue;
1102
1103
if (offline && !mOffline) {
1104
mOffline = true; // indicate we're trying to shutdown
1105
1106
// don't care if notifications fail
1107
if (observerService)
1108
observerService->NotifyObservers(subject,
1109
NS_IOSERVICE_GOING_OFFLINE_TOPIC,
1110
u"" NS_IOSERVICE_OFFLINE);
1111
1112
if (mSocketTransportService) mSocketTransportService->SetOffline(true);
1113
1114
mLastOfflineStateChange = PR_IntervalNow();
1115
if (observerService)
1116
observerService->NotifyObservers(subject,
1117
NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1118
u"" NS_IOSERVICE_OFFLINE);
1119
} else if (!offline && mOffline) {
1120
// go online
1121
InitializeSocketTransportService();
1122
mOffline = false; // indicate success only AFTER we've
1123
// brought up the services
1124
1125
mLastOfflineStateChange = PR_IntervalNow();
1126
// don't care if notification fails
1127
// Only send the ONLINE notification if there is connectivity
1128
if (observerService && mConnectivity) {
1129
observerService->NotifyObservers(subject,
1130
NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1131
(u"" NS_IOSERVICE_ONLINE));
1132
}
1133
}
1134
}
1135
1136
// Don't notify here, as the above notifications (if used) suffice.
1137
if ((mShutdown || mOfflineForProfileChange) && mOffline) {
1138
if (mSocketTransportService) {
1139
DebugOnly<nsresult> rv = mSocketTransportService->Shutdown(mShutdown);
1140
NS_ASSERTION(NS_SUCCEEDED(rv),
1141
"socket transport service shutdown failed");
1142
}
1143
}
1144
1145
mSettingOffline = false;
1146
1147
return NS_OK;
1148
}
1149
1150
NS_IMETHODIMP
1151
nsIOService::GetConnectivity(bool* aConnectivity) {
1152
*aConnectivity = mConnectivity;
1153
return NS_OK;
1154
}
1155
1156
NS_IMETHODIMP
1157
nsIOService::SetConnectivity(bool aConnectivity) {
1158
LOG(("nsIOService::SetConnectivity aConnectivity=%d\n", aConnectivity));
1159
// This should only be called from ContentChild to pass the connectivity
1160
// value from the chrome process to the content process.
1161
if (XRE_IsParentProcess()) {
1162
return NS_ERROR_NOT_AVAILABLE;
1163
}
1164
return SetConnectivityInternal(aConnectivity);
1165
}
1166
1167
nsresult nsIOService::SetConnectivityInternal(bool aConnectivity) {
1168
LOG(("nsIOService::SetConnectivityInternal aConnectivity=%d\n",
1169
aConnectivity));
1170
if (mConnectivity == aConnectivity) {
1171
// Nothing to do here.
1172
return NS_OK;
1173
}
1174
mConnectivity = aConnectivity;
1175
1176
// This is used for PR_Connect PR_Close telemetry so it is important that
1177
// we have statistic about network change event even if we are offline.
1178
mLastConnectivityChange = PR_IntervalNow();
1179
1180
if (mCaptivePortalService) {
1181
if (aConnectivity && gCaptivePortalEnabled) {
1182
// This will also trigger a captive portal check for the new network
1183
static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start();
1184
} else {
1185
static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1186
}
1187
}
1188
1189
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1190
if (!observerService) {
1191
return NS_OK;
1192
}
1193
// This notification sends the connectivity to the child processes
1194
if (XRE_IsParentProcess()) {
1195
observerService->NotifyObservers(nullptr,
1196
NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
1197
aConnectivity ? u"true" : u"false");
1198
}
1199
1200
if (mOffline) {
1201
// We don't need to send any notifications if we're offline
1202
return NS_OK;
1203
}
1204
1205
if (aConnectivity) {
1206
// If we were previously offline due to connectivity=false,
1207
// send the ONLINE notification
1208
observerService->NotifyObservers(static_cast<nsIIOService*>(this),
1209
NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1210
(u"" NS_IOSERVICE_ONLINE));
1211
} else {
1212
// If we were previously online and lost connectivity
1213
// send the OFFLINE notification
1214
observerService->NotifyObservers(static_cast<nsIIOService*>(this),
1215
NS_IOSERVICE_GOING_OFFLINE_TOPIC,
1216
u"" NS_IOSERVICE_OFFLINE);
1217
observerService->NotifyObservers(static_cast<nsIIOService*>(this),
1218
NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1219
u"" NS_IOSERVICE_OFFLINE);
1220
}
1221
return NS_OK;
1222
}
1223
1224
NS_IMETHODIMP
1225
nsIOService::AllowPort(int32_t inPort, const char* scheme, bool* _retval) {
1226
int32_t port = inPort;
1227
if (port == -1) {
1228
*_retval = true;
1229
return NS_OK;
1230
}
1231
1232
if (port == 0) {
1233
*_retval = false;
1234
return NS_OK;
1235
}
1236
1237
// first check to see if the port is in our blacklist:
1238
int32_t badPortListCnt = mRestrictedPortList.Length();
1239
for (int i = 0; i < badPortListCnt; i++) {
1240
if (port == mRestrictedPortList[i]) {
1241
*_retval = false;
1242
1243
// check to see if the protocol wants to override
1244
if (!scheme) return NS_OK;
1245
1246
nsCOMPtr<nsIProtocolHandler> handler;
1247
nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler));
1248
if (NS_FAILED(rv)) return rv;
1249
1250
// let the protocol handler decide
1251
return handler->AllowPort(port, scheme, _retval);
1252
}
1253
}
1254
1255
*_retval = true;
1256
return NS_OK;
1257
}
1258
1259
////////////////////////////////////////////////////////////////////////////////
1260
1261
// static
1262
void nsIOService::PrefsChanged(const char* pref, void* self) {
1263
static_cast<nsIOService*>(self)->PrefsChanged(pref);
1264
}
1265
1266
void nsIOService::PrefsChanged(const char* pref) {
1267
// Look for extra ports to block
1268
if (!pref || strcmp(pref, PORT_PREF("banned")) == 0)
1269
ParsePortList(PORT_PREF("banned"), false);
1270
1271
// ...as well as previous blocks to remove.
1272
if (!pref || strcmp(pref, PORT_PREF("banned.override")) == 0)
1273
ParsePortList(PORT_PREF("banned.override"), true);
1274
1275
if (!pref || strcmp(pref, MANAGE_OFFLINE_STATUS_PREF) == 0) {
1276
bool manage;
1277
if (mNetworkLinkServiceInitialized &&
1278
NS_SUCCEEDED(
1279
Preferences::GetBool(MANAGE_OFFLINE_STATUS_PREF, &manage))) {
1280
LOG(("nsIOService::PrefsChanged ManageOfflineStatus manage=%d\n",
1281
manage));
1282
SetManageOfflineStatus(manage);
1283
}
1284
}
1285
1286
if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_COUNT_PREF) == 0) {
1287
int32_t count;
1288
if (NS_SUCCEEDED(
1289
Preferences::GetInt(NECKO_BUFFER_CACHE_COUNT_PREF, &count)))
1290
/* check for bogus values and default if we find such a value */
1291
if (count > 0) gDefaultSegmentCount = count;
1292
}
1293
1294
if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_SIZE_PREF) == 0) {
1295
int32_t size;
1296
if (NS_SUCCEEDED(Preferences::GetInt(NECKO_BUFFER_CACHE_SIZE_PREF, &size)))
1297
/* check for bogus values and default if we find such a value
1298
* the upper limit here is arbitrary. having a 1mb segment size
1299
* is pretty crazy. if you remove this, consider adding some
1300
* integer rollover test.
1301
*/
1302
if (size > 0 && size < 1024 * 1024) gDefaultSegmentSize = size;
1303
NS_WARNING_ASSERTION(!(size & (size - 1)),
1304
"network segment size is not a power of 2!");
1305
}
1306
1307
if (!pref || strcmp(pref, NETWORK_CAPTIVE_PORTAL_PREF) == 0) {
1308
nsresult rv = Preferences::GetBool(NETWORK_CAPTIVE_PORTAL_PREF,
1309
&gCaptivePortalEnabled);
1310
if (NS_SUCCEEDED(rv) && mCaptivePortalService) {
1311
if (gCaptivePortalEnabled) {
1312
static_cast<CaptivePortalService*>(mCaptivePortalService.get())
1313
->Start();
1314
} else {
1315
static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1316
}
1317
}
1318
}
1319
}
1320
1321
void nsIOService::ParsePortList(const char* pref, bool remove) {
1322
nsAutoCString portList;
1323
1324
// Get a pref string and chop it up into a list of ports.
1325
Preferences::GetCString(pref, portList);
1326
if (!portList.IsVoid()) {
1327
nsTArray<nsCString> portListArray;
1328
ParseString(portList, ',', portListArray);
1329
uint32_t index;
1330
for (index = 0; index < portListArray.Length(); index++) {
1331
portListArray[index].StripWhitespace();
1332
int32_t portBegin, portEnd;
1333
1334
if (PR_sscanf(portListArray[index].get(), "%d-%d", &portBegin,
1335
&portEnd) == 2) {
1336
if ((portBegin < 65536) && (portEnd < 65536)) {
1337
int32_t curPort;
1338
if (remove) {
1339
for (curPort = portBegin; curPort <= portEnd; curPort++)
1340
mRestrictedPortList.RemoveElement(curPort);
1341
} else {
1342
for (curPort = portBegin; curPort <= portEnd; curPort++)
1343
mRestrictedPortList.AppendElement(curPort);
1344
}
1345
}
1346
} else {
1347
nsresult aErrorCode;
1348
int32_t port = portListArray[index].ToInteger(&aErrorCode);
1349
if (NS_SUCCEEDED(aErrorCode) && port < 65536) {
1350
if (remove)
1351
mRestrictedPortList.RemoveElement(port);
1352
else
1353
mRestrictedPortList.AppendElement(port);
1354
}
1355
}
1356
}
1357
}
1358
}
1359
1360
class nsWakeupNotifier : public Runnable {
1361
public:
1362
explicit nsWakeupNotifier(nsIIOServiceInternal* ioService)
1363
: Runnable("net::nsWakeupNotifier"), mIOService(ioService) {}
1364
1365
NS_IMETHOD Run() override { return mIOService->NotifyWakeup(); }
1366
1367
private:
1368
virtual ~nsWakeupNotifier() = default;
1369
nsCOMPtr<nsIIOServiceInternal> mIOService;
1370
};
1371
1372
NS_IMETHODIMP
1373
nsIOService::NotifyWakeup() {
1374
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1375
1376
NS_ASSERTION(observerService, "The observer service should not be null");
1377
1378
if (observerService && StaticPrefs::network_notify_changed()) {
1379
(void)observerService->NotifyObservers(nullptr, NS_NETWORK_LINK_TOPIC,
1380
(u"" NS_NETWORK_LINK_DATA_CHANGED));
1381
}
1382
1383
RecheckCaptivePortal();
1384
1385
return NS_OK;
1386
}
1387
1388
void nsIOService::SetHttpHandlerAlreadyShutingDown() {
1389
if (!mShutdown && !mOfflineForProfileChange) {
1390
mNetTearingDownStarted = PR_IntervalNow();
1391
mHttpHandlerAlreadyShutingDown = true;
1392
}
1393
}
1394
1395
// nsIObserver interface
1396
NS_IMETHODIMP
1397
nsIOService::Observe(nsISupports* subject, const char* topic,
1398
const char16_t* data) {
1399
if (!strcmp(topic, kProfileChangeNetTeardownTopic)) {
1400
if (!mHttpHandlerAlreadyShutingDown) {
1401
mNetTearingDownStarted = PR_IntervalNow();
1402
}
1403
mHttpHandlerAlreadyShutingDown = false;
1404
if (!mOffline) {
1405
mOfflineForProfileChange = true;
1406
SetOffline(true);
1407
}
1408
} else if (!strcmp(topic, kProfileChangeNetRestoreTopic)) {
1409
if (mOfflineForProfileChange) {
1410
mOfflineForProfileChange = false;
1411
SetOffline(false);
1412
}
1413
} else if (!strcmp(topic, kProfileDoChange)) {
1414
if (!data) {
1415
return NS_OK;
1416
}
1417
if (NS_LITERAL_STRING("startup").Equals(data)) {
1418
// Lazy initialization of network link service (see bug 620472)
1419
InitializeNetworkLinkService();
1420
// Set up the initilization flag regardless the actuall result.
1421
// If we fail here, we will fail always on.
1422
mNetworkLinkServiceInitialized = true;
1423
1424
// And now reflect the preference setting
1425
PrefsChanged(MANAGE_OFFLINE_STATUS_PREF);
1426
1427
// Bug 870460 - Read cookie database at an early-as-possible time
1428
// off main thread. Hence, we have more chance to finish db query
1429
// before something calls into the cookie service.
1430
nsCOMPtr<nsISupports> cookieServ =
1431
do_GetService(NS_COOKIESERVICE_CONTRACTID);
1432
} else if (NS_LITERAL_STRING("xpcshell-do-get-profile").Equals(data)) {
1433
// xpcshell doesn't read user profile.
1434
LaunchSocketProcess();
1435
}
1436
} else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
1437
// Remember we passed XPCOM shutdown notification to prevent any
1438
// changes of the offline status from now. We must not allow going
1439
// online after this point.
1440
mShutdown = true;
1441
1442
if (!mHttpHandlerAlreadyShutingDown && !mOfflineForProfileChange) {
1443
mNetTearingDownStarted = PR_IntervalNow();
1444
}
1445
mHttpHandlerAlreadyShutingDown = false;
1446
1447
SetOffline(true);
1448
1449
if (mCaptivePortalService) {
1450
static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1451
mCaptivePortalService = nullptr;
1452
}
1453
1454
SSLTokensCache::Shutdown();
1455
1456
DestroySocketProcess();
1457
} else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
1458
OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get());
1459
} else if (!strcmp(topic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
1460
// coming back alive from sleep
1461
// this indirection brought to you by:
1463
nsCOMPtr<nsIRunnable> wakeupNotifier = new nsWakeupNotifier(this);
1464
NS_DispatchToMainThread(wakeupNotifier);
1465
} else if (!strcmp(topic, NS_PREFSERVICE_READ_TOPIC_ID)) {
1466
// Launch socket process after we load user's pref. This is to make sure
1467
// that socket process can get the latest prefs.
1468
LaunchSocketProcess();
1469
}
1470
1471
return NS_OK;
1472
}
1473
1474
// nsINetUtil interface
1475
NS_IMETHODIMP
1476
nsIOService::ParseRequestContentType(const nsACString& aTypeHeader,
1477
nsACString& aCharset, bool* aHadCharset,
1478
nsACString& aContentType) {
1479
net_ParseRequestContentType(aTypeHeader, aContentType, aCharset, aHadCharset);
1480
return NS_OK;
1481
}
1482
1483
// nsINetUtil interface
1484
NS_IMETHODIMP
1485
nsIOService::ParseResponseContentType(const nsACString& aTypeHeader,
1486
nsACString& aCharset, bool* aHadCharset,
1487
nsACString& aContentType) {
1488
net_ParseContentType(aTypeHeader, aContentType, aCharset, aHadCharset);
1489
return NS_OK;
1490
}
1491
1492
NS_IMETHODIMP
1493
nsIOService::ProtocolHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
1494
NS_ENSURE_ARG(uri);
1495
1496
*result = false;
1497
nsAutoCString scheme;
1498
nsresult rv = uri->GetScheme(scheme);
1499
NS_ENSURE_SUCCESS(rv, rv);
1500
1501
// Grab the protocol flags from the URI.
1502
uint32_t protocolFlags;
1503
nsCOMPtr<nsIProtocolHandler> handler;
1504
rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
1505
NS_ENSURE_SUCCESS(rv, rv);
1506
rv = handler->DoGetProtocolFlags(uri, &protocolFlags);
1507
NS_ENSURE_SUCCESS(rv, rv);
1508
1509
*result = (protocolFlags & flags) == flags;
1510
return NS_OK;
1511
}
1512
1513
NS_IMETHODIMP
1514
nsIOService::URIChainHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
1515
nsresult rv = ProtocolHasFlags(uri, flags, result);
1516
NS_ENSURE_SUCCESS(rv, rv);
1517
1518
if (*result) {
1519
return rv;
1520
}
1521
1522
// Dig deeper into the chain. Note that this is not a do/while loop to
1523
// avoid the extra addref/release on |uri| in the common (non-nested) case.
1524
nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri);
1525
while (nestedURI) {
1526
nsCOMPtr<nsIURI> innerURI;
1527
rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI));
1528
NS_ENSURE_SUCCESS(rv, rv);
1529
1530
rv = ProtocolHasFlags(innerURI, flags, result);
1531
1532
if (*result) {
1533
return rv;
1534
}
1535
1536
nestedURI = do_QueryInterface(innerURI);
1537
}
1538
1539
return rv;
1540
}
1541
1542
NS_IMETHODIMP
1543
nsIOService::SetManageOfflineStatus(bool aManage) {
1544
LOG(("nsIOService::SetManageOfflineStatus aManage=%d\n", aManage));
1545
mManageLinkStatus = aManage;
1546
1547
// When detection is not activated, the default connectivity state is true.
1548
if (!mManageLinkStatus) {
1549
SetConnectivityInternal(true);
1550
return NS_OK;
1551
}
1552
1553
InitializeNetworkLinkService();
1554
// If the NetworkLinkService is already initialized, it does not call
1555
// OnNetworkLinkEvent. This is needed, when mManageLinkStatus goes from
1556
// false to true.
1557
OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
1558
return NS_OK;
1559
}
1560
1561
NS_IMETHODIMP
1562
nsIOService::GetManageOfflineStatus(bool* aManage) {
1563
*aManage = mManageLinkStatus;
1564
return NS_OK;
1565
}
1566
1567
// input argument 'data' is already UTF8'ed
1568
nsresult nsIOService::OnNetworkLinkEvent(const char* data) {
1569
if (IsNeckoChild() || IsSocketProcessChild()) {
1570
// There is nothing IO service could do on the child process
1571
// with this at the moment. Feel free to add functionality
1572
// here at will, though.
1573
return NS_OK;
1574
}
1575
1576
if (mShutdown) {
1577
return NS_ERROR_NOT_AVAILABLE;
1578
}
1579
1580
nsCString dataAsString(data);
1581
for (auto* cp : mozilla::dom::ContentParent::AllProcesses(
1582
mozilla::dom::ContentParent::eLive)) {
1583
PNeckoParent* neckoParent = SingleManagedOrNull(cp->ManagedPNeckoParent());
1584
if (!neckoParent) {
1585
continue;
1586
}
1587
Unused << neckoParent->SendNetworkChangeNotification(dataAsString);
1588
}
1589
1590
LOG(("nsIOService::OnNetworkLinkEvent data:%s\n", data));
1591
if (!mNetworkLinkService) {
1592
return NS_ERROR_FAILURE;
1593
}
1594
1595
if (!mManageLinkStatus) {
1596
LOG(("nsIOService::OnNetworkLinkEvent mManageLinkStatus=false\n"));
1597
return NS_OK;
1598
}
1599
1600
bool isUp = true;
1601
if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) {
1602
mLastNetworkLinkChange = PR_IntervalNow();
1603
// CHANGED means UP/DOWN didn't change
1604
// but the status of the captive portal may have changed.
1605
RecheckCaptivePortal();
1606
return NS_OK;
1607
}
1608
if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
1609
isUp = false;
1610
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_UP)) {
1611
isUp = true;
1612
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_UNKNOWN)) {
1613
nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp);
1614
NS_ENSURE_SUCCESS(rv, rv);
1615
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_NETWORKID_CHANGED)) {
1616
LOG(("nsIOService::OnNetworkLinkEvent Network id changed"));
1617
} else {
1618
NS_WARNING("Unhandled network event!");
1619
return NS_OK;
1620
}
1621
1622
return SetConnectivityInternal(isUp);
1623
}
1624
1625
NS_IMETHODIMP
1626
nsIOService::EscapeString(const nsACString& aString, uint32_t aEscapeType,
1627
nsACString& aResult) {
1628
NS_ENSURE_ARG_MAX(aEscapeType, 4);
1629
1630
nsAutoCString stringCopy(aString);
1631
nsCString result;
1632
1633
if (!NS_Escape(stringCopy, result, (nsEscapeMask)aEscapeType))
1634
return NS_ERROR_OUT_OF_MEMORY;
1635
1636
aResult.Assign(result);
1637
1638
return NS_OK;
1639
}
1640
1641
NS_IMETHODIMP
1642
nsIOService::EscapeURL(const nsACString& aStr, uint32_t aFlags,
1643
nsACString& aResult) {
1644
aResult.Truncate();
1645
NS_EscapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy,
1646
aResult);
1647
return NS_OK;
1648
}
1649
1650
NS_IMETHODIMP
1651
nsIOService::UnescapeString(const nsACString& aStr, uint32_t aFlags,
1652
nsACString& aResult) {
1653
aResult.Truncate();
1654
NS_UnescapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy,
1655
aResult);
1656
return NS_OK;
1657
}
1658
1659
NS_IMETHODIMP
1660
nsIOService::ExtractCharsetFromContentType(const nsACString& aTypeHeader,
1661
nsACString& aCharset,
1662
int32_t* aCharsetStart,
1663
int32_t* aCharsetEnd,
1664
bool* aHadCharset) {
1665
nsAutoCString ignored;
1666
net_ParseContentType(aTypeHeader, ignored, aCharset, aHadCharset,
1667
aCharsetStart, aCharsetEnd);
1668
if (*aHadCharset && *aCharsetStart == *aCharsetEnd) {
1669
*aHadCharset = false;
1670
}
1671
return NS_OK;
1672
}
1673
1674
// nsISpeculativeConnect
1675
class IOServiceProxyCallback final : public nsIProtocolProxyCallback {
1676
~IOServiceProxyCallback() = default;
1677
1678
public:
1679
NS_DECL_ISUPPORTS
1680
NS_DECL_NSIPROTOCOLPROXYCALLBACK
1681
1682
IOServiceProxyCallback(nsIInterfaceRequestor* aCallbacks,
1683
nsIOService* aIOService)
1684
: mCallbacks(aCallbacks), mIOService(aIOService) {}
1685
1686
private:
1687
RefPtr<nsIInterfaceRequestor> mCallbacks;
1688
RefPtr<nsIOService> mIOService;
1689
};
1690
1691
NS_IMPL_ISUPPORTS(IOServiceProxyCallback, nsIProtocolProxyCallback)
1692
1693
NS_IMETHODIMP
1694
IOServiceProxyCallback::OnProxyAvailable(nsICancelable* request,
1695
nsIChannel* channel, nsIProxyInfo* pi,
1696
nsresult status) {
1697
// Checking proxy status for speculative connect
1698
nsAutoCString type;
1699
if (NS_SUCCEEDED(status) && pi && NS_SUCCEEDED(pi->GetType(type)) &&
1700
!type.EqualsLiteral("direct")) {
1701
// proxies dont do speculative connect
1702
return NS_OK;
1703
}
1704
1705
nsCOMPtr<nsIURI> uri;
1706
nsresult rv = channel->GetURI(getter_AddRefs(uri));
1707
if (NS_FAILED(rv)) {
1708
return NS_OK;
1709
}
1710
1711
nsAutoCString scheme;
1712
rv = uri->GetScheme(scheme);
1713
if (NS_FAILED(rv)) return NS_OK;
1714
1715
nsCOMPtr<nsIProtocolHandler> handler;
1716
rv = mIOService->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
1717
if (NS_FAILED(rv)) return NS_OK;
1718
1719
nsCOMPtr<nsISpeculativeConnect> speculativeHandler =
1720
do_QueryInterface(handler);
1721
if (!speculativeHandler) return NS_OK;
1722
1723
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
1724
nsCOMPtr<nsIPrincipal> principal = loadInfo->LoadingPrincipal();
1725
1726
nsLoadFlags loadFlags = 0;
1727
channel->GetLoadFlags(&loadFlags);
1728
if (loadFlags & nsIRequest::LOAD_ANONYMOUS) {
1729
speculativeHandler->SpeculativeAnonymousConnect(uri, principal, mCallbacks);
1730
} else {
1731
speculativeHandler->SpeculativeConnect(uri, principal, mCallbacks);
1732
}
1733
1734
return NS_OK;
1735
}
1736
1737
nsresult nsIOService::SpeculativeConnectInternal(
1738
nsIURI* aURI, nsIPrincipal* aPrincipal, nsIInterfaceRequestor* aCallbacks,
1739
bool aAnonymous) {
1740
NS_ENSURE_ARG(aURI);
1741
1742
if (!aURI->SchemeIs("http") && !aURI->SchemeIs("https")) {
1743
// We don't speculatively connect to non-HTTP[S] URIs.
1744
return NS_OK;
1745
}
1746
1747
if (IsNeckoChild()) {
1748
ipc::URIParams params;
1749
SerializeURI(aURI, params);
1750
gNeckoChild->SendSpeculativeConnect(params, IPC::Principal(aPrincipal),
1751
aAnonymous);
1752
return NS_OK;
1753
}
1754
1755
// Check for proxy information. If there is a proxy configured then a
1756
// speculative connect should not be performed because the potential
1757
// reward is slim with tcp peers closely located to the browser.
1758
nsresult rv;
1759
nsCOMPtr<nsIProtocolProxyService> pps =
1760
do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
1761
NS_ENSURE_SUCCESS(rv, rv);
1762
1763
nsCOMPtr<nsIPrincipal> loadingPrincipal = aPrincipal;
1764
1765
MOZ_ASSERT(aPrincipal, "We expect passing a principal here.");
1766
1767
if (!aPrincipal) {
1768
return NS_ERROR_INVALID_ARG;
1769
}
1770
1771
// dummy channel used to create a TCP connection.
1772
// we perform security checks on the *real* channel, responsible
1773
// for any network loads. this real channel just checks the TCP
1774
// pool if there is an available connection created by the
1775
// channel we create underneath - hence it's safe to use
1776
// the systemPrincipal as the loadingPrincipal for this channel.
1777
nsCOMPtr<nsIChannel> channel;
1778
rv = NewChannelFromURI(aURI,
1779
nullptr, // aLoadingNode,
1780
loadingPrincipal,
1781
nullptr, // aTriggeringPrincipal,
1782
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
1783
nsIContentPolicy::TYPE_SPECULATIVE,
1784
getter_AddRefs(channel));
1785
NS_ENSURE_SUCCESS(rv, rv);
1786
1787
if (aAnonymous) {
1788
nsLoadFlags loadFlags = 0;
1789
channel->GetLoadFlags(&