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