nsIOService.cpp (81118B)
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 "netCore.h" 16 #include "nsIObserverService.h" 17 #include "nsXPCOM.h" 18 #include "nsIProxiedProtocolHandler.h" 19 #include "nsIProxyInfo.h" 20 #include "nsDNSService2.h" 21 #include "nsEscape.h" 22 #include "nsNetUtil.h" 23 #include "nsNetCID.h" 24 #include "nsCRT.h" 25 #include "nsSimpleNestedURI.h" 26 #include "nsSocketTransport2.h" 27 #include "nsTArray.h" 28 #include "nsIUploadChannel2.h" 29 #include "nsXULAppAPI.h" 30 #include "nsIProtocolProxyCallback.h" 31 #include "nsICancelable.h" 32 #include "nsINetworkLinkService.h" 33 #include "nsAsyncRedirectVerifyHelper.h" 34 #include "nsURLHelper.h" 35 #include "nsIProtocolProxyService2.h" 36 #include "MainThreadUtils.h" 37 #include "nsINode.h" 38 #include "nsIWebTransport.h" 39 #include "nsIWidget.h" 40 #include "nsThreadUtils.h" 41 #include "WebTransportSessionProxy.h" 42 #include "mozilla/AppShutdown.h" 43 #include "mozilla/Components.h" 44 #include "mozilla/LoadInfo.h" 45 #include "mozilla/net/NeckoCommon.h" 46 #include "mozilla/Services.h" 47 #include "mozilla/net/DNS.h" 48 #include "mozilla/ipc/URIUtils.h" 49 #include "mozilla/net/CacheControlParser.h" 50 #include "mozilla/net/NeckoChild.h" 51 #include "mozilla/net/NeckoParent.h" 52 #include "mozilla/dom/ChromeUtilsBinding.h" 53 #include "mozilla/dom/ClientInfo.h" 54 #include "mozilla/dom/ContentParent.h" 55 #include "mozilla/dom/nsHTTPSOnlyUtils.h" 56 #include "mozilla/dom/ServiceWorkerDescriptor.h" 57 #include "mozilla/net/CaptivePortalService.h" 58 #include "mozilla/net/NetworkConnectivityService.h" 59 #include "mozilla/net/SocketProcessHost.h" 60 #include "mozilla/net/SocketProcessParent.h" 61 #include "mozilla/net/SSLTokensCache.h" 62 #include "mozilla/StoragePrincipalHelper.h" 63 #include "nsContentSecurityManager.h" 64 #include "nsContentUtils.h" 65 #include "mozilla/StaticPrefs_network.h" 66 #include "mozilla/StaticPrefs_security.h" 67 #include "mozilla/glean/NetwerkMetrics.h" 68 #include "nsNSSComponent.h" 69 #include "IPv4Parser.h" 70 #include "ssl.h" 71 #include "StaticComponents.h" 72 #include "SuspendableChannelWrapper.h" 73 74 #ifdef MOZ_WIDGET_ANDROID 75 # include <regex> 76 # include "AndroidBridge.h" 77 # include "mozilla/java/GeckoAppShellWrappers.h" 78 # include "mozilla/jni/Utils.h" 79 #endif 80 81 namespace mozilla { 82 namespace net { 83 84 using mozilla::Maybe; 85 using mozilla::dom::ClientInfo; 86 using mozilla::dom::ServiceWorkerDescriptor; 87 88 #define PORT_PREF_PREFIX "network.security.ports." 89 #define PORT_PREF(x) PORT_PREF_PREFIX x 90 #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status" 91 92 // Nb: these have been misnomers since bug 715770 removed the buffer cache. 93 // "network.segment.count" and "network.segment.size" would be better names, 94 // but the old names are still used to preserve backward compatibility. 95 #define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count" 96 #define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size" 97 #define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled" 98 #define WEBRTC_PREF_PREFIX "media.peerconnection." 99 #define NETWORK_DNS_PREF "network.dns." 100 #define FORCE_EXTERNAL_PREF_PREFIX "network.protocol-handler.external." 101 // prefs for overriding IPAddress->IpAddressSpace mapping 102 #define PREF_LNA_IP_ADDR_SPACE_PUBLIC \ 103 "network.lna.address_space.public.override" 104 #define PREF_LNA_IP_ADDR_SPACE_PRIVATE \ 105 "network.lna.address_space.private.override" 106 #define PREF_LNA_IP_ADDR_SPACE_LOCAL "network.lna.address_space.local.override" 107 #define PREF_LNA_SKIP_DOMAINS "network.lna.skip-domains" 108 109 nsIOService* gIOService; 110 static bool gCaptivePortalEnabled = false; 111 static LazyLogModule gIOServiceLog("nsIOService"); 112 #undef LOG 113 #define LOG(args) MOZ_LOG(gIOServiceLog, LogLevel::Debug, args) 114 115 // A general port blacklist. Connections to these ports will not be allowed 116 // unless the protocol overrides. 117 // 118 // This list is to be kept in sync with "bad ports" as defined in the 119 // WHATWG Fetch standard at <https://fetch.spec.whatwg.org/#port-blocking> 120 121 int16_t gBadPortList[] = { 122 1, // tcpmux 123 7, // echo 124 9, // discard 125 11, // systat 126 13, // daytime 127 15, // netstat 128 17, // qotd 129 19, // chargen 130 20, // ftp-data 131 21, // ftp 132 22, // ssh 133 23, // telnet 134 25, // smtp 135 37, // time 136 42, // name 137 43, // nicname 138 53, // domain 139 69, // tftp 140 77, // priv-rjs 141 79, // finger 142 87, // ttylink 143 95, // supdup 144 101, // hostriame 145 102, // iso-tsap 146 103, // gppitnp 147 104, // acr-nema 148 109, // pop2 149 110, // pop3 150 111, // sunrpc 151 113, // auth 152 115, // sftp 153 117, // uucp-path 154 119, // nntp 155 123, // ntp 156 135, // loc-srv / epmap 157 137, // netbios 158 139, // netbios 159 143, // imap2 160 161, // snmp 161 179, // bgp 162 389, // ldap 163 427, // afp (alternate) 164 465, // smtp (alternate) 165 512, // print / exec 166 513, // login 167 514, // shell 168 515, // printer 169 526, // tempo 170 530, // courier 171 531, // chat 172 532, // netnews 173 540, // uucp 174 548, // afp 175 554, // rtsp 176 556, // remotefs 177 563, // nntp+ssl 178 587, // smtp (outgoing) 179 601, // syslog-conn 180 636, // ldap+ssl 181 989, // ftps-data 182 990, // ftps 183 993, // imap+ssl 184 995, // pop3+ssl 185 1719, // h323gatestat 186 1720, // h323hostcall 187 1723, // pptp 188 2049, // nfs 189 3659, // apple-sasl 190 4045, // lockd 191 4190, // sieve 192 5060, // sip 193 5061, // sips 194 6000, // x11 195 6566, // sane-port 196 6665, // irc (alternate) 197 6666, // irc (alternate) 198 6667, // irc (default) 199 6668, // irc (alternate) 200 6669, // irc (alternate) 201 6679, // osaut 202 6697, // irc+tls 203 10080, // amanda 204 0, // Sentinel value: This MUST be zero 205 }; 206 207 static const char kProfileChangeNetTeardownTopic[] = 208 "profile-change-net-teardown"; 209 static const char kProfileChangeNetRestoreTopic[] = 210 "profile-change-net-restore"; 211 static const char kProfileDoChange[] = "profile-do-change"; 212 213 // Necko buffer defaults 214 uint32_t nsIOService::gDefaultSegmentSize = 4096; 215 uint32_t nsIOService::gDefaultSegmentCount = 24; 216 217 uint32_t nsIOService::sSocketProcessCrashedCount = 0; 218 219 //////////////////////////////////////////////////////////////////////////////// 220 221 nsIOService::nsIOService() 222 : mLastOfflineStateChange(PR_IntervalNow()), 223 mLastConnectivityChange(PR_IntervalNow()), 224 mLastNetworkLinkChange(PR_IntervalNow()) {} 225 226 static const char* gCallbackPrefs[] = { 227 PORT_PREF_PREFIX, 228 MANAGE_OFFLINE_STATUS_PREF, 229 NECKO_BUFFER_CACHE_COUNT_PREF, 230 NECKO_BUFFER_CACHE_SIZE_PREF, 231 NETWORK_CAPTIVE_PORTAL_PREF, 232 FORCE_EXTERNAL_PREF_PREFIX, 233 SIMPLE_URI_SCHEMES_PREF, 234 PREF_LNA_IP_ADDR_SPACE_PUBLIC, 235 PREF_LNA_IP_ADDR_SPACE_PRIVATE, 236 PREF_LNA_IP_ADDR_SPACE_LOCAL, 237 PREF_LNA_SKIP_DOMAINS, 238 nullptr, 239 }; 240 241 static const char* gCallbackPrefsForSocketProcess[] = { 242 WEBRTC_PREF_PREFIX, 243 NETWORK_DNS_PREF, 244 "media.webrtc.enable_pq_hybrid_kex", 245 "media.webrtc.send_mlkem_keyshare", 246 "network.send_ODA_to_content_directly", 247 "network.trr.", 248 "doh-rollout.", 249 "network.dns.disableIPv6", 250 "network.offline-mirrors-connectivity", 251 "network.disable-localhost-when-offline", 252 "network.proxy.parse_pac_on_socket_process", 253 "network.proxy.allow_hijacking_localhost", 254 "network.proxy.testing_localhost_is_secure_when_hijacked", 255 "network.connectivity-service.", 256 "network.captive-portal-service.testMode", 257 "network.socket.ip_addr_any.disabled", 258 "network.socket.attach_mock_network_layer", 259 "network.lna.enabled", 260 "network.lna.blocking", 261 "network.lna.address_space.private.override", 262 "network.lna.address_space.public.override", 263 "network.lna.websocket.enabled", 264 "network.lna.local-network-to-localhost.skip-checks", 265 "network.socket.forcePort", 266 nullptr, 267 }; 268 269 static const char* gCallbackSecurityPrefs[] = { 270 // Note the prefs listed below should be in sync with the code in 271 // HandleTLSPrefChange(). 272 "security.tls.version.min", 273 "security.tls.version.max", 274 "security.tls.version.enable-deprecated", 275 "security.tls.hello_downgrade_check", 276 "security.ssl.require_safe_negotiation", 277 "security.ssl.enable_false_start", 278 "security.ssl.enable_alpn", 279 "security.tls.enable_0rtt_data", 280 "security.ssl.disable_session_identifiers", 281 "security.tls.enable_post_handshake_auth", 282 "security.tls.enable_delegated_credentials", 283 nullptr, 284 }; 285 286 nsresult nsIOService::Init() { 287 SSLTokensCache::Init(); 288 289 InitializeCaptivePortalService(); 290 291 // setup our bad port list stuff 292 for (int i = 0; gBadPortList[i]; i++) { 293 // We can't be accessed by another thread yet 294 MOZ_PUSH_IGNORE_THREAD_SAFETY 295 mRestrictedPortList.AppendElement(gBadPortList[i]); 296 MOZ_POP_THREAD_SAFETY 297 } 298 299 // Further modifications to the port list come from prefs 300 Preferences::RegisterPrefixCallbacks(nsIOService::PrefsChanged, 301 gCallbackPrefs, this); 302 PrefsChanged(); 303 304 mSocketProcessTopicBlockedList.Insert( 305 nsLiteralCString(NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID)); 306 mSocketProcessTopicBlockedList.Insert( 307 nsLiteralCString(NS_XPCOM_SHUTDOWN_OBSERVER_ID)); 308 mSocketProcessTopicBlockedList.Insert("xpcom-shutdown-threads"_ns); 309 mSocketProcessTopicBlockedList.Insert("profile-do-change"_ns); 310 mSocketProcessTopicBlockedList.Insert("network:socket-process-crashed"_ns); 311 312 // Register for profile change notifications 313 mObserverService = services::GetObserverService(); 314 MOZ_ALWAYS_SUCCEEDS(AddObserver(this, kProfileChangeNetTeardownTopic, true)); 315 MOZ_ALWAYS_SUCCEEDS(AddObserver(this, kProfileChangeNetRestoreTopic, true)); 316 MOZ_ALWAYS_SUCCEEDS(AddObserver(this, kProfileDoChange, true)); 317 MOZ_ALWAYS_SUCCEEDS(AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true)); 318 MOZ_ALWAYS_SUCCEEDS(AddObserver(this, NS_NETWORK_LINK_TOPIC, true)); 319 MOZ_ALWAYS_SUCCEEDS(AddObserver(this, NS_NETWORK_ID_CHANGED_TOPIC, true)); 320 MOZ_ALWAYS_SUCCEEDS(AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, true)); 321 322 // Register observers for sending notifications to nsSocketTransportService 323 if (XRE_IsParentProcess()) { 324 AddObserver(this, "profile-initial-state", true); 325 AddObserver(this, NS_WIDGET_SLEEP_OBSERVER_TOPIC, true); 326 } 327 328 if (IsSocketProcessChild()) { 329 Preferences::RegisterCallbacks(nsIOService::OnTLSPrefChange, 330 gCallbackSecurityPrefs, this); 331 } 332 333 gIOService = this; 334 335 InitializeNetworkLinkService(); 336 InitializeProtocolProxyService(); 337 SetOffline(false); 338 339 // This is just to start the DNS service to make it fast to get later. 340 // Don't invoke directly since we're already in GetService. RefPtr needed 341 // because already_AddRefed<> doesn't like to be dropped 342 NS_DispatchToCurrentThread(NS_NewRunnableFunction( 343 __func__, []() { RefPtr<nsIDNSService> dns = GetOrInitDNSService(); })); 344 345 return NS_OK; 346 } 347 348 NS_IMETHODIMP 349 nsIOService::AddObserver(nsIObserver* aObserver, const char* aTopic, 350 bool aOwnsWeak) { 351 if (!mObserverService) { 352 return NS_ERROR_FAILURE; 353 } 354 355 // Register for the origional observer. 356 nsresult rv = mObserverService->AddObserver(aObserver, aTopic, aOwnsWeak); 357 if (NS_FAILED(rv)) { 358 return rv; 359 } 360 361 if (!XRE_IsParentProcess()) { 362 return NS_OK; 363 } 364 365 nsAutoCString topic(aTopic); 366 // This happens when AddObserver() is called by nsIOService::Init(). We don't 367 // want to add nsIOService again. 368 if (SameCOMIdentity(aObserver, static_cast<nsIObserver*>(this))) { 369 mIOServiceTopicList.Insert(topic); 370 return NS_OK; 371 } 372 373 if (!UseSocketProcess()) { 374 return NS_OK; 375 } 376 377 if (mSocketProcessTopicBlockedList.Contains(topic)) { 378 return NS_ERROR_FAILURE; 379 } 380 381 // Avoid registering duplicate topics. 382 if (mObserverTopicForSocketProcess.Contains(topic)) { 383 return NS_ERROR_FAILURE; 384 } 385 386 mObserverTopicForSocketProcess.Insert(topic); 387 388 // Avoid registering duplicate topics. 389 if (mIOServiceTopicList.Contains(topic)) { 390 return NS_ERROR_FAILURE; 391 } 392 393 return mObserverService->AddObserver(this, aTopic, true); 394 } 395 396 NS_IMETHODIMP 397 nsIOService::RemoveObserver(nsIObserver* aObserver, const char* aTopic) { 398 return NS_ERROR_NOT_IMPLEMENTED; 399 } 400 401 NS_IMETHODIMP 402 nsIOService::EnumerateObservers(const char* aTopic, 403 nsISimpleEnumerator** anEnumerator) { 404 return NS_ERROR_NOT_IMPLEMENTED; 405 } 406 407 NS_IMETHODIMP nsIOService::NotifyObservers(nsISupports* aSubject, 408 const char* aTopic, 409 const char16_t* aSomeData) { 410 return NS_ERROR_NOT_IMPLEMENTED; 411 } 412 413 nsIOService::~nsIOService() { 414 if (gIOService) { 415 MOZ_ASSERT(gIOService == this); 416 gIOService = nullptr; 417 } 418 } 419 420 #ifdef MOZ_WIDGET_ANDROID 421 bool nsIOService::ShouldAddAdditionalSearchHeaders(nsIURI* aURI, 422 bool* aHeaderVal) { 423 if (!(mozilla::AndroidBridge::Bridge())) { 424 return false; 425 } 426 427 if (!aURI->SchemeIs("https")) { 428 return false; 429 } 430 431 // We need to improve below logic for matching google domains 432 // See Bug 1894642 433 // Is URI same as google ^https://www\\.google\\..+ 434 nsAutoCString host; 435 aURI->GetHost(host); 436 LOG(("nsIOService::ShouldAddAdditionalSearchHeaders() checking host %s\n", 437 PromiseFlatCString(host).get())); 438 439 std::regex pattern("^www\\.google\\..+"); 440 if (std::regex_match(host.get(), pattern)) { 441 LOG(("Google domain detected for host %s\n", 442 PromiseFlatCString(host).get())); 443 static bool ramAboveThreshold = 444 java::GeckoAppShell::IsDeviceRamThresholdOkay(); 445 *aHeaderVal = ramAboveThreshold; 446 return true; 447 } 448 449 return false; 450 } 451 #endif 452 453 // static 454 void nsIOService::OnTLSPrefChange(const char* aPref, void* aSelf) { 455 MOZ_ASSERT(IsSocketProcessChild()); 456 457 if (!EnsureNSSInitializedChromeOrContent()) { 458 LOG(("NSS not initialized.")); 459 return; 460 } 461 462 nsAutoCString pref(aPref); 463 // The preferences listed in gCallbackSecurityPrefs need to be in sync with 464 // the code in HandleTLSPrefChange(). 465 if (HandleTLSPrefChange(pref)) { 466 LOG(("HandleTLSPrefChange done")); 467 } 468 } 469 470 nsresult nsIOService::InitializeCaptivePortalService() { 471 if (XRE_GetProcessType() != GeckoProcessType_Default) { 472 // We only initalize a captive portal service in the main process 473 return NS_OK; 474 } 475 476 mCaptivePortalService = mozilla::components::CaptivePortal::Service(); 477 if (mCaptivePortalService) { 478 static_cast<CaptivePortalService*>(mCaptivePortalService.get()) 479 ->Initialize(); 480 } 481 482 // Instantiate and initialize the service 483 RefPtr<NetworkConnectivityService> ncs = 484 NetworkConnectivityService::GetSingleton(); 485 486 return NS_OK; 487 } 488 489 nsresult nsIOService::InitializeSocketTransportService() { 490 nsresult rv = NS_OK; 491 492 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) { 493 LOG( 494 ("nsIOService aborting InitializeSocketTransportService because of app " 495 "shutdown")); 496 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; 497 } 498 499 if (!mSocketTransportService) { 500 mSocketTransportService = 501 mozilla::components::SocketTransport::Service(&rv); 502 if (NS_FAILED(rv)) { 503 NS_WARNING("failed to get socket transport service"); 504 } 505 } 506 507 if (mSocketTransportService) { 508 rv = mSocketTransportService->Init(); 509 NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed"); 510 mSocketTransportService->SetOffline(false); 511 } 512 513 return rv; 514 } 515 516 nsresult nsIOService::InitializeNetworkLinkService() { 517 nsresult rv = NS_OK; 518 519 if (mNetworkLinkServiceInitialized) return rv; 520 521 if (!NS_IsMainThread()) { 522 NS_WARNING("Network link service should be created on main thread"); 523 return NS_ERROR_FAILURE; 524 } 525 526 // go into managed mode if we can, and chrome process 527 if (!XRE_IsParentProcess()) { 528 return NS_ERROR_NOT_AVAILABLE; 529 } 530 531 mNetworkLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv); 532 533 if (mNetworkLinkService) { 534 mNetworkLinkServiceInitialized = true; 535 } 536 537 // After initializing the networkLinkService, query the connectivity state 538 OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN); 539 540 return rv; 541 } 542 543 nsresult nsIOService::InitializeProtocolProxyService() { 544 nsresult rv = NS_OK; 545 546 if (XRE_IsParentProcess()) { 547 // for early-initialization 548 (void)mozilla::components::ProtocolProxy::Service(&rv); 549 } 550 551 return rv; 552 } 553 554 already_AddRefed<nsIOService> nsIOService::GetInstance() { 555 if (!gIOService) { 556 RefPtr<nsIOService> ios = new nsIOService(); 557 if (NS_SUCCEEDED(ios->Init())) { 558 MOZ_ASSERT(gIOService == ios.get()); 559 return ios.forget(); 560 } 561 } 562 return do_AddRef(gIOService); 563 } 564 565 class SocketProcessListenerProxy : public SocketProcessHost::Listener { 566 public: 567 SocketProcessListenerProxy() = default; 568 void OnProcessLaunchComplete(SocketProcessHost* aHost, bool aSucceeded) { 569 if (!gIOService) { 570 return; 571 } 572 573 gIOService->OnProcessLaunchComplete(aHost, aSucceeded); 574 } 575 576 void OnProcessUnexpectedShutdown(SocketProcessHost* aHost) { 577 if (!gIOService) { 578 return; 579 } 580 581 gIOService->OnProcessUnexpectedShutdown(aHost); 582 } 583 }; 584 585 // static 586 bool nsIOService::TooManySocketProcessCrash() { 587 return sSocketProcessCrashedCount >= 588 StaticPrefs::network_max_socket_process_failed_count(); 589 } 590 591 // static 592 void nsIOService::IncreaseSocketProcessCrashCount() { 593 MOZ_ASSERT(IsNeckoChild()); 594 sSocketProcessCrashedCount++; 595 } 596 597 nsresult nsIOService::LaunchSocketProcess() { 598 MOZ_ASSERT(NS_IsMainThread()); 599 600 if (XRE_GetProcessType() != GeckoProcessType_Default) { 601 return NS_OK; 602 } 603 604 // We shouldn't launch socket prcess when shutdown begins. 605 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) { 606 return NS_OK; 607 } 608 609 if (mSocketProcess) { 610 return NS_OK; 611 } 612 613 if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) { 614 LOG(("nsIOService skipping LaunchSocketProcess because of the env")); 615 return NS_OK; 616 } 617 618 if (!StaticPrefs::network_process_enabled()) { 619 LOG(("nsIOService skipping LaunchSocketProcess because of the pref")); 620 return NS_OK; 621 } 622 623 Preferences::RegisterPrefixCallbacks( 624 nsIOService::NotifySocketProcessPrefsChanged, 625 gCallbackPrefsForSocketProcess, this); 626 627 // The subprocess is launched asynchronously, so we wait for a callback to 628 // acquire the IPDL actor. 629 mSocketProcess = new SocketProcessHost(new SocketProcessListenerProxy()); 630 LOG(("nsIOService::LaunchSocketProcess")); 631 if (!mSocketProcess->Launch()) { 632 NS_WARNING("Failed to launch socket process!!"); 633 DestroySocketProcess(); 634 return NS_ERROR_FAILURE; 635 } 636 637 return NS_OK; 638 } 639 640 void nsIOService::DestroySocketProcess() { 641 LOG(("nsIOService::DestroySocketProcess")); 642 MOZ_ASSERT(NS_IsMainThread()); 643 644 if (XRE_GetProcessType() != GeckoProcessType_Default || !mSocketProcess) { 645 return; 646 } 647 648 Preferences::UnregisterPrefixCallbacks( 649 nsIOService::NotifySocketProcessPrefsChanged, 650 gCallbackPrefsForSocketProcess, this); 651 652 mSocketProcess->Shutdown(); 653 mSocketProcess = nullptr; 654 } 655 656 bool nsIOService::SocketProcessReady() { 657 return mSocketProcess && mSocketProcess->IsConnected(); 658 } 659 660 static bool sUseSocketProcess = false; 661 static bool sUseSocketProcessChecked = false; 662 663 // static 664 bool nsIOService::UseSocketProcess(bool aCheckAgain) { 665 if (sUseSocketProcessChecked && !aCheckAgain) { 666 return sUseSocketProcess; 667 } 668 669 sUseSocketProcessChecked = true; 670 sUseSocketProcess = false; 671 672 if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) { 673 return sUseSocketProcess; 674 } 675 676 if (TooManySocketProcessCrash()) { 677 LOG(("TooManySocketProcessCrash")); 678 return sUseSocketProcess; 679 } 680 681 if (PR_GetEnv("MOZ_FORCE_USE_SOCKET_PROCESS")) { 682 sUseSocketProcess = true; 683 return sUseSocketProcess; 684 } 685 686 if (StaticPrefs::network_process_enabled()) { 687 sUseSocketProcess = 688 StaticPrefs::network_http_network_access_on_socket_process_enabled(); 689 } 690 return sUseSocketProcess; 691 } 692 693 // static 694 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName, 695 void* aSelf) { 696 static_cast<nsIOService*>(aSelf)->NotifySocketProcessPrefsChanged(aName); 697 } 698 699 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName) { 700 MOZ_ASSERT(NS_IsMainThread()); 701 702 if (!XRE_IsParentProcess()) { 703 return; 704 } 705 706 if (!StaticPrefs::network_process_enabled()) { 707 return; 708 } 709 710 dom::Pref pref(nsCString(aName), /* isLocked */ false, 711 /* isSanitized */ false, Nothing(), Nothing()); 712 713 Preferences::GetPreference(&pref, GeckoProcessType_Socket, 714 /* remoteType */ ""_ns); 715 auto sendPrefUpdate = [pref]() { 716 (void)gIOService->mSocketProcess->GetActor()->SendPreferenceUpdate(pref); 717 }; 718 CallOrWaitForSocketProcess(sendPrefUpdate); 719 } 720 721 void nsIOService::OnProcessLaunchComplete(SocketProcessHost* aHost, 722 bool aSucceeded) { 723 MOZ_ASSERT(NS_IsMainThread()); 724 725 LOG(("nsIOService::OnProcessLaunchComplete aSucceeded=%d\n", aSucceeded)); 726 727 mSocketProcessLaunchComplete = aSucceeded; 728 729 if (mShutdown || !SocketProcessReady() || !aSucceeded) { 730 mPendingEvents.Clear(); 731 return; 732 } 733 734 if (!mPendingEvents.IsEmpty()) { 735 nsTArray<std::function<void()>> pendingEvents = std::move(mPendingEvents); 736 for (auto& func : pendingEvents) { 737 func(); 738 } 739 } 740 } 741 742 void nsIOService::CallOrWaitForSocketProcess( 743 const std::function<void()>& aFunc) { 744 MOZ_ASSERT(NS_IsMainThread()); 745 if (IsSocketProcessLaunchComplete() && SocketProcessReady()) { 746 aFunc(); 747 } else { 748 mPendingEvents.AppendElement(aFunc); // infallible 749 LaunchSocketProcess(); 750 } 751 } 752 753 int32_t nsIOService::SocketProcessPid() { 754 if (!mSocketProcess) { 755 return 0; 756 } 757 if (SocketProcessParent* actor = mSocketProcess->GetActor()) { 758 return (int32_t)actor->OtherPid(); 759 } 760 return 0; 761 } 762 763 bool nsIOService::IsSocketProcessLaunchComplete() { 764 MOZ_ASSERT(NS_IsMainThread()); 765 return mSocketProcessLaunchComplete; 766 } 767 768 void nsIOService::OnProcessUnexpectedShutdown(SocketProcessHost* aHost) { 769 MOZ_ASSERT(NS_IsMainThread()); 770 771 LOG(("nsIOService::OnProcessUnexpectedShutdown\n")); 772 DestroySocketProcess(); 773 mPendingEvents.Clear(); 774 775 // Nothing to do if socket process was not used before. 776 if (!UseSocketProcess()) { 777 return; 778 } 779 780 sSocketProcessCrashedCount++; 781 if (TooManySocketProcessCrash()) { 782 sUseSocketProcessChecked = false; 783 DNSServiceWrapper::SwitchToBackupDNSService(); 784 } 785 786 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); 787 if (observerService) { 788 (void)observerService->NotifyObservers( 789 nullptr, "network:socket-process-crashed", nullptr); 790 } 791 792 // UseSocketProcess() could return false if we have too many crashes, so we 793 // should call it again. 794 if (UseSocketProcess()) { 795 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread( 796 NewRunnableMethod("nsIOService::LaunchSocketProcess", this, 797 &nsIOService::LaunchSocketProcess))); 798 } 799 } 800 801 RefPtr<MemoryReportingProcess> nsIOService::GetSocketProcessMemoryReporter() { 802 // Check the prefs here again, since we don't want to create 803 // SocketProcessMemoryReporter for some tests. 804 if (!StaticPrefs::network_process_enabled() || !SocketProcessReady()) { 805 return nullptr; 806 } 807 808 return new SocketProcessMemoryReporter(); 809 } 810 811 NS_IMETHODIMP 812 nsIOService::SocketProcessTelemetryPing() { 813 CallOrWaitForSocketProcess([]() { 814 (void)gIOService->mSocketProcess->GetActor() 815 ->SendSocketProcessTelemetryPing(); 816 }); 817 return NS_OK; 818 } 819 820 NS_IMPL_ISUPPORTS(nsIOService, nsIIOService, nsINetUtil, nsISpeculativeConnect, 821 nsIObserver, nsIIOServiceInternal, nsISupportsWeakReference, 822 nsIObserverService) 823 824 //////////////////////////////////////////////////////////////////////////////// 825 826 nsresult nsIOService::RecheckCaptivePortal() { 827 MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread"); 828 if (!mCaptivePortalService) { 829 return NS_OK; 830 } 831 nsCOMPtr<nsIRunnable> task = NewRunnableMethod( 832 "nsIOService::RecheckCaptivePortal", mCaptivePortalService, 833 &nsICaptivePortalService::RecheckCaptivePortal); 834 return NS_DispatchToMainThread(task); 835 } 836 837 nsresult nsIOService::RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan) { 838 nsresult rv; 839 840 if (!mCaptivePortalService) { 841 return NS_OK; 842 } 843 844 nsCOMPtr<nsIURI> uri; 845 rv = newChan->GetURI(getter_AddRefs(uri)); 846 if (NS_FAILED(rv)) { 847 return rv; 848 } 849 850 nsCString host; 851 rv = uri->GetHost(host); 852 if (NS_FAILED(rv)) { 853 return rv; 854 } 855 856 NetAddr addr; 857 // If the redirect wasn't to an IP literal, so there's probably no need 858 // to trigger the captive portal detection right now. It can wait. 859 if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrLocal()) { 860 RecheckCaptivePortal(); 861 } 862 863 return NS_OK; 864 } 865 866 nsresult nsIOService::AsyncOnChannelRedirect( 867 nsIChannel* oldChan, nsIChannel* newChan, uint32_t flags, 868 nsAsyncRedirectVerifyHelper* helper) { 869 // If a redirect to a local network address occurs, then chances are we 870 // are in a captive portal, so we trigger a recheck. 871 RecheckCaptivePortalIfLocalRedirect(newChan); 872 873 // This is silly. I wish there was a simpler way to get at the global 874 // reference of the contentSecurityManager. But it lives in the XPCOM 875 // service registry. 876 nsCOMPtr<nsIChannelEventSink> sink; 877 sink = mozilla::components::ContentSecurityManager::Service(); 878 if (sink) { 879 nsresult rv = 880 helper->DelegateOnChannelRedirect(sink, oldChan, newChan, flags); 881 if (NS_FAILED(rv)) return rv; 882 } 883 884 // Finally, our category 885 nsCOMArray<nsIChannelEventSink> entries; 886 mChannelEventSinks.GetEntries(entries); 887 int32_t len = entries.Count(); 888 for (int32_t i = 0; i < len; ++i) { 889 nsresult rv = 890 helper->DelegateOnChannelRedirect(entries[i], oldChan, newChan, flags); 891 if (NS_FAILED(rv)) return rv; 892 } 893 894 nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(oldChan)); 895 896 // Collect the redirection from HTTP(S) only. 897 if (httpChan) { 898 MOZ_ASSERT(NS_IsMainThread()); 899 nsCOMPtr<nsIURI> newURI; 900 newChan->GetURI(getter_AddRefs(newURI)); 901 MOZ_ASSERT(newURI); 902 903 nsAutoCString scheme; 904 newURI->GetScheme(scheme); 905 MOZ_ASSERT(!scheme.IsEmpty()); 906 907 if (oldChan->IsDocument()) { 908 mozilla::glean::networking::http_redirect_to_scheme_top_level.Get(scheme) 909 .Add(1); 910 } else { 911 mozilla::glean::networking::http_redirect_to_scheme_subresource 912 .Get(scheme) 913 .Add(1); 914 } 915 } 916 return NS_OK; 917 } 918 919 bool nsIOService::UsesExternalProtocolHandler(const nsACString& aScheme) { 920 if (aScheme == "file"_ns || aScheme == "chrome"_ns || 921 aScheme == "resource"_ns || aScheme == "moz-src"_ns) { 922 // Don't allow file:, chrome: or resource: URIs to be handled with 923 // nsExternalProtocolHandler, since internally we rely on being able to 924 // use and read from these URIs. 925 return false; 926 } 927 928 if (aScheme == "place"_ns || aScheme == "fake-favicon-uri"_ns || 929 aScheme == "favicon"_ns || aScheme == "moz-nullprincipal"_ns) { 930 // Force place: fake-favicon-uri: favicon: and moz-nullprincipal: URIs to be 931 // handled with nsExternalProtocolHandler, and not with a dynamically 932 // registered handler. 933 return true; 934 } 935 936 // If prefs configure the URI to be handled externally, do so. 937 for (const auto& scheme : mForceExternalSchemes) { 938 if (aScheme == scheme) { 939 return true; 940 } 941 } 942 return false; 943 } 944 945 ProtocolHandlerInfo nsIOService::LookupProtocolHandler( 946 const nsACString& aScheme) { 947 // Look-ups are ASCII-case-insensitive, so lower-case the string before 948 // continuing. 949 nsAutoCString scheme(aScheme); 950 ToLowerCase(scheme); 951 952 // NOTE: If we could get rid of mForceExternalSchemes (or prevent them from 953 // disabling static protocols), we could avoid locking mLock until we need to 954 // check `mRuntimeProtocolHandlers. 955 AutoReadLock lock(mLock); 956 if (!UsesExternalProtocolHandler(scheme)) { 957 // Try the static protocol handler first - they cannot be overridden by 958 // dynamic protocols. 959 if (const xpcom::StaticProtocolHandler* handler = 960 xpcom::StaticProtocolHandler::Lookup(scheme)) { 961 return ProtocolHandlerInfo(*handler); 962 } 963 if (auto handler = mRuntimeProtocolHandlers.Lookup(scheme)) { 964 return ProtocolHandlerInfo(handler.Data()); 965 } 966 } 967 return ProtocolHandlerInfo(xpcom::StaticProtocolHandler::Default()); 968 } 969 970 NS_IMETHODIMP 971 nsIOService::GetProtocolHandler(const char* scheme, 972 nsIProtocolHandler** result) { 973 AssertIsOnMainThread(); 974 NS_ENSURE_ARG_POINTER(scheme); 975 976 *result = LookupProtocolHandler(nsDependentCString(scheme)).Handler().take(); 977 return *result ? NS_OK : NS_ERROR_UNKNOWN_PROTOCOL; 978 } 979 980 NS_IMETHODIMP 981 nsIOService::ExtractScheme(const nsACString& inURI, nsACString& scheme) { 982 return net_ExtractURLScheme(inURI, scheme); 983 } 984 985 NS_IMETHODIMP 986 nsIOService::HostnameIsLocalIPAddress(nsIURI* aURI, bool* aResult) { 987 NS_ENSURE_ARG_POINTER(aURI); 988 989 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI); 990 NS_ENSURE_ARG_POINTER(innerURI); 991 992 nsAutoCString host; 993 nsresult rv = innerURI->GetAsciiHost(host); 994 if (NS_FAILED(rv)) { 995 return rv; 996 } 997 998 *aResult = false; 999 1000 NetAddr addr; 1001 if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrLocal()) { 1002 *aResult = true; 1003 } 1004 1005 return NS_OK; 1006 } 1007 1008 NS_IMETHODIMP 1009 nsIOService::HostnameIsIPAddressAny(nsIURI* aURI, bool* aResult) { 1010 NS_ENSURE_ARG_POINTER(aURI); 1011 1012 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI); 1013 NS_ENSURE_ARG_POINTER(innerURI); 1014 1015 nsAutoCString host; 1016 nsresult rv = innerURI->GetAsciiHost(host); 1017 if (NS_FAILED(rv)) { 1018 return rv; 1019 } 1020 1021 *aResult = false; 1022 1023 NetAddr addr; 1024 if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrAny()) { 1025 *aResult = true; 1026 } 1027 1028 return NS_OK; 1029 } 1030 1031 NS_IMETHODIMP 1032 nsIOService::HostnameIsSharedIPAddress(nsIURI* aURI, bool* aResult) { 1033 NS_ENSURE_ARG_POINTER(aURI); 1034 1035 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI); 1036 NS_ENSURE_ARG_POINTER(innerURI); 1037 1038 nsAutoCString host; 1039 nsresult rv = innerURI->GetAsciiHost(host); 1040 if (NS_FAILED(rv)) { 1041 return rv; 1042 } 1043 1044 *aResult = false; 1045 1046 NetAddr addr; 1047 if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrShared()) { 1048 *aResult = true; 1049 } 1050 1051 return NS_OK; 1052 } 1053 1054 NS_IMETHODIMP 1055 nsIOService::IsValidHostname(const nsACString& inHostname, bool* aResult) { 1056 if (!net_IsValidDNSHost(inHostname)) { 1057 *aResult = false; 1058 return NS_OK; 1059 } 1060 1061 // hostname ending with a "." delimited octet that is a number 1062 // must be IPv4 or IPv6 dual address 1063 nsAutoCString host(inHostname); 1064 if (IPv4Parser::EndsInANumber(host)) { 1065 // ipv6 dual address; for example "::1.2.3.4" 1066 if (net_IsValidIPv6Addr(host)) { 1067 *aResult = true; 1068 return NS_OK; 1069 } 1070 1071 nsAutoCString normalized; 1072 nsresult rv = IPv4Parser::NormalizeIPv4(host, normalized); 1073 if (NS_FAILED(rv)) { 1074 *aResult = false; 1075 return NS_OK; 1076 } 1077 } 1078 *aResult = true; 1079 return NS_OK; 1080 } 1081 1082 NS_IMETHODIMP 1083 nsIOService::GetProtocolFlags(const char* scheme, uint32_t* flags) { 1084 NS_ENSURE_ARG_POINTER(scheme); 1085 1086 *flags = 1087 LookupProtocolHandler(nsDependentCString(scheme)).StaticProtocolFlags(); 1088 return NS_OK; 1089 } 1090 1091 NS_IMETHODIMP 1092 nsIOService::GetDynamicProtocolFlags(nsIURI* uri, uint32_t* flags) { 1093 AssertIsOnMainThread(); 1094 NS_ENSURE_ARG(uri); 1095 1096 nsAutoCString scheme; 1097 nsresult rv = uri->GetScheme(scheme); 1098 NS_ENSURE_SUCCESS(rv, rv); 1099 1100 return LookupProtocolHandler(scheme).DynamicProtocolFlags(uri, flags); 1101 } 1102 1103 NS_IMETHODIMP 1104 nsIOService::GetDefaultPort(const char* scheme, int32_t* defaultPort) { 1105 NS_ENSURE_ARG_POINTER(scheme); 1106 1107 *defaultPort = 1108 LookupProtocolHandler(nsDependentCString(scheme)).DefaultPort(); 1109 return NS_OK; 1110 } 1111 1112 nsresult nsIOService::NewURI(const nsACString& aSpec, const char* aCharset, 1113 nsIURI* aBaseURI, nsIURI** result) { 1114 return NS_NewURI(result, aSpec, aCharset, aBaseURI); 1115 } 1116 1117 NS_IMETHODIMP 1118 nsIOService::NewFileURI(nsIFile* file, nsIURI** result) { 1119 nsresult rv; 1120 NS_ENSURE_ARG_POINTER(file); 1121 1122 nsCOMPtr<nsIProtocolHandler> handler; 1123 1124 rv = GetProtocolHandler("file", getter_AddRefs(handler)); 1125 if (NS_FAILED(rv)) return rv; 1126 1127 nsCOMPtr<nsIFileProtocolHandler> fileHandler(do_QueryInterface(handler, &rv)); 1128 if (NS_FAILED(rv)) return rv; 1129 1130 return fileHandler->NewFileURI(file, result); 1131 } 1132 1133 // static 1134 already_AddRefed<nsIURI> nsIOService::CreateExposableURI(nsIURI* aURI) { 1135 MOZ_ASSERT(aURI, "Must have a URI"); 1136 nsCOMPtr<nsIURI> uri = aURI; 1137 bool hasUserPass; 1138 if (NS_SUCCEEDED(aURI->GetHasUserPass(&hasUserPass)) && hasUserPass) { 1139 DebugOnly<nsresult> rv = NS_MutateURI(uri).SetUserPass(""_ns).Finalize(uri); 1140 MOZ_ASSERT(NS_SUCCEEDED(rv) && uri, "Mutating URI should never fail"); 1141 } 1142 return uri.forget(); 1143 } 1144 1145 NS_IMETHODIMP 1146 nsIOService::CreateExposableURI(nsIURI* aURI, nsIURI** _result) { 1147 NS_ENSURE_ARG_POINTER(aURI); 1148 NS_ENSURE_ARG_POINTER(_result); 1149 nsCOMPtr<nsIURI> exposableURI = CreateExposableURI(aURI); 1150 exposableURI.forget(_result); 1151 return NS_OK; 1152 } 1153 1154 NS_IMETHODIMP 1155 nsIOService::NewChannelFromURI(nsIURI* aURI, nsINode* aLoadingNode, 1156 nsIPrincipal* aLoadingPrincipal, 1157 nsIPrincipal* aTriggeringPrincipal, 1158 uint32_t aSecurityFlags, 1159 nsContentPolicyType aContentPolicyType, 1160 nsIChannel** result) { 1161 return NewChannelFromURIWithProxyFlags(aURI, 1162 nullptr, // aProxyURI 1163 0, // aProxyFlags 1164 aLoadingNode, aLoadingPrincipal, 1165 aTriggeringPrincipal, aSecurityFlags, 1166 aContentPolicyType, result); 1167 } 1168 nsresult nsIOService::NewChannelFromURIWithClientAndController( 1169 nsIURI* aURI, nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal, 1170 nsIPrincipal* aTriggeringPrincipal, 1171 const Maybe<ClientInfo>& aLoadingClientInfo, 1172 const Maybe<ServiceWorkerDescriptor>& aController, uint32_t aSecurityFlags, 1173 nsContentPolicyType aContentPolicyType, uint32_t aSandboxFlags, 1174 nsIChannel** aResult) { 1175 return NewChannelFromURIWithProxyFlagsInternal( 1176 aURI, 1177 nullptr, // aProxyURI 1178 0, // aProxyFlags 1179 aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal, aLoadingClientInfo, 1180 aController, aSecurityFlags, aContentPolicyType, aSandboxFlags, aResult); 1181 } 1182 1183 NS_IMETHODIMP 1184 nsIOService::NewChannelFromURIWithLoadInfo(nsIURI* aURI, nsILoadInfo* aLoadInfo, 1185 nsIChannel** result) { 1186 return NewChannelFromURIWithProxyFlagsInternal(aURI, 1187 nullptr, // aProxyURI 1188 0, // aProxyFlags 1189 aLoadInfo, result); 1190 } 1191 1192 nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal( 1193 nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags, 1194 nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal, 1195 nsIPrincipal* aTriggeringPrincipal, 1196 const Maybe<ClientInfo>& aLoadingClientInfo, 1197 const Maybe<ServiceWorkerDescriptor>& aController, uint32_t aSecurityFlags, 1198 nsContentPolicyType aContentPolicyType, uint32_t aSandboxFlags, 1199 nsIChannel** result) { 1200 nsCOMPtr<nsILoadInfo> loadInfo = MOZ_TRY(LoadInfo::Create( 1201 aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags, 1202 aContentPolicyType, aLoadingClientInfo, aController, aSandboxFlags)); 1203 return NewChannelFromURIWithProxyFlagsInternal(aURI, aProxyURI, aProxyFlags, 1204 loadInfo, result); 1205 } 1206 1207 nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal( 1208 nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags, 1209 nsILoadInfo* aLoadInfo, nsIChannel** result) { 1210 nsresult rv; 1211 NS_ENSURE_ARG_POINTER(aURI); 1212 // all channel creations must provide a valid loadinfo 1213 MOZ_ASSERT(aLoadInfo, "can not create channel without aLoadInfo"); 1214 NS_ENSURE_ARG_POINTER(aLoadInfo); 1215 1216 nsAutoCString scheme; 1217 rv = aURI->GetScheme(scheme); 1218 if (NS_FAILED(rv)) return rv; 1219 1220 nsCOMPtr<nsIProtocolHandler> handler; 1221 rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); 1222 if (NS_FAILED(rv)) return rv; 1223 1224 nsCOMPtr<nsIChannel> channel; 1225 nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler); 1226 if (pph) { 1227 rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI, 1228 aLoadInfo, getter_AddRefs(channel)); 1229 } else { 1230 rv = handler->NewChannel(aURI, aLoadInfo, getter_AddRefs(channel)); 1231 } 1232 if (NS_FAILED(rv)) return rv; 1233 1234 // Make sure that all the individual protocolhandlers attach a loadInfo. 1235 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo(); 1236 if (aLoadInfo != loadInfo) { 1237 MOZ_ASSERT(false, "newly created channel must have a loadinfo attached"); 1238 return NS_ERROR_UNEXPECTED; 1239 } 1240 1241 // If we're sandboxed, make sure to clear any owner the channel 1242 // might already have. 1243 if (loadInfo->GetLoadingSandboxed()) { 1244 channel->SetOwner(nullptr); 1245 } 1246 channel.forget(result); 1247 return NS_OK; 1248 } 1249 1250 NS_IMETHODIMP 1251 nsIOService::NewChannelFromURIWithProxyFlags( 1252 nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags, 1253 nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal, 1254 nsIPrincipal* aTriggeringPrincipal, uint32_t aSecurityFlags, 1255 nsContentPolicyType aContentPolicyType, nsIChannel** result) { 1256 return NewChannelFromURIWithProxyFlagsInternal( 1257 aURI, aProxyURI, aProxyFlags, aLoadingNode, aLoadingPrincipal, 1258 aTriggeringPrincipal, Maybe<ClientInfo>(), 1259 Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType, 0, 1260 result); 1261 } 1262 1263 NS_IMETHODIMP 1264 nsIOService::NewChannel(const nsACString& aSpec, const char* aCharset, 1265 nsIURI* aBaseURI, nsINode* aLoadingNode, 1266 nsIPrincipal* aLoadingPrincipal, 1267 nsIPrincipal* aTriggeringPrincipal, 1268 uint32_t aSecurityFlags, 1269 nsContentPolicyType aContentPolicyType, 1270 nsIChannel** result) { 1271 nsresult rv; 1272 nsCOMPtr<nsIURI> uri; 1273 rv = NewURI(aSpec, aCharset, aBaseURI, getter_AddRefs(uri)); 1274 if (NS_FAILED(rv)) return rv; 1275 1276 return NewChannelFromURI(uri, aLoadingNode, aLoadingPrincipal, 1277 aTriggeringPrincipal, aSecurityFlags, 1278 aContentPolicyType, result); 1279 } 1280 1281 NS_IMETHODIMP 1282 nsIOService::NewSuspendableChannelWrapper( 1283 nsIChannel* aInnerChannel, nsISuspendableChannelWrapper** result) { 1284 NS_ENSURE_ARG_POINTER(aInnerChannel); 1285 1286 nsCOMPtr<nsISuspendableChannelWrapper> wrapper = 1287 new SuspendableChannelWrapper(aInnerChannel); 1288 wrapper.forget(result); 1289 return NS_OK; 1290 } 1291 1292 NS_IMETHODIMP 1293 nsIOService::NewWebTransport(nsIWebTransport** result) { 1294 if (!XRE_IsParentProcess()) { 1295 return NS_ERROR_NOT_AVAILABLE; 1296 } 1297 1298 nsCOMPtr<nsIWebTransport> webTransport = new WebTransportSessionProxy(); 1299 1300 webTransport.forget(result); 1301 return NS_OK; 1302 } 1303 1304 NS_IMETHODIMP 1305 nsIOService::OriginAttributesForNetworkState( 1306 nsIChannel* aChannel, JSContext* cx, JS::MutableHandle<JS::Value> _retval) { 1307 OriginAttributes attrs; 1308 if (!StoragePrincipalHelper::GetOriginAttributesForNetworkState(aChannel, 1309 attrs)) { 1310 return NS_ERROR_FAILURE; 1311 } 1312 1313 if (NS_WARN_IF(!mozilla::dom::ToJSValue(cx, attrs, _retval))) { 1314 return NS_ERROR_FAILURE; 1315 } 1316 1317 return NS_OK; 1318 } 1319 1320 bool nsIOService::IsLinkUp() { 1321 InitializeNetworkLinkService(); 1322 1323 if (!mNetworkLinkService) { 1324 // We cannot decide, assume the link is up 1325 return true; 1326 } 1327 1328 bool isLinkUp; 1329 nsresult rv; 1330 rv = mNetworkLinkService->GetIsLinkUp(&isLinkUp); 1331 if (NS_FAILED(rv)) { 1332 return true; 1333 } 1334 1335 return isLinkUp; 1336 } 1337 1338 NS_IMETHODIMP 1339 nsIOService::GetOffline(bool* offline) { 1340 if (StaticPrefs::network_offline_mirrors_connectivity()) { 1341 *offline = mOffline || !mConnectivity; 1342 } else { 1343 *offline = mOffline; 1344 } 1345 return NS_OK; 1346 } 1347 1348 NS_IMETHODIMP 1349 nsIOService::SetOffline(bool offline) { return SetOfflineInternal(offline); } 1350 1351 nsresult nsIOService::SetOfflineInternal(bool offline, 1352 bool notifySocketProcess) { 1353 LOG(("nsIOService::SetOffline offline=%d\n", offline)); 1354 // When someone wants to go online (!offline) after we got XPCOM shutdown 1355 // throw ERROR_NOT_AVAILABLE to prevent return to online state. 1356 if ((mShutdown || mOfflineForProfileChange) && !offline) { 1357 return NS_ERROR_NOT_AVAILABLE; 1358 } 1359 1360 // SetOffline() may re-enter while it's shutting down services. 1361 // If that happens, save the most recent value and it will be 1362 // processed when the first SetOffline() call is done bringing 1363 // down the service. 1364 mSetOfflineValue = offline; 1365 if (mSettingOffline) { 1366 return NS_OK; 1367 } 1368 1369 mSettingOffline = true; 1370 1371 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); 1372 1373 NS_ASSERTION(observerService, "The observer service should not be null"); 1374 1375 if (XRE_IsParentProcess()) { 1376 if (observerService) { 1377 (void)observerService->NotifyObservers(nullptr, 1378 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, 1379 offline ? u"true" : u"false"); 1380 } 1381 if (SocketProcessReady() && notifySocketProcess) { 1382 (void)mSocketProcess->GetActor()->SendSetOffline(offline); 1383 } 1384 } 1385 1386 nsIIOService* subject = static_cast<nsIIOService*>(this); 1387 while (mSetOfflineValue != mOffline) { 1388 offline = mSetOfflineValue; 1389 1390 if (offline && !mOffline) { 1391 mOffline = true; // indicate we're trying to shutdown 1392 1393 // don't care if notifications fail 1394 if (observerService) { 1395 observerService->NotifyObservers(subject, 1396 NS_IOSERVICE_GOING_OFFLINE_TOPIC, 1397 u"" NS_IOSERVICE_OFFLINE); 1398 } 1399 1400 if (mSocketTransportService) mSocketTransportService->SetOffline(true); 1401 1402 mLastOfflineStateChange = PR_IntervalNow(); 1403 if (observerService) { 1404 observerService->NotifyObservers(subject, 1405 NS_IOSERVICE_OFFLINE_STATUS_TOPIC, 1406 u"" NS_IOSERVICE_OFFLINE); 1407 } 1408 } else if (!offline && mOffline) { 1409 // go online 1410 InitializeSocketTransportService(); 1411 mOffline = false; // indicate success only AFTER we've 1412 // brought up the services 1413 1414 mLastOfflineStateChange = PR_IntervalNow(); 1415 // don't care if notification fails 1416 // Only send the ONLINE notification if there is connectivity 1417 if (observerService && mConnectivity) { 1418 observerService->NotifyObservers(subject, 1419 NS_IOSERVICE_OFFLINE_STATUS_TOPIC, 1420 (u"" NS_IOSERVICE_ONLINE)); 1421 } 1422 } 1423 } 1424 1425 // Don't notify here, as the above notifications (if used) suffice. 1426 if ((mShutdown || mOfflineForProfileChange) && mOffline) { 1427 if (mSocketTransportService) { 1428 DebugOnly<nsresult> rv = mSocketTransportService->Shutdown(mShutdown); 1429 NS_ASSERTION(NS_SUCCEEDED(rv), 1430 "socket transport service shutdown failed"); 1431 } 1432 } 1433 1434 mSettingOffline = false; 1435 1436 return NS_OK; 1437 } 1438 1439 NS_IMETHODIMP 1440 nsIOService::GetConnectivity(bool* aConnectivity) { 1441 *aConnectivity = mConnectivity; 1442 return NS_OK; 1443 } 1444 1445 NS_IMETHODIMP 1446 nsIOService::SetConnectivity(bool aConnectivity) { 1447 LOG(("nsIOService::SetConnectivity aConnectivity=%d\n", aConnectivity)); 1448 // This should only be called from ContentChild to pass the connectivity 1449 // value from the chrome process to the content process. 1450 if (XRE_IsParentProcess()) { 1451 return NS_ERROR_NOT_AVAILABLE; 1452 } 1453 return SetConnectivityInternal(aConnectivity); 1454 } 1455 1456 NS_IMETHODIMP 1457 nsIOService::SetConnectivityForTesting(bool aConnectivity) { 1458 return SetConnectivityInternal(aConnectivity); 1459 } 1460 1461 nsresult nsIOService::SetConnectivityInternal(bool aConnectivity) { 1462 LOG(("nsIOService::SetConnectivityInternal aConnectivity=%d\n", 1463 aConnectivity)); 1464 if (mConnectivity == aConnectivity) { 1465 // Nothing to do here. 1466 return NS_OK; 1467 } 1468 mConnectivity = aConnectivity; 1469 1470 // This is used for PR_Connect PR_Close telemetry so it is important that 1471 // we have statistic about network change event even if we are offline. 1472 mLastConnectivityChange = PR_IntervalNow(); 1473 1474 if (mCaptivePortalService) { 1475 if (aConnectivity && gCaptivePortalEnabled) { 1476 // This will also trigger a captive portal check for the new network 1477 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start(); 1478 } else { 1479 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop(); 1480 } 1481 } 1482 1483 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); 1484 if (!observerService) { 1485 return NS_OK; 1486 } 1487 // This notification sends the connectivity to the child processes 1488 if (XRE_IsParentProcess()) { 1489 observerService->NotifyObservers(nullptr, 1490 NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC, 1491 aConnectivity ? u"true" : u"false"); 1492 if (SocketProcessReady()) { 1493 (void)mSocketProcess->GetActor()->SendSetConnectivity(aConnectivity); 1494 } 1495 } 1496 1497 if (mOffline) { 1498 // We don't need to send any notifications if we're offline 1499 return NS_OK; 1500 } 1501 1502 if (aConnectivity) { 1503 // If we were previously offline due to connectivity=false, 1504 // send the ONLINE notification 1505 observerService->NotifyObservers(static_cast<nsIIOService*>(this), 1506 NS_IOSERVICE_OFFLINE_STATUS_TOPIC, 1507 (u"" NS_IOSERVICE_ONLINE)); 1508 } else { 1509 // If we were previously online and lost connectivity 1510 // send the OFFLINE notification 1511 observerService->NotifyObservers(static_cast<nsIIOService*>(this), 1512 NS_IOSERVICE_GOING_OFFLINE_TOPIC, 1513 u"" NS_IOSERVICE_OFFLINE); 1514 observerService->NotifyObservers(static_cast<nsIIOService*>(this), 1515 NS_IOSERVICE_OFFLINE_STATUS_TOPIC, 1516 u"" NS_IOSERVICE_OFFLINE); 1517 } 1518 return NS_OK; 1519 } 1520 1521 NS_IMETHODIMP 1522 nsIOService::AllowPort(int32_t inPort, const char* scheme, bool* _retval) { 1523 int32_t port = inPort; 1524 if (port == -1) { 1525 *_retval = true; 1526 return NS_OK; 1527 } 1528 1529 if (port <= 0 || port > std::numeric_limits<uint16_t>::max()) { 1530 *_retval = false; 1531 return NS_OK; 1532 } 1533 1534 nsTArray<int32_t> restrictedPortList; 1535 { 1536 AutoReadLock lock(mLock); 1537 restrictedPortList.Assign(mRestrictedPortList); 1538 } 1539 // first check to see if the port is in our blacklist: 1540 int32_t badPortListCnt = restrictedPortList.Length(); 1541 for (int i = 0; i < badPortListCnt; i++) { 1542 if (port == restrictedPortList[i]) { 1543 *_retval = false; 1544 1545 // check to see if the protocol wants to override 1546 if (!scheme) return NS_OK; 1547 1548 // We don't support get protocol handler off main thread. 1549 if (!NS_IsMainThread()) { 1550 return NS_OK; 1551 } 1552 nsCOMPtr<nsIProtocolHandler> handler; 1553 nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler)); 1554 if (NS_FAILED(rv)) return rv; 1555 1556 // let the protocol handler decide 1557 return handler->AllowPort(port, scheme, _retval); 1558 } 1559 } 1560 1561 *_retval = true; 1562 return NS_OK; 1563 } 1564 1565 //////////////////////////////////////////////////////////////////////////////// 1566 1567 // static 1568 void nsIOService::PrefsChanged(const char* pref, void* self) { 1569 static_cast<nsIOService*>(self)->PrefsChanged(pref); 1570 } 1571 1572 void nsIOService::PrefsChanged(const char* pref) { 1573 // Look for extra ports to block 1574 if (!pref || strcmp(pref, PORT_PREF("banned")) == 0) { 1575 ParsePortList(PORT_PREF("banned"), false); 1576 } 1577 1578 // ...as well as previous blocks to remove. 1579 if (!pref || strcmp(pref, PORT_PREF("banned.override")) == 0) { 1580 ParsePortList(PORT_PREF("banned.override"), true); 1581 } 1582 1583 if (!pref || strcmp(pref, MANAGE_OFFLINE_STATUS_PREF) == 0) { 1584 bool manage; 1585 if (mNetworkLinkServiceInitialized && 1586 NS_SUCCEEDED( 1587 Preferences::GetBool(MANAGE_OFFLINE_STATUS_PREF, &manage))) { 1588 LOG(("nsIOService::PrefsChanged ManageOfflineStatus manage=%d\n", 1589 manage)); 1590 SetManageOfflineStatus(manage); 1591 } 1592 } 1593 1594 if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_COUNT_PREF) == 0) { 1595 int32_t count; 1596 if (NS_SUCCEEDED( 1597 Preferences::GetInt(NECKO_BUFFER_CACHE_COUNT_PREF, &count))) { 1598 /* check for bogus values and default if we find such a value */ 1599 if (count > 0) gDefaultSegmentCount = count; 1600 } 1601 } 1602 1603 if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_SIZE_PREF) == 0) { 1604 int32_t size; 1605 if (NS_SUCCEEDED( 1606 Preferences::GetInt(NECKO_BUFFER_CACHE_SIZE_PREF, &size))) { 1607 /* check for bogus values and default if we find such a value 1608 * the upper limit here is arbitrary. having a 1mb segment size 1609 * is pretty crazy. if you remove this, consider adding some 1610 * integer rollover test. 1611 */ 1612 if (size > 0 && size < 1024 * 1024) gDefaultSegmentSize = size; 1613 } 1614 NS_WARNING_ASSERTION(!(size & (size - 1)), 1615 "network segment size is not a power of 2!"); 1616 } 1617 1618 if (!pref || strcmp(pref, NETWORK_CAPTIVE_PORTAL_PREF) == 0) { 1619 nsresult rv = Preferences::GetBool(NETWORK_CAPTIVE_PORTAL_PREF, 1620 &gCaptivePortalEnabled); 1621 if (NS_SUCCEEDED(rv) && mCaptivePortalService) { 1622 if (gCaptivePortalEnabled) { 1623 static_cast<CaptivePortalService*>(mCaptivePortalService.get()) 1624 ->Start(); 1625 } else { 1626 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop(); 1627 } 1628 } 1629 } 1630 1631 if (!pref || strncmp(pref, FORCE_EXTERNAL_PREF_PREFIX, 1632 strlen(FORCE_EXTERNAL_PREF_PREFIX)) == 0) { 1633 nsTArray<nsCString> prefs; 1634 if (nsIPrefBranch* prefRootBranch = Preferences::GetRootBranch()) { 1635 prefRootBranch->GetChildList(FORCE_EXTERNAL_PREF_PREFIX, prefs); 1636 } 1637 nsTArray<nsCString> forceExternalSchemes; 1638 for (const auto& pref : prefs) { 1639 if (Preferences::GetBool(pref.get(), false)) { 1640 forceExternalSchemes.AppendElement( 1641 Substring(pref, strlen(FORCE_EXTERNAL_PREF_PREFIX))); 1642 } 1643 } 1644 AutoWriteLock lock(mLock); 1645 mForceExternalSchemes = std::move(forceExternalSchemes); 1646 } 1647 1648 if (!pref || strncmp(pref, SIMPLE_URI_SCHEMES_PREF, 1649 strlen(SIMPLE_URI_SCHEMES_PREF)) == 0) { 1650 LOG(("simple_uri_unknown_schemes pref changed, updating the scheme list")); 1651 mSimpleURIUnknownSchemes.ParseAndMergePrefSchemes(); 1652 // runs on parent and child, no need to broadcast 1653 } 1654 1655 if (!pref || strncmp(pref, PREF_LNA_IP_ADDR_SPACE_PUBLIC, 1656 strlen(PREF_LNA_IP_ADDR_SPACE_PUBLIC)) == 0) { 1657 AutoWriteLock lock(mLock); 1658 UpdateAddressSpaceOverrideList(PREF_LNA_IP_ADDR_SPACE_PUBLIC, 1659 mPublicAddressSpaceOverridesList); 1660 } 1661 1662 if (!pref || strncmp(pref, PREF_LNA_IP_ADDR_SPACE_PRIVATE, 1663 strlen(PREF_LNA_IP_ADDR_SPACE_PRIVATE)) == 0) { 1664 AutoWriteLock lock(mLock); 1665 UpdateAddressSpaceOverrideList(PREF_LNA_IP_ADDR_SPACE_PRIVATE, 1666 mPrivateAddressSpaceOverridesList); 1667 } 1668 if (!pref || strncmp(pref, PREF_LNA_IP_ADDR_SPACE_LOCAL, 1669 strlen(PREF_LNA_IP_ADDR_SPACE_LOCAL)) == 0) { 1670 AutoWriteLock lock(mLock); 1671 UpdateAddressSpaceOverrideList(PREF_LNA_IP_ADDR_SPACE_LOCAL, 1672 mLocalAddressSpaceOverrideList); 1673 } 1674 if (!pref || strncmp(pref, PREF_LNA_SKIP_DOMAINS, 1675 strlen(PREF_LNA_SKIP_DOMAINS)) == 0) { 1676 UpdateSkipDomainsList(); 1677 } 1678 } 1679 1680 void nsIOService::UpdateAddressSpaceOverrideList( 1681 const char* aPrefName, nsTArray<nsCString>& aTargetList) { 1682 nsAutoCString aAddressSpaceOverrides; 1683 Preferences::GetCString(aPrefName, aAddressSpaceOverrides); 1684 1685 nsTArray<nsCString> addressSpaceOverridesArray; 1686 nsCCharSeparatedTokenizer tokenizer(aAddressSpaceOverrides, ','); 1687 while (tokenizer.hasMoreTokens()) { 1688 nsAutoCString token(tokenizer.nextToken()); 1689 token.StripWhitespace(); 1690 addressSpaceOverridesArray.AppendElement(token); 1691 } 1692 1693 aTargetList = std::move(addressSpaceOverridesArray); 1694 } 1695 1696 void nsIOService::UpdateSkipDomainsList() { 1697 nsAutoCString skipDomains; 1698 Preferences::GetCString(PREF_LNA_SKIP_DOMAINS, skipDomains); 1699 1700 nsTArray<nsCString> skipDomainsArray; 1701 nsCCharSeparatedTokenizer tokenizer(skipDomains, ','); 1702 while (tokenizer.hasMoreTokens()) { 1703 nsAutoCString token(tokenizer.nextToken()); 1704 token.StripWhitespace(); 1705 if (!token.IsEmpty()) { 1706 skipDomainsArray.AppendElement(token); 1707 } 1708 } 1709 1710 AutoWriteLock lock(mLock); 1711 mLNASkipDomainsList = std::move(skipDomainsArray); 1712 } 1713 1714 bool nsIOService::ShouldSkipDomainForLNA(const nsACString& aDomain) { 1715 AutoReadLock lock(mLock); 1716 1717 // Check each domain pattern 1718 for (const auto& pattern : mLNASkipDomainsList) { 1719 // Special case: plain "*" matches all domains 1720 if (pattern.Equals("*"_ns)) { 1721 return true; 1722 } 1723 1724 // Suffix wildcard pattern (starts with *.) 1725 if (StringBeginsWith(pattern, "*."_ns)) { 1726 nsDependentCSubstring suffix(Substring(pattern, 2)); 1727 nsDependentCSubstring suffixWithDot(Substring(pattern, 1)); 1728 if (aDomain == suffix || StringEndsWith(aDomain, suffixWithDot)) { 1729 return true; 1730 } 1731 } 1732 1733 // Exact match 1734 if (pattern == aDomain) { 1735 return true; 1736 } 1737 } 1738 1739 return false; 1740 } 1741 1742 void nsIOService::ParsePortList(const char* pref, bool remove) { 1743 nsAutoCString portList; 1744 nsTArray<int32_t> restrictedPortList; 1745 { 1746 AutoWriteLock lock(mLock); 1747 restrictedPortList.Assign(std::move(mRestrictedPortList)); 1748 } 1749 // Get a pref string and chop it up into a list of ports. 1750 Preferences::GetCString(pref, portList); 1751 if (!portList.IsVoid()) { 1752 nsTArray<nsCString> portListArray; 1753 ParseString(portList, ',', portListArray); 1754 uint32_t index; 1755 for (index = 0; index < portListArray.Length(); index++) { 1756 portListArray[index].StripWhitespace(); 1757 int32_t portBegin, portEnd; 1758 1759 if (PR_sscanf(portListArray[index].get(), "%d-%d", &portBegin, 1760 &portEnd) == 2) { 1761 if ((portBegin < 65536) && (portEnd < 65536)) { 1762 int32_t curPort; 1763 if (remove) { 1764 for (curPort = portBegin; curPort <= portEnd; curPort++) { 1765 restrictedPortList.RemoveElement(curPort); 1766 } 1767 } else { 1768 for (curPort = portBegin; curPort <= portEnd; curPort++) { 1769 restrictedPortList.AppendElement(curPort); 1770 } 1771 } 1772 } 1773 } else { 1774 nsresult aErrorCode; 1775 int32_t port = portListArray[index].ToInteger(&aErrorCode); 1776 if (NS_SUCCEEDED(aErrorCode) && port < 65536) { 1777 if (remove) { 1778 restrictedPortList.RemoveElement(port); 1779 } else { 1780 restrictedPortList.AppendElement(port); 1781 } 1782 } 1783 } 1784 } 1785 } 1786 1787 AutoWriteLock lock(mLock); 1788 mRestrictedPortList.Assign(std::move(restrictedPortList)); 1789 } 1790 1791 class nsWakeupNotifier : public Runnable { 1792 public: 1793 explicit nsWakeupNotifier(nsIIOServiceInternal* ioService) 1794 : Runnable("net::nsWakeupNotifier"), mIOService(ioService) {} 1795 1796 NS_IMETHOD Run() override { return mIOService->NotifyWakeup(); } 1797 1798 private: 1799 virtual ~nsWakeupNotifier() = default; 1800 nsCOMPtr<nsIIOServiceInternal> mIOService; 1801 }; 1802 1803 NS_IMETHODIMP 1804 nsIOService::NotifyWakeup() { 1805 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); 1806 1807 NS_ASSERTION(observerService, "The observer service should not be null"); 1808 1809 if (observerService && StaticPrefs::network_notify_changed()) { 1810 (void)observerService->NotifyObservers(nullptr, NS_NETWORK_LINK_TOPIC, 1811 (u"" NS_NETWORK_LINK_DATA_CHANGED)); 1812 } 1813 1814 RecheckCaptivePortal(); 1815 1816 return NS_OK; 1817 } 1818 1819 void nsIOService::SetHttpHandlerAlreadyShutingDown() { 1820 if (!mShutdown && !mOfflineForProfileChange) { 1821 mNetTearingDownStarted = PR_IntervalNow(); 1822 mHttpHandlerAlreadyShutingDown = true; 1823 } 1824 } 1825 1826 // nsIObserver interface 1827 NS_IMETHODIMP 1828 nsIOService::Observe(nsISupports* subject, const char* topic, 1829 const char16_t* data) { 1830 if (UseSocketProcess() && SocketProcessReady() && 1831 mObserverTopicForSocketProcess.Contains(nsDependentCString(topic))) { 1832 nsCString topicStr(topic); 1833 nsString dataStr(data); 1834 (void)mSocketProcess->GetActor()->SendNotifyObserver(topicStr, dataStr); 1835 } 1836 1837 if (!strcmp(topic, kProfileChangeNetTeardownTopic)) { 1838 if (!mHttpHandlerAlreadyShutingDown) { 1839 mNetTearingDownStarted = PR_IntervalNow(); 1840 } 1841 mHttpHandlerAlreadyShutingDown = false; 1842 if (!mOffline) { 1843 mOfflineForProfileChange = true; 1844 SetOfflineInternal(true, false); 1845 } 1846 } else if (!strcmp(topic, kProfileChangeNetRestoreTopic)) { 1847 if (mOfflineForProfileChange) { 1848 mOfflineForProfileChange = false; 1849 SetOfflineInternal(false, false); 1850 } 1851 } else if (!strcmp(topic, kProfileDoChange)) { 1852 if (data && u"startup"_ns.Equals(data)) { 1853 // Lazy initialization of network link service (see bug 620472) 1854 InitializeNetworkLinkService(); 1855 // Set up the initilization flag regardless the actuall result. 1856 // If we fail here, we will fail always on. 1857 mNetworkLinkServiceInitialized = true; 1858 1859 // And now reflect the preference setting 1860 PrefsChanged(MANAGE_OFFLINE_STATUS_PREF); 1861 1862 // Bug 870460 - Read cookie database at an early-as-possible time 1863 // off main thread. Hence, we have more chance to finish db query 1864 // before something calls into the cookie service. 1865 nsCOMPtr<nsISupports> cookieServ = 1866 do_GetService(NS_COOKIESERVICE_CONTRACTID); 1867 } 1868 } else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { 1869 // Remember we passed XPCOM shutdown notification to prevent any 1870 // changes of the offline status from now. We must not allow going 1871 // online after this point. 1872 mShutdown = true; 1873 1874 if (!mHttpHandlerAlreadyShutingDown && !mOfflineForProfileChange) { 1875 mNetTearingDownStarted = PR_IntervalNow(); 1876 } 1877 mHttpHandlerAlreadyShutingDown = false; 1878 1879 SetOfflineInternal(true, false); 1880 1881 if (mCaptivePortalService) { 1882 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop(); 1883 mCaptivePortalService = nullptr; 1884 } 1885 1886 SSLTokensCache::Shutdown(); 1887 1888 DestroySocketProcess(); 1889 1890 if (IsSocketProcessChild()) { 1891 Preferences::UnregisterCallbacks(nsIOService::OnTLSPrefChange, 1892 gCallbackSecurityPrefs, this); 1893 PrepareForShutdownInSocketProcess(); 1894 } 1895 1896 // We're in XPCOM shutdown now. Unregister any dynamic protocol handlers 1897 // after this point to avoid leaks. 1898 { 1899 AutoWriteLock lock(mLock); 1900 mRuntimeProtocolHandlers.Clear(); 1901 } 1902 } else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) { 1903 OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get()); 1904 } else if (!strcmp(topic, NS_NETWORK_ID_CHANGED_TOPIC)) { 1905 LOG(("nsIOService::OnNetworkLinkEvent Network id changed")); 1906 } else if (!strcmp(topic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) { 1907 // coming back alive from sleep 1908 // this indirection brought to you by: 1909 // https://bugzilla.mozilla.org/show_bug.cgi?id=1152048#c19 1910 nsCOMPtr<nsIRunnable> wakeupNotifier = new nsWakeupNotifier(this); 1911 NS_DispatchToMainThread(wakeupNotifier); 1912 mInSleepMode = false; 1913 } else if (!strcmp(topic, NS_WIDGET_SLEEP_OBSERVER_TOPIC)) { 1914 mInSleepMode = true; 1915 } 1916 1917 return NS_OK; 1918 } 1919 1920 // nsINetUtil interface 1921 NS_IMETHODIMP 1922 nsIOService::ParseRequestContentType(const nsACString& aTypeHeader, 1923 nsACString& aCharset, bool* aHadCharset, 1924 nsACString& aContentType) { 1925 net_ParseRequestContentType(aTypeHeader, aContentType, aCharset, aHadCharset); 1926 return NS_OK; 1927 } 1928 1929 // nsINetUtil interface 1930 NS_IMETHODIMP 1931 nsIOService::ParseResponseContentType(const nsACString& aTypeHeader, 1932 nsACString& aCharset, bool* aHadCharset, 1933 nsACString& aContentType) { 1934 net_ParseContentType(aTypeHeader, aContentType, aCharset, aHadCharset); 1935 return NS_OK; 1936 } 1937 1938 NS_IMETHODIMP 1939 nsIOService::ProtocolHasFlags(nsIURI* uri, uint32_t flags, bool* result) { 1940 NS_ENSURE_ARG(uri); 1941 1942 *result = false; 1943 nsAutoCString scheme; 1944 nsresult rv = uri->GetScheme(scheme); 1945 NS_ENSURE_SUCCESS(rv, rv); 1946 1947 auto handler = LookupProtocolHandler(scheme); 1948 1949 uint32_t protocolFlags; 1950 if (flags & nsIProtocolHandler::DYNAMIC_URI_FLAGS) { 1951 AssertIsOnMainThread(); 1952 rv = handler.DynamicProtocolFlags(uri, &protocolFlags); 1953 NS_ENSURE_SUCCESS(rv, rv); 1954 } else { 1955 protocolFlags = handler.StaticProtocolFlags(); 1956 } 1957 1958 *result = (protocolFlags & flags) == flags; 1959 return NS_OK; 1960 } 1961 1962 NS_IMETHODIMP 1963 nsIOService::URIChainHasFlags(nsIURI* uri, uint32_t flags, bool* result) { 1964 nsresult rv = ProtocolHasFlags(uri, flags, result); 1965 NS_ENSURE_SUCCESS(rv, rv); 1966 1967 if (*result) { 1968 return rv; 1969 } 1970 1971 // Dig deeper into the chain. Note that this is not a do/while loop to 1972 // avoid the extra addref/release on |uri| in the common (non-nested) case. 1973 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri); 1974 while (nestedURI) { 1975 nsCOMPtr<nsIURI> innerURI; 1976 rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI)); 1977 NS_ENSURE_SUCCESS(rv, rv); 1978 1979 rv = ProtocolHasFlags(innerURI, flags, result); 1980 1981 if (*result) { 1982 return rv; 1983 } 1984 1985 nestedURI = do_QueryInterface(innerURI); 1986 } 1987 1988 return rv; 1989 } 1990 1991 NS_IMETHODIMP 1992 nsIOService::SetManageOfflineStatus(bool aManage) { 1993 LOG(("nsIOService::SetManageOfflineStatus aManage=%d\n", aManage)); 1994 mManageLinkStatus = aManage; 1995 1996 // When detection is not activated, the default connectivity state is true. 1997 if (!mManageLinkStatus) { 1998 SetConnectivityInternal(true); 1999 return NS_OK; 2000 } 2001 2002 InitializeNetworkLinkService(); 2003 // If the NetworkLinkService is already initialized, it does not call 2004 // OnNetworkLinkEvent. This is needed, when mManageLinkStatus goes from 2005 // false to true. 2006 OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN); 2007 return NS_OK; 2008 } 2009 2010 NS_IMETHODIMP 2011 nsIOService::GetManageOfflineStatus(bool* aManage) { 2012 *aManage = mManageLinkStatus; 2013 return NS_OK; 2014 } 2015 2016 // input argument 'data' is already UTF8'ed 2017 nsresult nsIOService::OnNetworkLinkEvent(const char* data) { 2018 if (IsNeckoChild() || IsSocketProcessChild()) { 2019 // There is nothing IO service could do on the child process 2020 // with this at the moment. Feel free to add functionality 2021 // here at will, though. 2022 return NS_OK; 2023 } 2024 2025 if (mShutdown) { 2026 return NS_ERROR_NOT_AVAILABLE; 2027 } 2028 2029 nsCString dataAsString(data); 2030 for (auto* cp : mozilla::dom::ContentParent::AllProcesses( 2031 mozilla::dom::ContentParent::eLive)) { 2032 PNeckoParent* neckoParent = SingleManagedOrNull(cp->ManagedPNeckoParent()); 2033 if (!neckoParent) { 2034 continue; 2035 } 2036 (void)neckoParent->SendNetworkChangeNotification(dataAsString); 2037 } 2038 2039 LOG(("nsIOService::OnNetworkLinkEvent data:%s\n", data)); 2040 if (!mNetworkLinkService) { 2041 return NS_ERROR_FAILURE; 2042 } 2043 2044 if (!mManageLinkStatus) { 2045 LOG(("nsIOService::OnNetworkLinkEvent mManageLinkStatus=false\n")); 2046 return NS_OK; 2047 } 2048 2049 bool isUp = true; 2050 if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) { 2051 mLastNetworkLinkChange = PR_IntervalNow(); 2052 // CHANGED means UP/DOWN didn't change 2053 // but the status of the captive portal may have changed. 2054 RecheckCaptivePortal(); 2055 return NS_OK; 2056 } 2057 if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) { 2058 isUp = false; 2059 } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UP)) { 2060 isUp = true; 2061 } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UNKNOWN)) { 2062 nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp); 2063 NS_ENSURE_SUCCESS(rv, rv); 2064 } else { 2065 NS_WARNING("Unhandled network event!"); 2066 return NS_OK; 2067 } 2068 2069 return SetConnectivityInternal(isUp); 2070 } 2071 2072 NS_IMETHODIMP 2073 nsIOService::EscapeString(const nsACString& aString, uint32_t aEscapeType, 2074 nsACString& aResult) { 2075 NS_ENSURE_ARG_MAX(aEscapeType, 4); 2076 2077 nsAutoCString stringCopy(aString); 2078 nsCString result; 2079 2080 if (!NS_Escape(stringCopy, result, (nsEscapeMask)aEscapeType)) { 2081 return NS_ERROR_OUT_OF_MEMORY; 2082 } 2083 2084 aResult.Assign(result); 2085 2086 return NS_OK; 2087 } 2088 2089 NS_IMETHODIMP 2090 nsIOService::EscapeURL(const nsACString& aStr, uint32_t aFlags, 2091 nsACString& aResult) { 2092 aResult.Truncate(); 2093 NS_EscapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy, 2094 aResult); 2095 return NS_OK; 2096 } 2097 2098 NS_IMETHODIMP 2099 nsIOService::UnescapeString(const nsACString& aStr, uint32_t aFlags, 2100 nsACString& aResult) { 2101 aResult.Truncate(); 2102 NS_UnescapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy, 2103 aResult); 2104 return NS_OK; 2105 } 2106 2107 NS_IMETHODIMP 2108 nsIOService::ExtractCharsetFromContentType(const nsACString& aTypeHeader, 2109 nsACString& aCharset, 2110 int32_t* aCharsetStart, 2111 int32_t* aCharsetEnd, 2112 bool* aHadCharset) { 2113 nsAutoCString ignored; 2114 net_ParseContentType(aTypeHeader, ignored, aCharset, aHadCharset, 2115 aCharsetStart, aCharsetEnd); 2116 if (*aHadCharset && *aCharsetStart == *aCharsetEnd) { 2117 *aHadCharset = false; 2118 } 2119 return NS_OK; 2120 } 2121 2122 // nsISpeculativeConnect 2123 class IOServiceProxyCallback final : public nsIProtocolProxyCallback { 2124 ~IOServiceProxyCallback() = default; 2125 2126 public: 2127 NS_DECL_ISUPPORTS 2128 NS_DECL_NSIPROTOCOLPROXYCALLBACK 2129 2130 IOServiceProxyCallback(nsIInterfaceRequestor* aCallbacks, 2131 nsIOService* aIOService, 2132 Maybe<OriginAttributes>&& aOriginAttributes) 2133 : mCallbacks(aCallbacks), 2134 mIOService(aIOService), 2135 mOriginAttributes(std::move(aOriginAttributes)) {} 2136 2137 private: 2138 RefPtr<nsIInterfaceRequestor> mCallbacks; 2139 RefPtr<nsIOService> mIOService; 2140 Maybe<OriginAttributes> mOriginAttributes; 2141 }; 2142 2143 NS_IMPL_ISUPPORTS(IOServiceProxyCallback, nsIProtocolProxyCallback) 2144 2145 NS_IMETHODIMP 2146 IOServiceProxyCallback::OnProxyAvailable(nsICancelable* request, 2147 nsIChannel* channel, nsIProxyInfo* pi, 2148 nsresult status) { 2149 // Checking proxy status for speculative connect 2150 nsAutoCString type; 2151 if (NS_SUCCEEDED(status) && pi && NS_SUCCEEDED(pi->GetType(type)) && 2152 !type.EqualsLiteral("direct")) { 2153 // proxies dont do speculative connect 2154 return NS_OK; 2155 } 2156 2157 nsCOMPtr<nsIURI> uri; 2158 nsresult rv = channel->GetURI(getter_AddRefs(uri)); 2159 if (NS_FAILED(rv)) { 2160 return NS_OK; 2161 } 2162 2163 nsAutoCString scheme; 2164 rv = uri->GetScheme(scheme); 2165 if (NS_FAILED(rv)) return NS_OK; 2166 2167 nsCOMPtr<nsIProtocolHandler> handler; 2168 rv = mIOService->GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); 2169 if (NS_FAILED(rv)) return NS_OK; 2170 2171 nsCOMPtr<nsISpeculativeConnect> speculativeHandler = 2172 do_QueryInterface(handler); 2173 if (!speculativeHandler) return NS_OK; 2174 2175 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo(); 2176 nsCOMPtr<nsIPrincipal> principal = loadInfo->GetLoadingPrincipal(); 2177 2178 nsLoadFlags loadFlags = 0; 2179 channel->GetLoadFlags(&loadFlags); 2180 bool anonymous = !!(loadFlags & nsIRequest::LOAD_ANONYMOUS); 2181 if (mOriginAttributes) { 2182 speculativeHandler->SpeculativeConnectWithOriginAttributesNative( 2183 uri, std::move(mOriginAttributes.ref()), mCallbacks, anonymous); 2184 } else { 2185 speculativeHandler->SpeculativeConnect(uri, principal, mCallbacks, 2186 anonymous); 2187 } 2188 2189 return NS_OK; 2190 } 2191 2192 nsresult nsIOService::SpeculativeConnectInternal( 2193 nsIURI* aURI, nsIPrincipal* aPrincipal, 2194 Maybe<OriginAttributes>&& aOriginAttributes, 2195 nsIInterfaceRequestor* aCallbacks, bool aAnonymous) { 2196 NS_ENSURE_ARG(aURI); 2197 2198 if (!SchemeIsHttpOrHttps(aURI)) { 2199 // We don't speculatively connect to non-HTTP[S] URIs. 2200 return NS_OK; 2201 } 2202 2203 if (IsNeckoChild()) { 2204 gNeckoChild->SendSpeculativeConnect( 2205 aURI, aPrincipal, std::move(aOriginAttributes), aAnonymous); 2206 return NS_OK; 2207 } 2208 2209 // Check for proxy information. If there is a proxy configured then a 2210 // speculative connect should not be performed because the potential 2211 // reward is slim with tcp peers closely located to the browser. 2212 nsresult rv; 2213 nsCOMPtr<nsIProtocolProxyService> pps; 2214 pps = mozilla::components::ProtocolProxy::Service(&rv); 2215 NS_ENSURE_SUCCESS(rv, rv); 2216 2217 nsCOMPtr<nsIPrincipal> loadingPrincipal = aPrincipal; 2218 2219 MOZ_ASSERT(aPrincipal || aOriginAttributes, 2220 "We expect passing a principal or OriginAttributes here."); 2221 2222 if (!aPrincipal && !aOriginAttributes) { 2223 return NS_ERROR_INVALID_ARG; 2224 } 2225 2226 if (aOriginAttributes) { 2227 loadingPrincipal = 2228 BasePrincipal::CreateContentPrincipal(aURI, aOriginAttributes.ref()); 2229 } 2230 2231 // XXX Bug 1724080: Avoid TCP connections on port 80 when https-only 2232 // or https-first is enabled. Let's create a dummy loadinfo which we 2233 // only use to determine whether we need ot upgrade the speculative 2234 // connection from http to https. 2235 nsCOMPtr<nsIURI> httpsURI; 2236 if (aURI->SchemeIs("http")) { 2237 nsCOMPtr<nsILoadInfo> httpsOnlyCheckLoadInfo = MOZ_TRY( 2238 LoadInfo::Create(loadingPrincipal, loadingPrincipal, nullptr, 2239 nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, 2240 nsIContentPolicy::TYPE_SPECULATIVE)); 2241 2242 // Check if https-only, or https-first would upgrade the request 2243 if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, httpsOnlyCheckLoadInfo) || 2244 nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest( 2245 aURI, httpsOnlyCheckLoadInfo)) { 2246 rv = NS_GetSecureUpgradedURI(aURI, getter_AddRefs(httpsURI)); 2247 NS_ENSURE_SUCCESS(rv, rv); 2248 aURI = httpsURI.get(); 2249 } 2250 } 2251 2252 // dummy channel used to create a TCP connection. 2253 // we perform security checks on the *real* channel, responsible 2254 // for any network loads. this real channel just checks the TCP 2255 // pool if there is an available connection created by the 2256 // channel we create underneath - hence it's safe to use 2257 // the systemPrincipal as the loadingPrincipal for this channel. 2258 nsCOMPtr<nsIChannel> channel; 2259 rv = NewChannelFromURI( 2260 aURI, 2261 nullptr, // aLoadingNode, 2262 loadingPrincipal, 2263 nullptr, // aTriggeringPrincipal, 2264 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, 2265 nsIContentPolicy::TYPE_SPECULATIVE, getter_AddRefs(channel)); 2266 NS_ENSURE_SUCCESS(rv, rv); 2267 2268 if (aAnonymous) { 2269 nsLoadFlags loadFlags = 0; 2270 channel->GetLoadFlags(&loadFlags); 2271 loadFlags |= nsIRequest::LOAD_ANONYMOUS; 2272 channel->SetLoadFlags(loadFlags); 2273 } 2274 2275 if (!aCallbacks) { 2276 // Proxy filters are registered, but no callbacks were provided. 2277 // When proxyDNS is true, this speculative connection would likely leak a 2278 // DNS lookup, so we should return early to avoid that. 2279 bool hasProxyFilterRegistered = false; 2280 (void)pps->GetHasProxyFilterRegistered(&hasProxyFilterRegistered); 2281 if (hasProxyFilterRegistered) { 2282 return NS_ERROR_FAILURE; 2283 } 2284 } else { 2285 rv = channel->SetNotificationCallbacks(aCallbacks); 2286 NS_ENSURE_SUCCESS(rv, rv); 2287 } 2288 2289 nsCOMPtr<nsICancelable> cancelable; 2290 RefPtr<IOServiceProxyCallback> callback = new IOServiceProxyCallback( 2291 aCallbacks, this, std::move(aOriginAttributes)); 2292 nsCOMPtr<nsIProtocolProxyService2> pps2 = do_QueryInterface(pps); 2293 if (pps2) { 2294 return pps2->AsyncResolve2(channel, 0, callback, nullptr, 2295 getter_AddRefs(cancelable)); 2296 } 2297 return pps->AsyncResolve(channel, 0, callback, nullptr, 2298 getter_AddRefs(cancelable)); 2299 } 2300 2301 NS_IMETHODIMP 2302 nsIOService::SpeculativeConnect(nsIURI* aURI, nsIPrincipal* aPrincipal, 2303 nsIInterfaceRequestor* aCallbacks, 2304 bool aAnonymous) { 2305 return SpeculativeConnectInternal(aURI, aPrincipal, Nothing(), aCallbacks, 2306 aAnonymous); 2307 } 2308 2309 NS_IMETHODIMP nsIOService::SpeculativeConnectWithOriginAttributes( 2310 nsIURI* aURI, JS::Handle<JS::Value> aOriginAttributes, 2311 nsIInterfaceRequestor* aCallbacks, bool aAnonymous, JSContext* aCx) { 2312 OriginAttributes attrs; 2313 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 2314 return NS_ERROR_INVALID_ARG; 2315 } 2316 2317 SpeculativeConnectWithOriginAttributesNative(aURI, std::move(attrs), 2318 aCallbacks, aAnonymous); 2319 return NS_OK; 2320 } 2321 2322 NS_IMETHODIMP_(void) 2323 nsIOService::SpeculativeConnectWithOriginAttributesNative( 2324 nsIURI* aURI, OriginAttributes&& aOriginAttributes, 2325 nsIInterfaceRequestor* aCallbacks, bool aAnonymous) { 2326 Maybe<OriginAttributes> originAttributes; 2327 originAttributes.emplace(aOriginAttributes); 2328 (void)SpeculativeConnectInternal(aURI, nullptr, std::move(originAttributes), 2329 aCallbacks, aAnonymous); 2330 } 2331 2332 NS_IMETHODIMP 2333 nsIOService::NotImplemented() { return NS_ERROR_NOT_IMPLEMENTED; } 2334 2335 NS_IMETHODIMP 2336 nsIOService::GetSocketProcessLaunched(bool* aResult) { 2337 NS_ENSURE_ARG_POINTER(aResult); 2338 2339 *aResult = SocketProcessReady(); 2340 return NS_OK; 2341 } 2342 2343 bool nsIOService::HasObservers(const char* aTopic) { 2344 MOZ_ASSERT(false, "Calling this method is unexpected"); 2345 return false; 2346 } 2347 2348 NS_IMETHODIMP 2349 nsIOService::GetSocketProcessId(uint64_t* aPid) { 2350 NS_ENSURE_ARG_POINTER(aPid); 2351 2352 *aPid = 0; 2353 if (!mSocketProcess) { 2354 return NS_OK; 2355 } 2356 2357 if (SocketProcessParent* actor = mSocketProcess->GetActor()) { 2358 *aPid = (uint64_t)actor->OtherPid(); 2359 } 2360 2361 return NS_OK; 2362 } 2363 2364 NS_IMETHODIMP 2365 nsIOService::RegisterProtocolHandler(const nsACString& aScheme, 2366 nsIProtocolHandler* aHandler, 2367 uint32_t aProtocolFlags, 2368 int32_t aDefaultPort) { 2369 if (mShutdown) { 2370 return NS_ERROR_NOT_AVAILABLE; 2371 } 2372 if (aScheme.IsEmpty()) { 2373 return NS_ERROR_INVALID_ARG; 2374 } 2375 2376 nsAutoCString scheme(aScheme); 2377 ToLowerCase(scheme); 2378 2379 AutoWriteLock lock(mLock); 2380 return mRuntimeProtocolHandlers.WithEntryHandle(scheme, [&](auto&& entry) { 2381 if (entry) { 2382 NS_WARNING("Cannot override an existing dynamic protocol handler"); 2383 return NS_ERROR_FACTORY_EXISTS; 2384 } 2385 if (xpcom::StaticProtocolHandler::Lookup(scheme)) { 2386 NS_WARNING("Cannot override an existing static protocol handler"); 2387 return NS_ERROR_FACTORY_EXISTS; 2388 } 2389 nsMainThreadPtrHandle<nsIProtocolHandler> handler( 2390 new nsMainThreadPtrHolder<nsIProtocolHandler>("RuntimeProtocolHandler", 2391 aHandler)); 2392 entry.Insert(RuntimeProtocolHandler{ 2393 .mHandler = std::move(handler), 2394 .mProtocolFlags = aProtocolFlags, 2395 .mDefaultPort = aDefaultPort, 2396 }); 2397 return NS_OK; 2398 }); 2399 } 2400 2401 NS_IMETHODIMP 2402 nsIOService::UnregisterProtocolHandler(const nsACString& aScheme) { 2403 if (mShutdown) { 2404 return NS_OK; 2405 } 2406 if (aScheme.IsEmpty()) { 2407 return NS_ERROR_INVALID_ARG; 2408 } 2409 2410 nsAutoCString scheme(aScheme); 2411 ToLowerCase(scheme); 2412 2413 AutoWriteLock lock(mLock); 2414 return mRuntimeProtocolHandlers.Remove(scheme) 2415 ? NS_OK 2416 : NS_ERROR_FACTORY_NOT_REGISTERED; 2417 } 2418 2419 NS_IMETHODIMP 2420 nsIOService::SetSimpleURIUnknownRemoteSchemes( 2421 const nsTArray<nsCString>& aRemoteSchemes) { 2422 LOG(("nsIOService::SetSimpleUriUnknownRemoteSchemes")); 2423 mSimpleURIUnknownSchemes.SetAndMergeRemoteSchemes(aRemoteSchemes); 2424 2425 if (XRE_IsParentProcess()) { 2426 // since we only expect socket, parent and content processes to create URLs 2427 // that need to check the bypass list 2428 // we only broadcast the list to content processes 2429 // (and leave socket process broadcast as todo if necessary) 2430 // 2431 // sending only the remote-settings schemes to the content, 2432 // which already has the pref list 2433 for (auto* cp : mozilla::dom::ContentParent::AllProcesses( 2434 mozilla::dom::ContentParent::eLive)) { 2435 (void)cp->SendSimpleURIUnknownRemoteSchemes(aRemoteSchemes); 2436 } 2437 } 2438 return NS_OK; 2439 } 2440 2441 // Check for any address space overrides for Local Network Access Checks 2442 // The override prefs should be set only for tests (controlled by 2443 // network_lna_blocking pref). 2444 NS_IMETHODIMP 2445 nsIOService::GetOverridenIpAddressSpace( 2446 nsILoadInfo::IPAddressSpace* aIpAddressSpace, const NetAddr& aAddr) { 2447 nsAutoCString addrPortString; 2448 2449 if (!StaticPrefs::network_lna_enabled()) { 2450 return NS_ERROR_FAILURE; 2451 } 2452 2453 { 2454 AutoReadLock lock(mLock); 2455 if (mPublicAddressSpaceOverridesList.IsEmpty() && 2456 mPrivateAddressSpaceOverridesList.IsEmpty() && 2457 mLocalAddressSpaceOverrideList.IsEmpty()) { 2458 return NS_ERROR_FAILURE; 2459 } 2460 } 2461 2462 aAddr.ToAddrPortString(addrPortString); 2463 addrPortString.StripWhitespace(); 2464 AutoReadLock lock(mLock); 2465 2466 for (const auto& ipAddr : mPublicAddressSpaceOverridesList) { 2467 if (addrPortString.Equals(ipAddr)) { 2468 *aIpAddressSpace = nsILoadInfo::IPAddressSpace::Public; 2469 return NS_OK; 2470 } 2471 } 2472 2473 for (const auto& ipAddr : mPrivateAddressSpaceOverridesList) { 2474 if (addrPortString.Equals(ipAddr)) { 2475 *aIpAddressSpace = nsILoadInfo::IPAddressSpace::Private; 2476 return NS_OK; 2477 } 2478 } 2479 2480 for (const auto& ipAddr : mLocalAddressSpaceOverrideList) { 2481 if (addrPortString.Equals(ipAddr)) { 2482 *aIpAddressSpace = nsILoadInfo::IPAddressSpace::Local; 2483 return NS_OK; 2484 } 2485 } 2486 2487 *aIpAddressSpace = nsILoadInfo::IPAddressSpace::Unknown; 2488 return NS_ERROR_FAILURE; 2489 } 2490 2491 NS_IMETHODIMP 2492 nsIOService::IsSimpleURIUnknownScheme(const nsACString& aScheme, 2493 bool* _retval) { 2494 *_retval = mSimpleURIUnknownSchemes.IsSimpleURIUnknownScheme(aScheme); 2495 return NS_OK; 2496 } 2497 2498 NS_IMETHODIMP 2499 nsIOService::GetSimpleURIUnknownRemoteSchemes(nsTArray<nsCString>& _retval) { 2500 mSimpleURIUnknownSchemes.GetRemoteSchemes(_retval); 2501 return NS_OK; 2502 } 2503 2504 NS_IMETHODIMP 2505 nsIOService::AddEssentialDomainMapping(const nsACString& aFrom, 2506 const nsACString& aTo) { 2507 MOZ_ASSERT(NS_IsMainThread()); 2508 mEssentialDomainMapping.InsertOrUpdate(aFrom, aTo); 2509 return NS_OK; 2510 } 2511 2512 NS_IMETHODIMP 2513 nsIOService::ClearEssentialDomainMapping() { 2514 MOZ_ASSERT(NS_IsMainThread()); 2515 mEssentialDomainMapping.Clear(); 2516 return NS_OK; 2517 } 2518 2519 bool nsIOService::GetFallbackDomain(const nsACString& aDomain, 2520 nsACString& aFallbackDomain) { 2521 MOZ_ASSERT(NS_IsMainThread()); 2522 if (auto entry = mEssentialDomainMapping.Lookup(aDomain)) { 2523 aFallbackDomain = entry.Data(); 2524 return true; 2525 } 2526 return false; 2527 } 2528 2529 NS_IMETHODIMP 2530 nsIOService::ParseCacheControlHeader(const nsACString& aCacheControlHeader, 2531 JSContext* cx, 2532 JS::MutableHandle<JS::Value> _retval) { 2533 MOZ_ASSERT(NS_IsMainThread()); 2534 2535 mozilla::dom::HTTPCacheControlParseResult result; 2536 CacheControlParser parser(aCacheControlHeader); 2537 2538 bool didParseValue = false; 2539 2540 uint32_t maxAge = 0; 2541 didParseValue = parser.MaxAge(&maxAge); 2542 if (didParseValue) { 2543 result.mMaxAge = maxAge; 2544 } 2545 2546 uint32_t maxStale = 0; 2547 didParseValue = parser.MaxStale(&maxStale); 2548 if (didParseValue) { 2549 result.mMaxStale = maxStale; 2550 } 2551 2552 uint32_t minFresh = 0; 2553 didParseValue = parser.MaxStale(&minFresh); 2554 if (didParseValue) { 2555 result.mMinFresh = minFresh; 2556 } 2557 2558 uint32_t staleWhileRevalidate = 0; 2559 didParseValue = parser.StaleWhileRevalidate(&staleWhileRevalidate); 2560 if (didParseValue) { 2561 result.mStaleWhileRevalidate = staleWhileRevalidate; 2562 } 2563 2564 result.mNoCache = parser.NoCache(); 2565 result.mNoStore = parser.NoStore(); 2566 result.mPublic = parser.Public(); 2567 result.mPrivate = parser.Private(); 2568 result.mImmutable = parser.Immutable(); 2569 2570 if (!ToJSValue(cx, result, _retval)) { 2571 return NS_ERROR_FAILURE; 2572 } 2573 return NS_OK; 2574 } 2575 2576 } // namespace net 2577 } // namespace mozilla