nsNetUtil.cpp (146888B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=4 sw=2 sts=2 et cin: */ 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 // HttpLog.h should generally be included first 8 #include "DecoderDoctorDiagnostics.h" 9 #include "HttpLog.h" 10 11 #include "nsNetUtil.h" 12 13 #include "mozilla/Atomics.h" 14 #include "mozilla/BasePrincipal.h" 15 #include "mozilla/Components.h" 16 #include "mozilla/Encoding.h" 17 #include "mozilla/LoadContext.h" 18 #include "mozilla/LoadInfo.h" 19 #include "mozilla/MathAlgorithms.h" 20 #include "mozilla/Monitor.h" 21 #include "mozilla/StaticPrefs_browser.h" 22 #include "mozilla/StaticPrefs_network.h" 23 #include "mozilla/StaticPrefs_privacy.h" 24 #include "mozilla/StaticPrefs_urlclassifier.h" 25 #include "mozilla/StoragePrincipalHelper.h" 26 #include "mozilla/TaskQueue.h" 27 #include "nsAboutProtocolUtils.h" 28 #include "nsBufferedStreams.h" 29 #include "nsCategoryCache.h" 30 #include "nsComponentManagerUtils.h" 31 #include "nsContentUtils.h" 32 #include "nsEscape.h" 33 #include "nsFileStreams.h" 34 #include "nsHashKeys.h" 35 #include "nsHttp.h" 36 #include "nsMimeTypes.h" 37 #include "nsIAuthPrompt.h" 38 #include "nsIAuthPrompt2.h" 39 #include "nsIAuthPromptAdapterFactory.h" 40 #include "nsIBufferedStreams.h" 41 #include "nsBufferedStreams.h" 42 #include "nsIChannelEventSink.h" 43 #include "nsIClassifiedChannel.h" 44 #include "nsIContentSniffer.h" 45 #include "mozilla/dom/Document.h" 46 #include "nsIDownloader.h" 47 #include "nsIFileProtocolHandler.h" 48 #include "nsIFileStreams.h" 49 #include "nsIFileURL.h" 50 #include "nsIIDNService.h" 51 #include "nsIInputStreamChannel.h" 52 #include "nsIInputStreamPump.h" 53 #include "nsIInterfaceRequestorUtils.h" 54 #include "nsILoadContext.h" 55 #include "nsIMIMEHeaderParam.h" 56 #include "nsINode.h" 57 #include "nsIObjectLoadingContent.h" 58 #include "nsPersistentProperties.h" 59 #include "nsIPrivateBrowsingChannel.h" 60 #include "nsIPropertyBag2.h" 61 #include "nsIProtocolProxyService.h" 62 #include "mozilla/net/RedirectChannelRegistrar.h" 63 #include "nsRequestObserverProxy.h" 64 #include "nsISensitiveInfoHiddenURI.h" 65 #include "nsISimpleStreamListener.h" 66 #include "nsISocketProvider.h" 67 #include "nsIStandardURL.h" 68 #include "nsIStreamLoader.h" 69 #include "nsIIncrementalStreamLoader.h" 70 #include "nsStringStream.h" 71 #include "nsSyncStreamListener.h" 72 #include "nsITextToSubURI.h" 73 #include "nsIURIWithSpecialOrigin.h" 74 #include "nsIViewSourceChannel.h" 75 #include "nsInterfaceRequestorAgg.h" 76 #include "nsINestedURI.h" 77 #include "mozilla/dom/nsCSPUtils.h" 78 #include "mozilla/dom/nsHTTPSOnlyUtils.h" 79 #include "mozilla/dom/nsMixedContentBlocker.h" 80 #include "mozilla/dom/BlobURLProtocolHandler.h" 81 #include "mozilla/net/HttpBaseChannel.h" 82 #include "nsIScriptError.h" 83 #include "nsISiteSecurityService.h" 84 #include "nsHttpHandler.h" 85 #include "nsNSSComponent.h" 86 #include "nsIRedirectHistoryEntry.h" 87 #include "nsICertStorage.h" 88 #include "nsICertOverrideService.h" 89 #include "nsQueryObject.h" 90 #include "mozIThirdPartyUtil.h" 91 #include "../mime/nsMIMEHeaderParamImpl.h" 92 #include "nsStandardURL.h" 93 #include "DefaultURI.h" 94 #include "nsChromeProtocolHandler.h" 95 #include "nsJSProtocolHandler.h" 96 #include "nsDataHandler.h" 97 #include "mozilla/dom/BlobURLProtocolHandler.h" 98 #include "nsStreamUtils.h" 99 #include "nsSocketTransportService2.h" 100 #include "nsViewSourceHandler.h" 101 #include "nsJARURI.h" 102 #ifndef XP_IOS 103 # include "nsIconURI.h" 104 #endif 105 #include "nsAboutProtocolHandler.h" 106 #include "nsResProtocolHandler.h" 107 #include "mozilla/net/CookieJarSettings.h" 108 #include "mozilla/net/MozSrcProtocolHandler.h" 109 #include "mozilla/net/ExtensionProtocolHandler.h" 110 #include "mozilla/net/MozNewTabWallpaperProtocolHandler.h" 111 #include "mozilla/net/PageThumbProtocolHandler.h" 112 #include "mozilla/net/SFVService.h" 113 #include "nsICookieService.h" 114 #include "nsIXPConnect.h" 115 #include "nsParserConstants.h" 116 #include "nsCRT.h" 117 #include "nsServiceManagerUtils.h" 118 #include "mozilla/dom/MediaList.h" 119 #include "MediaContainerType.h" 120 #include "DecoderTraits.h" 121 #include "imgLoader.h" 122 123 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) 124 # include "nsNewMailnewsURI.h" 125 #endif 126 127 using namespace mozilla; 128 using namespace mozilla::net; 129 using mozilla::dom::BlobURLProtocolHandler; 130 using mozilla::dom::ClientInfo; 131 using mozilla::dom::PerformanceStorage; 132 using mozilla::dom::ServiceWorkerDescriptor; 133 134 #define MAX_RECURSION_COUNT 50 135 136 enum class ClassifierMode { 137 Disabled = 0, 138 AntiTracking = 1, 139 SafeBrowsing = 2, 140 Enabled = 3, 141 }; 142 143 already_AddRefed<nsIIOService> do_GetIOService(nsresult* error /* = 0 */) { 144 nsCOMPtr<nsIIOService> io; 145 io = mozilla::components::IO::Service(); 146 if (error) *error = io ? NS_OK : NS_ERROR_FAILURE; 147 return io.forget(); 148 } 149 150 nsresult NS_NewLocalFileInputStream(nsIInputStream** result, nsIFile* file, 151 int32_t ioFlags /* = -1 */, 152 int32_t perm /* = -1 */, 153 int32_t behaviorFlags /* = 0 */) { 154 nsresult rv; 155 nsCOMPtr<nsIFileInputStream> in = 156 do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv); 157 if (NS_SUCCEEDED(rv)) { 158 rv = in->Init(file, ioFlags, perm, behaviorFlags); 159 if (NS_SUCCEEDED(rv)) in.forget(result); 160 } 161 return rv; 162 } 163 164 Result<nsCOMPtr<nsIInputStream>, nsresult> NS_NewLocalFileInputStream( 165 nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */, 166 int32_t behaviorFlags /* = 0 */) { 167 nsCOMPtr<nsIInputStream> stream; 168 const nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file, 169 ioFlags, perm, behaviorFlags); 170 if (NS_SUCCEEDED(rv)) { 171 return stream; 172 } 173 return Err(rv); 174 } 175 176 nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result, nsIFile* file, 177 int32_t ioFlags /* = -1 */, 178 int32_t perm /* = -1 */, 179 int32_t behaviorFlags /* = 0 */) { 180 nsresult rv; 181 nsCOMPtr<nsIFileOutputStream> out = 182 do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv); 183 if (NS_SUCCEEDED(rv)) { 184 rv = out->Init(file, ioFlags, perm, behaviorFlags); 185 if (NS_SUCCEEDED(rv)) out.forget(result); 186 } 187 return rv; 188 } 189 190 Result<nsCOMPtr<nsIOutputStream>, nsresult> NS_NewLocalFileOutputStream( 191 nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */, 192 int32_t behaviorFlags /* = 0 */) { 193 nsCOMPtr<nsIOutputStream> stream; 194 const nsresult rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), file, 195 ioFlags, perm, behaviorFlags); 196 if (NS_SUCCEEDED(rv)) { 197 return stream; 198 } 199 return Err(rv); 200 } 201 202 nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result, 203 const mozilla::ipc::FileDescriptor& fd) { 204 nsCOMPtr<nsIFileOutputStream> out; 205 nsFileOutputStream::Create(NS_GET_IID(nsIFileOutputStream), 206 getter_AddRefs(out)); 207 208 nsresult rv = 209 static_cast<nsFileOutputStream*>(out.get())->InitWithFileDescriptor(fd); 210 if (NS_FAILED(rv)) { 211 return rv; 212 } 213 214 out.forget(result); 215 return NS_OK; 216 } 217 218 nsresult net_EnsureIOService(nsIIOService** ios, nsCOMPtr<nsIIOService>& grip) { 219 nsresult rv = NS_OK; 220 if (!*ios) { 221 grip = do_GetIOService(&rv); 222 *ios = grip; 223 } 224 return rv; 225 } 226 227 nsresult NS_NewFileURI( 228 nsIURI** result, nsIFile* spec, 229 nsIIOService* 230 ioService /* = nullptr */) // pass in nsIIOService to optimize callers 231 { 232 nsresult rv; 233 nsCOMPtr<nsIIOService> grip; 234 rv = net_EnsureIOService(&ioService, grip); 235 if (ioService) rv = ioService->NewFileURI(spec, result); 236 return rv; 237 } 238 239 nsresult NS_GetURIWithNewRef(nsIURI* aInput, const nsACString& aRef, 240 nsIURI** aOutput) { 241 MOZ_DIAGNOSTIC_ASSERT(aRef.IsEmpty() || aRef[0] == '#'); 242 243 if (NS_WARN_IF(!aInput || !aOutput)) { 244 return NS_ERROR_INVALID_ARG; 245 } 246 247 bool hasRef; 248 nsresult rv = aInput->GetHasRef(&hasRef); 249 250 nsAutoCString ref; 251 if (NS_SUCCEEDED(rv)) { 252 rv = aInput->GetRef(ref); 253 } 254 255 // If the ref is already equal to the new ref, we do not need to do anything. 256 // Also, if the GetRef failed (it could return NS_ERROR_NOT_IMPLEMENTED) 257 // we can assume SetRef would fail as well, so returning the original 258 // URI is OK. 259 // 260 // Note that aRef contains the hash, but ref doesn't, so need to account for 261 // that in the equality check. 262 if (NS_FAILED(rv) || (!hasRef && aRef.IsEmpty()) || 263 (!aRef.IsEmpty() && hasRef && 264 Substring(aRef.Data() + 1, aRef.Length() - 1) == ref)) { 265 nsCOMPtr<nsIURI> uri = aInput; 266 uri.forget(aOutput); 267 return NS_OK; 268 } 269 270 return NS_MutateURI(aInput).SetRef(aRef).Finalize(aOutput); 271 } 272 273 nsresult NS_GetURIWithoutRef(nsIURI* aInput, nsIURI** aOutput) { 274 return NS_GetURIWithNewRef(aInput, ""_ns, aOutput); 275 } 276 277 nsresult NS_NewChannelInternal( 278 nsIChannel** outChannel, nsIURI* aUri, nsILoadInfo* aLoadInfo, 279 PerformanceStorage* aPerformanceStorage /* = nullptr */, 280 nsILoadGroup* aLoadGroup /* = nullptr */, 281 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 282 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */, 283 nsIIOService* aIoService /* = nullptr */) { 284 // NS_NewChannelInternal is mostly called for channel redirects. We should 285 // allow the creation of a channel even if the original channel did not have a 286 // loadinfo attached. 287 NS_ENSURE_ARG_POINTER(outChannel); 288 289 nsCOMPtr<nsIIOService> grip; 290 nsresult rv = net_EnsureIOService(&aIoService, grip); 291 NS_ENSURE_SUCCESS(rv, rv); 292 293 nsCOMPtr<nsIChannel> channel; 294 rv = aIoService->NewChannelFromURIWithLoadInfo(aUri, aLoadInfo, 295 getter_AddRefs(channel)); 296 NS_ENSURE_SUCCESS(rv, rv); 297 298 if (aLoadGroup) { 299 rv = channel->SetLoadGroup(aLoadGroup); 300 NS_ENSURE_SUCCESS(rv, rv); 301 } 302 303 if (aCallbacks) { 304 rv = channel->SetNotificationCallbacks(aCallbacks); 305 NS_ENSURE_SUCCESS(rv, rv); 306 } 307 308 #ifdef DEBUG 309 nsLoadFlags channelLoadFlags = 0; 310 channel->GetLoadFlags(&channelLoadFlags); 311 // Will be removed when we remove LOAD_REPLACE altogether 312 // This check is trying to catch protocol handlers that still 313 // try to set the LOAD_REPLACE flag. 314 MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE)); 315 #endif 316 317 if (aLoadFlags != nsIRequest::LOAD_NORMAL) { 318 rv = channel->SetLoadFlags(aLoadFlags); 319 NS_ENSURE_SUCCESS(rv, rv); 320 } 321 322 if (aPerformanceStorage) { 323 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo(); 324 loadInfo->SetPerformanceStorage(aPerformanceStorage); 325 } 326 327 channel.forget(outChannel); 328 return NS_OK; 329 } 330 331 namespace { 332 333 void AssertLoadingPrincipalAndClientInfoMatch( 334 nsIPrincipal* aLoadingPrincipal, const ClientInfo& aLoadingClientInfo, 335 nsContentPolicyType aType) { 336 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 337 // Verify that the provided loading ClientInfo matches the loading 338 // principal. Unfortunately we can't just use nsIPrincipal::Equals() here 339 // because of some corner cases: 340 // 341 // 1. Worker debugger scripts want to use a system loading principal for 342 // worker scripts with a content principal. We exempt these from this 343 // check. 344 // 2. Null principals currently require exact object identity for 345 // nsIPrincipal::Equals() to return true. This doesn't work here because 346 // ClientInfo::GetPrincipal() uses PrincipalInfoToPrincipal() to allocate 347 // a new object. To work around this we compare the principal origin 348 // string itself. If bug 1431771 is fixed then we could switch to 349 // Equals(). 350 351 // Allow worker debugger to load with a system principal. 352 if (aLoadingPrincipal->IsSystemPrincipal() && 353 (aType == nsIContentPolicy::TYPE_INTERNAL_WORKER || 354 aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER || 355 aType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER || 356 aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS || 357 aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE)) { 358 return; 359 } 360 361 // Perform a fast comparison for most principal checks. 362 auto clientPrincipalOrErr(aLoadingClientInfo.GetPrincipal()); 363 if (clientPrincipalOrErr.isOk()) { 364 nsCOMPtr<nsIPrincipal> clientPrincipal = clientPrincipalOrErr.unwrap(); 365 if (aLoadingPrincipal->Equals(clientPrincipal)) { 366 return; 367 } 368 // Fall back to a slower origin equality test to support null principals. 369 nsAutoCString loadingOriginNoSuffix; 370 MOZ_ALWAYS_SUCCEEDS( 371 aLoadingPrincipal->GetOriginNoSuffix(loadingOriginNoSuffix)); 372 373 nsAutoCString clientOriginNoSuffix; 374 MOZ_ALWAYS_SUCCEEDS( 375 clientPrincipal->GetOriginNoSuffix(clientOriginNoSuffix)); 376 377 // The client principal will have the partitionKey set if it's in a third 378 // party context, but the loading principal won't. So, we ignore he 379 // partitionKey when doing the verification here. 380 MOZ_DIAGNOSTIC_ASSERT(loadingOriginNoSuffix == clientOriginNoSuffix); 381 MOZ_DIAGNOSTIC_ASSERT( 382 aLoadingPrincipal->OriginAttributesRef().EqualsIgnoringPartitionKey( 383 clientPrincipal->OriginAttributesRef())); 384 } 385 #endif 386 } 387 388 } // namespace 389 390 nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri, 391 nsIPrincipal* aLoadingPrincipal, 392 nsSecurityFlags aSecurityFlags, 393 nsContentPolicyType aContentPolicyType, 394 nsICookieJarSettings* aCookieJarSettings /* = nullptr */, 395 PerformanceStorage* aPerformanceStorage /* = nullptr */, 396 nsILoadGroup* aLoadGroup /* = nullptr */, 397 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 398 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */, 399 nsIIOService* aIoService /* = nullptr */, 400 uint32_t aSandboxFlags /* = 0 */) { 401 return NS_NewChannelInternal( 402 outChannel, aUri, 403 nullptr, // aLoadingNode, 404 aLoadingPrincipal, 405 nullptr, // aTriggeringPrincipal 406 Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, 407 aContentPolicyType, aCookieJarSettings, aPerformanceStorage, aLoadGroup, 408 aCallbacks, aLoadFlags, aIoService, aSandboxFlags); 409 } 410 411 nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri, 412 nsIPrincipal* aLoadingPrincipal, 413 const ClientInfo& aLoadingClientInfo, 414 const Maybe<ServiceWorkerDescriptor>& aController, 415 nsSecurityFlags aSecurityFlags, 416 nsContentPolicyType aContentPolicyType, 417 nsICookieJarSettings* aCookieJarSettings /* = nullptr */, 418 PerformanceStorage* aPerformanceStorage /* = nullptr */, 419 nsILoadGroup* aLoadGroup /* = nullptr */, 420 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 421 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */, 422 nsIIOService* aIoService /* = nullptr */, 423 uint32_t aSandboxFlags /* = 0 */) { 424 AssertLoadingPrincipalAndClientInfoMatch( 425 aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType); 426 427 Maybe<ClientInfo> loadingClientInfo; 428 loadingClientInfo.emplace(aLoadingClientInfo); 429 430 return NS_NewChannelInternal(outChannel, aUri, 431 nullptr, // aLoadingNode, 432 aLoadingPrincipal, 433 nullptr, // aTriggeringPrincipal 434 loadingClientInfo, aController, aSecurityFlags, 435 aContentPolicyType, aCookieJarSettings, 436 aPerformanceStorage, aLoadGroup, aCallbacks, 437 aLoadFlags, aIoService, aSandboxFlags); 438 } 439 440 nsresult NS_NewChannelInternal( 441 nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode, 442 nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, 443 const Maybe<ClientInfo>& aLoadingClientInfo, 444 const Maybe<ServiceWorkerDescriptor>& aController, 445 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType, 446 nsICookieJarSettings* aCookieJarSettings /* = nullptr */, 447 PerformanceStorage* aPerformanceStorage /* = nullptr */, 448 nsILoadGroup* aLoadGroup /* = nullptr */, 449 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 450 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */, 451 nsIIOService* aIoService /* = nullptr */, 452 uint32_t aSandboxFlags /* = 0 */) { 453 NS_ENSURE_ARG_POINTER(outChannel); 454 455 nsCOMPtr<nsIIOService> grip; 456 nsresult rv = net_EnsureIOService(&aIoService, grip); 457 NS_ENSURE_SUCCESS(rv, rv); 458 459 nsCOMPtr<nsIChannel> channel; 460 rv = aIoService->NewChannelFromURIWithClientAndController( 461 aUri, aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal, 462 aLoadingClientInfo, aController, aSecurityFlags, aContentPolicyType, 463 aSandboxFlags, getter_AddRefs(channel)); 464 if (NS_FAILED(rv)) { 465 return rv; 466 } 467 468 if (aLoadGroup) { 469 rv = channel->SetLoadGroup(aLoadGroup); 470 NS_ENSURE_SUCCESS(rv, rv); 471 } 472 473 if (aCallbacks) { 474 rv = channel->SetNotificationCallbacks(aCallbacks); 475 NS_ENSURE_SUCCESS(rv, rv); 476 } 477 478 #ifdef DEBUG 479 nsLoadFlags channelLoadFlags = 0; 480 channel->GetLoadFlags(&channelLoadFlags); 481 // Will be removed when we remove LOAD_REPLACE altogether 482 // This check is trying to catch protocol handlers that still 483 // try to set the LOAD_REPLACE flag. 484 MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE)); 485 #endif 486 487 if (aLoadFlags != nsIRequest::LOAD_NORMAL) { 488 rv = channel->SetLoadFlags(aLoadFlags); 489 NS_ENSURE_SUCCESS(rv, rv); 490 } 491 492 if (aPerformanceStorage || aCookieJarSettings) { 493 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo(); 494 495 if (aPerformanceStorage) { 496 loadInfo->SetPerformanceStorage(aPerformanceStorage); 497 } 498 499 if (aCookieJarSettings) { 500 loadInfo->SetCookieJarSettings(aCookieJarSettings); 501 } 502 } 503 504 if (aLoadingNode) { 505 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo(); 506 ClassificationFlags flags = 507 aLoadingNode->OwnerDoc()->GetScriptTrackingFlags(); 508 509 loadInfo->SetTriggeringFirstPartyClassificationFlags(flags.firstPartyFlags); 510 loadInfo->SetTriggeringThirdPartyClassificationFlags(flags.thirdPartyFlags); 511 } 512 513 channel.forget(outChannel); 514 return NS_OK; 515 } 516 517 nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */ 518 NS_NewChannelWithTriggeringPrincipal( 519 nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode, 520 nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags, 521 nsContentPolicyType aContentPolicyType, 522 PerformanceStorage* aPerformanceStorage /* = nullptr */, 523 nsILoadGroup* aLoadGroup /* = nullptr */, 524 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 525 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */, 526 nsIIOService* aIoService /* = nullptr */) { 527 MOZ_ASSERT(aLoadingNode); 528 NS_ASSERTION(aTriggeringPrincipal, 529 "Can not create channel without a triggering Principal!"); 530 531 nsCOMPtr<nsICookieJarSettings> cookieJarSettings; 532 533 // Special treatment for resources injected by add-ons if not document, 534 // iframe, workers. 535 if (!nsContentUtils::IsNonSubresourceInternalPolicyType(aContentPolicyType) && 536 aTriggeringPrincipal && 537 StaticPrefs::privacy_antitracking_isolateContentScriptResources() && 538 nsContentUtils::IsExpandedPrincipal(aTriggeringPrincipal)) { 539 bool shouldResistFingerprinting = 540 nsContentUtils::ShouldResistFingerprinting_dangerous( 541 aLoadingNode->NodePrincipal(), 542 "CookieJarSettings can't exist yet, we're creating it", 543 RFPTarget::IsAlwaysEnabledForPrecompute); 544 cookieJarSettings = CookieJarSettings::Create( 545 nsICookieService::BEHAVIOR_REJECT, 546 StoragePrincipalHelper::PartitionKeyForExpandedPrincipal( 547 aTriggeringPrincipal), 548 OriginAttributes::IsFirstPartyEnabled(), false, 549 shouldResistFingerprinting); 550 } else { 551 // Let's inherit the cookie behavior and permission from the parent 552 // document. 553 cookieJarSettings = aLoadingNode->OwnerDoc()->CookieJarSettings(); 554 } 555 556 return NS_NewChannelInternal( 557 outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(), 558 aTriggeringPrincipal, Maybe<ClientInfo>(), 559 Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType, 560 cookieJarSettings, aPerformanceStorage, aLoadGroup, aCallbacks, 561 aLoadFlags, aIoService); 562 } 563 564 // See NS_NewChannelInternal for usage and argument description 565 nsresult NS_NewChannelWithTriggeringPrincipal( 566 nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal, 567 nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags, 568 nsContentPolicyType aContentPolicyType, 569 nsICookieJarSettings* aCookieJarSettings /* = nullptr */, 570 PerformanceStorage* aPerformanceStorage /* = nullptr */, 571 nsILoadGroup* aLoadGroup /* = nullptr */, 572 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 573 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */, 574 nsIIOService* aIoService /* = nullptr */) { 575 NS_ASSERTION(aLoadingPrincipal, 576 "Can not create channel without a loading Principal!"); 577 return NS_NewChannelInternal( 578 outChannel, aUri, 579 nullptr, // aLoadingNode 580 aLoadingPrincipal, aTriggeringPrincipal, Maybe<ClientInfo>(), 581 Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType, 582 aCookieJarSettings, aPerformanceStorage, aLoadGroup, aCallbacks, 583 aLoadFlags, aIoService); 584 } 585 586 // See NS_NewChannelInternal for usage and argument description 587 nsresult NS_NewChannelWithTriggeringPrincipal( 588 nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal, 589 nsIPrincipal* aTriggeringPrincipal, const ClientInfo& aLoadingClientInfo, 590 const Maybe<ServiceWorkerDescriptor>& aController, 591 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType, 592 nsICookieJarSettings* aCookieJarSettings /* = nullptr */, 593 PerformanceStorage* aPerformanceStorage /* = nullptr */, 594 nsILoadGroup* aLoadGroup /* = nullptr */, 595 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 596 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */, 597 nsIIOService* aIoService /* = nullptr */) { 598 AssertLoadingPrincipalAndClientInfoMatch( 599 aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType); 600 601 Maybe<ClientInfo> loadingClientInfo; 602 loadingClientInfo.emplace(aLoadingClientInfo); 603 604 return NS_NewChannelInternal( 605 outChannel, aUri, 606 nullptr, // aLoadingNode 607 aLoadingPrincipal, aTriggeringPrincipal, loadingClientInfo, aController, 608 aSecurityFlags, aContentPolicyType, aCookieJarSettings, 609 aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService); 610 } 611 612 nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri, 613 nsINode* aLoadingNode, nsSecurityFlags aSecurityFlags, 614 nsContentPolicyType aContentPolicyType, 615 PerformanceStorage* aPerformanceStorage /* = nullptr */, 616 nsILoadGroup* aLoadGroup /* = nullptr */, 617 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 618 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */, 619 nsIIOService* aIoService /* = nullptr */, 620 uint32_t aSandboxFlags /* = 0 */) { 621 NS_ASSERTION(aLoadingNode, "Can not create channel without a loading Node!"); 622 return NS_NewChannelInternal( 623 outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(), 624 nullptr, // aTriggeringPrincipal 625 Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, 626 aContentPolicyType, aLoadingNode->OwnerDoc()->CookieJarSettings(), 627 aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService, 628 aSandboxFlags); 629 } 630 631 nsresult NS_GetIsDocumentChannel(nsIChannel* aChannel, bool* aIsDocument) { 632 // Check if this channel is going to be used to create a document. If it has 633 // LOAD_DOCUMENT_URI set it is trivially creating a document. If 634 // LOAD_HTML_OBJECT_DATA is set it may or may not be used to create a 635 // document, depending on its MIME type. 636 637 if (!aChannel || !aIsDocument) { 638 return NS_ERROR_NULL_POINTER; 639 } 640 *aIsDocument = false; 641 nsLoadFlags loadFlags; 642 nsresult rv = aChannel->GetLoadFlags(&loadFlags); 643 if (NS_FAILED(rv)) { 644 return rv; 645 } 646 if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) { 647 *aIsDocument = true; 648 return NS_OK; 649 } 650 if (!(loadFlags & nsIRequest::LOAD_HTML_OBJECT_DATA)) { 651 *aIsDocument = false; 652 return NS_OK; 653 } 654 nsAutoCString mimeType; 655 rv = aChannel->GetContentType(mimeType); 656 if (NS_FAILED(rv)) { 657 return rv; 658 } 659 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); 660 if (nsContentUtils::HtmlObjectContentTypeForMIMEType( 661 mimeType, loadInfo->GetSandboxFlags()) == 662 nsIObjectLoadingContent::TYPE_DOCUMENT) { 663 *aIsDocument = true; 664 return NS_OK; 665 } 666 *aIsDocument = false; 667 return NS_OK; 668 } 669 670 nsresult NS_MakeAbsoluteURI(nsACString& result, const nsACString& spec, 671 nsIURI* baseURI) { 672 nsresult rv; 673 if (!baseURI) { 674 NS_WARNING("It doesn't make sense to not supply a base URI"); 675 result = spec; 676 rv = NS_OK; 677 } else if (spec.IsEmpty()) { 678 rv = baseURI->GetSpec(result); 679 } else { 680 rv = baseURI->Resolve(spec, result); 681 } 682 return rv; 683 } 684 685 nsresult NS_MakeAbsoluteURI(char** result, const char* spec, nsIURI* baseURI) { 686 nsresult rv; 687 nsAutoCString resultBuf; 688 rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI); 689 if (NS_SUCCEEDED(rv)) { 690 *result = ToNewCString(resultBuf, mozilla::fallible); 691 if (!*result) rv = NS_ERROR_OUT_OF_MEMORY; 692 } 693 return rv; 694 } 695 696 nsresult NS_MakeAbsoluteURI(nsAString& result, const nsAString& spec, 697 nsIURI* baseURI) { 698 nsresult rv; 699 if (!baseURI) { 700 NS_WARNING("It doesn't make sense to not supply a base URI"); 701 result = spec; 702 rv = NS_OK; 703 } else { 704 nsAutoCString resultBuf; 705 if (spec.IsEmpty()) { 706 rv = baseURI->GetSpec(resultBuf); 707 } else { 708 rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf); 709 } 710 if (NS_SUCCEEDED(rv)) CopyUTF8toUTF16(resultBuf, result); 711 } 712 return rv; 713 } 714 715 int32_t NS_GetDefaultPort(const char* scheme, 716 nsIIOService* ioService /* = nullptr */) { 717 nsresult rv; 718 719 // Getting the default port through the protocol handler previously had a lot 720 // of XPCOM overhead involved. We optimize the protocols that matter for Web 721 // pages (HTTP and HTTPS) by hardcoding their default ports here. 722 // 723 // XXX: This might not be necessary for performance anymore. 724 if (strncmp(scheme, "http", 4) == 0) { 725 if (scheme[4] == 's' && scheme[5] == '\0') { 726 return 443; 727 } 728 if (scheme[4] == '\0') { 729 return 80; 730 } 731 } 732 733 nsCOMPtr<nsIIOService> grip; 734 net_EnsureIOService(&ioService, grip); 735 if (!ioService) return -1; 736 737 int32_t port; 738 rv = ioService->GetDefaultPort(scheme, &port); 739 return NS_SUCCEEDED(rv) ? port : -1; 740 } 741 742 int32_t NS_GetRealPort(nsIURI* aURI) { 743 int32_t port; 744 nsresult rv = aURI->GetPort(&port); 745 if (NS_FAILED(rv)) return -1; 746 747 if (port != -1) return port; // explicitly specified 748 749 // Otherwise, we have to get the default port from the protocol handler 750 751 // Need the scheme first 752 nsAutoCString scheme; 753 rv = aURI->GetScheme(scheme); 754 if (NS_FAILED(rv)) return -1; 755 756 return NS_GetDefaultPort(scheme.get()); 757 } 758 759 nsresult NS_NewInputStreamChannelInternal( 760 nsIChannel** outChannel, nsIURI* aUri, 761 already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType, 762 const nsACString& aContentCharset, nsILoadInfo* aLoadInfo) { 763 nsresult rv; 764 nsCOMPtr<nsIInputStreamChannel> isc = 765 do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv); 766 NS_ENSURE_SUCCESS(rv, rv); 767 rv = isc->SetURI(aUri); 768 NS_ENSURE_SUCCESS(rv, rv); 769 770 nsCOMPtr<nsIInputStream> stream = std::move(aStream); 771 rv = isc->SetContentStream(stream); 772 NS_ENSURE_SUCCESS(rv, rv); 773 774 nsCOMPtr<nsIChannel> channel = do_QueryInterface(isc, &rv); 775 NS_ENSURE_SUCCESS(rv, rv); 776 777 if (!aContentType.IsEmpty()) { 778 rv = channel->SetContentType(aContentType); 779 NS_ENSURE_SUCCESS(rv, rv); 780 } 781 782 if (!aContentCharset.IsEmpty()) { 783 rv = channel->SetContentCharset(aContentCharset); 784 NS_ENSURE_SUCCESS(rv, rv); 785 } 786 787 MOZ_ASSERT(aLoadInfo, "need a loadinfo to create a inputstreamchannel"); 788 channel->SetLoadInfo(aLoadInfo); 789 790 // If we're sandboxed, make sure to clear any owner the channel 791 // might already have. 792 if (aLoadInfo && aLoadInfo->GetLoadingSandboxed()) { 793 channel->SetOwner(nullptr); 794 } 795 796 channel.forget(outChannel); 797 return NS_OK; 798 } 799 800 nsresult NS_NewInputStreamChannelInternal( 801 nsIChannel** outChannel, nsIURI* aUri, 802 already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType, 803 const nsACString& aContentCharset, nsINode* aLoadingNode, 804 nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, 805 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType) { 806 nsCOMPtr<nsILoadInfo> loadInfo = MOZ_TRY( 807 LoadInfo::Create(aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, 808 aSecurityFlags, aContentPolicyType)); 809 if (!loadInfo) { 810 return NS_ERROR_UNEXPECTED; 811 } 812 813 nsCOMPtr<nsIInputStream> stream = std::move(aStream); 814 815 return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(), 816 aContentType, aContentCharset, 817 loadInfo); 818 } 819 820 nsresult NS_NewInputStreamChannel( 821 nsIChannel** outChannel, nsIURI* aUri, 822 already_AddRefed<nsIInputStream> aStream, nsIPrincipal* aLoadingPrincipal, 823 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType, 824 const nsACString& aContentType /* = ""_ns */, 825 const nsACString& aContentCharset /* = ""_ns */) { 826 nsCOMPtr<nsIInputStream> stream = aStream; 827 return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(), 828 aContentType, aContentCharset, 829 nullptr, // aLoadingNode 830 aLoadingPrincipal, 831 nullptr, // aTriggeringPrincipal 832 aSecurityFlags, aContentPolicyType); 833 } 834 835 nsresult NS_NewInputStreamChannelInternal(nsIChannel** outChannel, nsIURI* aUri, 836 const nsAString& aData, 837 const nsACString& aContentType, 838 nsILoadInfo* aLoadInfo, 839 bool aIsSrcdocChannel /* = false */) { 840 nsresult rv; 841 nsCOMPtr<nsIStringInputStream> stream; 842 stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv); 843 NS_ENSURE_SUCCESS(rv, rv); 844 845 uint32_t len; 846 char* utf8Bytes = ToNewUTF8String(aData, &len); 847 rv = stream->AdoptData(utf8Bytes, len); 848 849 nsCOMPtr<nsIChannel> channel; 850 rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aUri, 851 stream.forget(), aContentType, 852 "UTF-8"_ns, aLoadInfo); 853 854 NS_ENSURE_SUCCESS(rv, rv); 855 856 if (aIsSrcdocChannel) { 857 nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(channel); 858 NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE); 859 inStrmChan->SetSrcdocData(aData); 860 } 861 channel.forget(outChannel); 862 return NS_OK; 863 } 864 865 nsresult NS_NewInputStreamChannelInternal( 866 nsIChannel** outChannel, nsIURI* aUri, const nsAString& aData, 867 const nsACString& aContentType, nsINode* aLoadingNode, 868 nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, 869 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType, 870 bool aIsSrcdocChannel /* = false */) { 871 nsCOMPtr<nsILoadInfo> loadInfo = MOZ_TRY( 872 net::LoadInfo::Create(aLoadingPrincipal, aTriggeringPrincipal, 873 aLoadingNode, aSecurityFlags, aContentPolicyType)); 874 return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType, 875 loadInfo, aIsSrcdocChannel); 876 } 877 878 nsresult NS_NewInputStreamChannel(nsIChannel** outChannel, nsIURI* aUri, 879 const nsAString& aData, 880 const nsACString& aContentType, 881 nsIPrincipal* aLoadingPrincipal, 882 nsSecurityFlags aSecurityFlags, 883 nsContentPolicyType aContentPolicyType, 884 bool aIsSrcdocChannel /* = false */) { 885 return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType, 886 nullptr, // aLoadingNode 887 aLoadingPrincipal, 888 nullptr, // aTriggeringPrincipal 889 aSecurityFlags, aContentPolicyType, 890 aIsSrcdocChannel); 891 } 892 893 nsresult NS_NewInputStreamPump( 894 nsIInputStreamPump** aResult, already_AddRefed<nsIInputStream> aStream, 895 uint32_t aSegsize /* = 0 */, uint32_t aSegcount /* = 0 */, 896 bool aCloseWhenDone /* = false */, 897 nsISerialEventTarget* aMainThreadTarget /* = nullptr */) { 898 nsCOMPtr<nsIInputStream> stream = std::move(aStream); 899 900 nsresult rv; 901 nsCOMPtr<nsIInputStreamPump> pump = 902 do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv); 903 if (NS_SUCCEEDED(rv)) { 904 rv = pump->Init(stream, aSegsize, aSegcount, aCloseWhenDone, 905 aMainThreadTarget); 906 if (NS_SUCCEEDED(rv)) { 907 *aResult = nullptr; 908 pump.swap(*aResult); 909 } 910 } 911 return rv; 912 } 913 914 nsresult NS_NewLoadGroup(nsILoadGroup** result, nsIRequestObserver* obs) { 915 nsresult rv; 916 nsCOMPtr<nsILoadGroup> group = 917 do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv); 918 if (NS_SUCCEEDED(rv)) { 919 rv = group->SetGroupObserver(obs); 920 if (NS_SUCCEEDED(rv)) { 921 *result = nullptr; 922 group.swap(*result); 923 } 924 } 925 return rv; 926 } 927 928 bool NS_IsReasonableHTTPHeaderValue(const nsACString& aValue) { 929 return mozilla::net::nsHttp::IsReasonableHeaderValue(aValue); 930 } 931 932 bool NS_IsValidHTTPToken(const nsACString& aToken) { 933 return mozilla::net::nsHttp::IsValidToken(aToken); 934 } 935 936 void NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest) { 937 mozilla::net::nsHttp::TrimHTTPWhitespace(aSource, aDest); 938 } 939 940 nsresult NS_NewLoadGroup(nsILoadGroup** aResult, nsIPrincipal* aPrincipal) { 941 using mozilla::LoadContext; 942 nsresult rv; 943 944 nsCOMPtr<nsILoadGroup> group = 945 do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv); 946 NS_ENSURE_SUCCESS(rv, rv); 947 948 RefPtr<LoadContext> loadContext = new LoadContext(aPrincipal); 949 rv = group->SetNotificationCallbacks(loadContext); 950 NS_ENSURE_SUCCESS(rv, rv); 951 952 group.forget(aResult); 953 return rv; 954 } 955 956 bool NS_LoadGroupMatchesPrincipal(nsILoadGroup* aLoadGroup, 957 nsIPrincipal* aPrincipal) { 958 if (!aPrincipal) { 959 return false; 960 } 961 962 // If this is a null principal then the load group doesn't really matter. 963 // The principal will not be allowed to perform any actions that actually 964 // use the load group. Unconditionally treat null principals as a match. 965 if (aPrincipal->GetIsNullPrincipal()) { 966 return true; 967 } 968 969 if (!aLoadGroup) { 970 return false; 971 } 972 973 nsCOMPtr<nsILoadContext> loadContext; 974 NS_QueryNotificationCallbacks(nullptr, aLoadGroup, NS_GET_IID(nsILoadContext), 975 getter_AddRefs(loadContext)); 976 NS_ENSURE_TRUE(loadContext, false); 977 978 return true; 979 } 980 981 nsresult NS_NewDownloader(nsIStreamListener** result, 982 nsIDownloadObserver* observer, 983 nsIFile* downloadLocation /* = nullptr */) { 984 nsresult rv; 985 nsCOMPtr<nsIDownloader> downloader = 986 do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv); 987 if (NS_SUCCEEDED(rv)) { 988 rv = downloader->Init(observer, downloadLocation); 989 if (NS_SUCCEEDED(rv)) { 990 downloader.forget(result); 991 } 992 } 993 return rv; 994 } 995 996 nsresult NS_NewIncrementalStreamLoader( 997 nsIIncrementalStreamLoader** result, 998 nsIIncrementalStreamLoaderObserver* observer) { 999 nsresult rv; 1000 nsCOMPtr<nsIIncrementalStreamLoader> loader = 1001 do_CreateInstance(NS_INCREMENTALSTREAMLOADER_CONTRACTID, &rv); 1002 if (NS_SUCCEEDED(rv)) { 1003 rv = loader->Init(observer); 1004 if (NS_SUCCEEDED(rv)) { 1005 *result = nullptr; 1006 loader.swap(*result); 1007 } 1008 } 1009 return rv; 1010 } 1011 1012 nsresult NS_NewStreamLoader( 1013 nsIStreamLoader** result, nsIStreamLoaderObserver* observer, 1014 nsIRequestObserver* requestObserver /* = nullptr */) { 1015 nsresult rv; 1016 nsCOMPtr<nsIStreamLoader> loader = 1017 do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv); 1018 if (NS_SUCCEEDED(rv)) { 1019 rv = loader->Init(observer, requestObserver); 1020 if (NS_SUCCEEDED(rv)) { 1021 *result = nullptr; 1022 loader.swap(*result); 1023 } 1024 } 1025 return rv; 1026 } 1027 1028 nsresult NS_NewStreamLoaderInternal( 1029 nsIStreamLoader** outStream, nsIURI* aUri, 1030 nsIStreamLoaderObserver* aObserver, nsINode* aLoadingNode, 1031 nsIPrincipal* aLoadingPrincipal, nsSecurityFlags aSecurityFlags, 1032 nsContentPolicyType aContentPolicyType, 1033 nsILoadGroup* aLoadGroup /* = nullptr */, 1034 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 1035 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) { 1036 nsCOMPtr<nsIChannel> channel; 1037 nsresult rv = NS_NewChannelInternal( 1038 getter_AddRefs(channel), aUri, aLoadingNode, aLoadingPrincipal, 1039 nullptr, // aTriggeringPrincipal 1040 Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, 1041 aContentPolicyType, 1042 nullptr, // nsICookieJarSettings 1043 nullptr, // PerformanceStorage 1044 aLoadGroup, aCallbacks, aLoadFlags); 1045 1046 NS_ENSURE_SUCCESS(rv, rv); 1047 rv = NS_NewStreamLoader(outStream, aObserver); 1048 NS_ENSURE_SUCCESS(rv, rv); 1049 return channel->AsyncOpen(*outStream); 1050 } 1051 1052 nsresult NS_NewStreamLoader( 1053 nsIStreamLoader** outStream, nsIURI* aUri, 1054 nsIStreamLoaderObserver* aObserver, nsINode* aLoadingNode, 1055 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType, 1056 nsILoadGroup* aLoadGroup /* = nullptr */, 1057 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 1058 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) { 1059 NS_ASSERTION(aLoadingNode, 1060 "Can not create stream loader without a loading Node!"); 1061 return NS_NewStreamLoaderInternal( 1062 outStream, aUri, aObserver, aLoadingNode, aLoadingNode->NodePrincipal(), 1063 aSecurityFlags, aContentPolicyType, aLoadGroup, aCallbacks, aLoadFlags); 1064 } 1065 1066 nsresult NS_NewStreamLoader( 1067 nsIStreamLoader** outStream, nsIURI* aUri, 1068 nsIStreamLoaderObserver* aObserver, nsIPrincipal* aLoadingPrincipal, 1069 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType, 1070 nsILoadGroup* aLoadGroup /* = nullptr */, 1071 nsIInterfaceRequestor* aCallbacks /* = nullptr */, 1072 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) { 1073 return NS_NewStreamLoaderInternal(outStream, aUri, aObserver, 1074 nullptr, // aLoadingNode 1075 aLoadingPrincipal, aSecurityFlags, 1076 aContentPolicyType, aLoadGroup, aCallbacks, 1077 aLoadFlags); 1078 } 1079 1080 nsresult NS_NewSyncStreamListener(nsIStreamListener** result, 1081 nsIInputStream** stream) { 1082 nsCOMPtr<nsISyncStreamListener> listener = new nsSyncStreamListener(); 1083 nsresult rv = listener->GetInputStream(stream); 1084 if (NS_SUCCEEDED(rv)) { 1085 listener.forget(result); 1086 } 1087 return rv; 1088 } 1089 1090 nsresult NS_ImplementChannelOpen(nsIChannel* channel, nsIInputStream** result) { 1091 nsCOMPtr<nsIStreamListener> listener; 1092 nsCOMPtr<nsIInputStream> stream; 1093 nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener), 1094 getter_AddRefs(stream)); 1095 NS_ENSURE_SUCCESS(rv, rv); 1096 1097 rv = channel->AsyncOpen(listener); 1098 NS_ENSURE_SUCCESS(rv, rv); 1099 1100 uint64_t n; 1101 // block until the initial response is received or an error occurs. 1102 rv = stream->Available(&n); 1103 NS_ENSURE_SUCCESS(rv, rv); 1104 1105 *result = nullptr; 1106 stream.swap(*result); 1107 1108 return NS_OK; 1109 } 1110 1111 nsresult NS_NewRequestObserverProxy(nsIRequestObserver** result, 1112 nsIRequestObserver* observer, 1113 nsISupports* context) { 1114 nsCOMPtr<nsIRequestObserverProxy> proxy = new nsRequestObserverProxy(); 1115 nsresult rv = proxy->Init(observer, context); 1116 if (NS_SUCCEEDED(rv)) { 1117 proxy.forget(result); 1118 } 1119 return rv; 1120 } 1121 1122 nsresult NS_NewSimpleStreamListener( 1123 nsIStreamListener** result, nsIOutputStream* sink, 1124 nsIRequestObserver* observer /* = nullptr */) { 1125 nsresult rv; 1126 nsCOMPtr<nsISimpleStreamListener> listener = 1127 do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv); 1128 if (NS_SUCCEEDED(rv)) { 1129 rv = listener->Init(sink, observer); 1130 if (NS_SUCCEEDED(rv)) { 1131 listener.forget(result); 1132 } 1133 } 1134 return rv; 1135 } 1136 1137 nsresult NS_CheckPortSafety(int32_t port, const char* scheme, 1138 nsIIOService* ioService /* = nullptr */) { 1139 nsresult rv; 1140 nsCOMPtr<nsIIOService> grip; 1141 rv = net_EnsureIOService(&ioService, grip); 1142 if (ioService) { 1143 bool allow; 1144 rv = ioService->AllowPort(port, scheme, &allow); 1145 if (NS_SUCCEEDED(rv) && !allow) { 1146 NS_WARNING("port blocked"); 1147 rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED; 1148 } 1149 } 1150 return rv; 1151 } 1152 1153 nsresult NS_CheckPortSafety(nsIURI* uri) { 1154 int32_t port; 1155 nsresult rv = uri->GetPort(&port); 1156 if (NS_FAILED(rv) || port == -1) { // port undefined or default-valued 1157 return NS_OK; 1158 } 1159 nsAutoCString scheme; 1160 uri->GetScheme(scheme); 1161 return NS_CheckPortSafety(port, scheme.get()); 1162 } 1163 1164 nsresult NS_GetFileProtocolHandler(nsIFileProtocolHandler** result, 1165 nsIIOService* ioService /* = nullptr */) { 1166 nsresult rv; 1167 nsCOMPtr<nsIIOService> grip; 1168 rv = net_EnsureIOService(&ioService, grip); 1169 if (ioService) { 1170 nsCOMPtr<nsIProtocolHandler> handler; 1171 rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler)); 1172 if (NS_SUCCEEDED(rv)) rv = CallQueryInterface(handler, result); 1173 } 1174 return rv; 1175 } 1176 1177 nsresult NS_GetFileFromURLSpec(const nsACString& inURL, nsIFile** result, 1178 nsIIOService* ioService /* = nullptr */) { 1179 nsresult rv; 1180 nsCOMPtr<nsIFileProtocolHandler> fileHandler; 1181 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService); 1182 if (NS_SUCCEEDED(rv)) rv = fileHandler->GetFileFromURLSpec(inURL, result); 1183 return rv; 1184 } 1185 1186 nsresult NS_GetURLSpecFromFile(nsIFile* file, nsACString& url, 1187 nsIIOService* ioService /* = nullptr */) { 1188 nsresult rv; 1189 nsCOMPtr<nsIFileProtocolHandler> fileHandler; 1190 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService); 1191 if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromFile(file, url); 1192 return rv; 1193 } 1194 1195 nsresult NS_GetURLSpecFromActualFile(nsIFile* file, nsACString& url, 1196 nsIIOService* ioService /* = nullptr */) { 1197 nsresult rv; 1198 nsCOMPtr<nsIFileProtocolHandler> fileHandler; 1199 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService); 1200 if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromActualFile(file, url); 1201 return rv; 1202 } 1203 1204 nsresult NS_GetURLSpecFromDir(nsIFile* file, nsACString& url, 1205 nsIIOService* ioService /* = nullptr */) { 1206 nsresult rv; 1207 nsCOMPtr<nsIFileProtocolHandler> fileHandler; 1208 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService); 1209 if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromDir(file, url); 1210 return rv; 1211 } 1212 1213 void NS_GetReferrerFromChannel(nsIChannel* channel, nsIURI** referrer) { 1214 *referrer = nullptr; 1215 1216 if (nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(channel)) { 1217 // We have to check for a property on a property bag because the 1218 // referrer may be empty for security reasons (for example, when loading 1219 // an http page with an https referrer). 1220 nsresult rv; 1221 nsCOMPtr<nsIURI> uri( 1222 do_GetProperty(props, u"docshell.internalReferrer"_ns, &rv)); 1223 if (NS_SUCCEEDED(rv)) { 1224 uri.forget(referrer); 1225 return; 1226 } 1227 } 1228 1229 // if that didn't work, we can still try to get the referrer from the 1230 // nsIHttpChannel (if we can QI to it) 1231 nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel)); 1232 if (!chan) { 1233 return; 1234 } 1235 1236 nsCOMPtr<nsIReferrerInfo> referrerInfo = chan->GetReferrerInfo(); 1237 if (!referrerInfo) { 1238 return; 1239 } 1240 1241 referrerInfo->GetOriginalReferrer(referrer); 1242 } 1243 1244 already_AddRefed<nsINetUtil> do_GetNetUtil(nsresult* error /* = 0 */) { 1245 nsCOMPtr<nsIIOService> io; 1246 nsCOMPtr<nsINetUtil> util; 1247 1248 io = mozilla::components::IO::Service(); 1249 if (io) util = do_QueryInterface(io); 1250 1251 if (error) *error = !!util ? NS_OK : NS_ERROR_FAILURE; 1252 return util.forget(); 1253 } 1254 1255 nsresult NS_ParseRequestContentType(const nsACString& rawContentType, 1256 nsCString& contentType, 1257 nsCString& contentCharset) { 1258 // contentCharset is left untouched if not present in rawContentType 1259 nsresult rv; 1260 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv); 1261 NS_ENSURE_SUCCESS(rv, rv); 1262 nsCString charset; 1263 bool hadCharset; 1264 rv = util->ParseRequestContentType(rawContentType, charset, &hadCharset, 1265 contentType); 1266 if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset; 1267 return rv; 1268 } 1269 1270 nsresult NS_ParseResponseContentType(const nsACString& rawContentType, 1271 nsCString& contentType, 1272 nsCString& contentCharset) { 1273 // contentCharset is left untouched if not present in rawContentType 1274 nsresult rv; 1275 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv); 1276 NS_ENSURE_SUCCESS(rv, rv); 1277 nsCString charset; 1278 bool hadCharset; 1279 rv = util->ParseResponseContentType(rawContentType, charset, &hadCharset, 1280 contentType); 1281 if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset; 1282 return rv; 1283 } 1284 1285 nsresult NS_ExtractCharsetFromContentType(const nsACString& rawContentType, 1286 nsCString& contentCharset, 1287 bool* hadCharset, 1288 int32_t* charsetStart, 1289 int32_t* charsetEnd) { 1290 // contentCharset is left untouched if not present in rawContentType 1291 nsresult rv; 1292 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv); 1293 NS_ENSURE_SUCCESS(rv, rv); 1294 1295 return util->ExtractCharsetFromContentType( 1296 rawContentType, contentCharset, charsetStart, charsetEnd, hadCharset); 1297 } 1298 1299 nsresult NS_NewAtomicFileOutputStream(nsIOutputStream** result, nsIFile* file, 1300 int32_t ioFlags /* = -1 */, 1301 int32_t perm /* = -1 */, 1302 int32_t behaviorFlags /* = 0 */) { 1303 nsresult rv; 1304 nsCOMPtr<nsIFileOutputStream> out = 1305 do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv); 1306 if (NS_SUCCEEDED(rv)) { 1307 rv = out->Init(file, ioFlags, perm, behaviorFlags); 1308 if (NS_SUCCEEDED(rv)) out.forget(result); 1309 } 1310 return rv; 1311 } 1312 1313 nsresult NS_NewSafeLocalFileOutputStream(nsIOutputStream** result, 1314 nsIFile* file, 1315 int32_t ioFlags /* = -1 */, 1316 int32_t perm /* = -1 */, 1317 int32_t behaviorFlags /* = 0 */) { 1318 nsresult rv; 1319 nsCOMPtr<nsIFileOutputStream> out = 1320 do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv); 1321 if (NS_SUCCEEDED(rv)) { 1322 rv = out->Init(file, ioFlags, perm, behaviorFlags); 1323 if (NS_SUCCEEDED(rv)) out.forget(result); 1324 } 1325 return rv; 1326 } 1327 1328 nsresult NS_NewLocalFileRandomAccessStream(nsIRandomAccessStream** result, 1329 nsIFile* file, 1330 int32_t ioFlags /* = -1 */, 1331 int32_t perm /* = -1 */, 1332 int32_t behaviorFlags /* = 0 */) { 1333 nsCOMPtr<nsIFileRandomAccessStream> stream = new nsFileRandomAccessStream(); 1334 nsresult rv = stream->Init(file, ioFlags, perm, behaviorFlags); 1335 if (NS_SUCCEEDED(rv)) { 1336 stream.forget(result); 1337 } 1338 return rv; 1339 } 1340 1341 mozilla::Result<nsCOMPtr<nsIRandomAccessStream>, nsresult> 1342 NS_NewLocalFileRandomAccessStream(nsIFile* file, int32_t ioFlags /* = -1 */, 1343 int32_t perm /* = -1 */, 1344 int32_t behaviorFlags /* = 0 */) { 1345 nsCOMPtr<nsIRandomAccessStream> stream; 1346 const nsresult rv = NS_NewLocalFileRandomAccessStream( 1347 getter_AddRefs(stream), file, ioFlags, perm, behaviorFlags); 1348 if (NS_SUCCEEDED(rv)) { 1349 return stream; 1350 } 1351 return Err(rv); 1352 } 1353 1354 nsresult NS_NewBufferedOutputStream( 1355 nsIOutputStream** aResult, already_AddRefed<nsIOutputStream> aOutputStream, 1356 uint32_t aBufferSize) { 1357 nsCOMPtr<nsIOutputStream> outputStream = std::move(aOutputStream); 1358 1359 nsresult rv; 1360 nsCOMPtr<nsIBufferedOutputStream> out = 1361 do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv); 1362 if (NS_SUCCEEDED(rv)) { 1363 rv = out->Init(outputStream, aBufferSize); 1364 if (NS_SUCCEEDED(rv)) { 1365 out.forget(aResult); 1366 } 1367 } 1368 return rv; 1369 } 1370 1371 [[nodiscard]] nsresult NS_NewBufferedInputStream( 1372 nsIInputStream** aResult, already_AddRefed<nsIInputStream> aInputStream, 1373 uint32_t aBufferSize) { 1374 nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream); 1375 1376 nsCOMPtr<nsIBufferedInputStream> in; 1377 nsresult rv = nsBufferedInputStream::Create( 1378 NS_GET_IID(nsIBufferedInputStream), getter_AddRefs(in)); 1379 if (NS_SUCCEEDED(rv)) { 1380 rv = in->Init(inputStream, aBufferSize); 1381 if (NS_SUCCEEDED(rv)) { 1382 *aResult = static_cast<nsBufferedInputStream*>(in.get()) 1383 ->GetInputStream() 1384 .take(); 1385 } 1386 } 1387 return rv; 1388 } 1389 1390 Result<nsCOMPtr<nsIInputStream>, nsresult> NS_NewBufferedInputStream( 1391 already_AddRefed<nsIInputStream> aInputStream, uint32_t aBufferSize) { 1392 nsCOMPtr<nsIInputStream> stream; 1393 const nsresult rv = NS_NewBufferedInputStream( 1394 getter_AddRefs(stream), std::move(aInputStream), aBufferSize); 1395 if (NS_SUCCEEDED(rv)) { 1396 return stream; 1397 } 1398 return Err(rv); 1399 } 1400 1401 namespace { 1402 1403 // Returns the buffer size from the pref, floored to the nearest power of two. 1404 static uint32_t GetBufferSize() { 1405 uint32_t prefValue = StaticPrefs::network_buffer_default_size(); 1406 return uint32_t(1) << FloorLog2(prefValue); 1407 } 1408 1409 class BufferWriter final : public nsIInputStreamCallback { 1410 public: 1411 NS_DECL_THREADSAFE_ISUPPORTS 1412 1413 BufferWriter(nsIInputStream* aInputStream, void* aBuffer, int64_t aCount) 1414 : mMonitor("BufferWriter.mMonitor"), 1415 mInputStream(aInputStream), 1416 mBuffer(aBuffer), 1417 mCount(aCount), 1418 mWrittenData(0), 1419 mBufferType(aBuffer ? eExternal : eInternal), 1420 mBufferSize(0) { 1421 MOZ_ASSERT(aInputStream); 1422 MOZ_ASSERT(aCount == -1 || aCount > 0); 1423 MOZ_ASSERT_IF(mBuffer, aCount > 0); 1424 } 1425 1426 nsresult Write() { 1427 NS_ASSERT_OWNINGTHREAD(BufferWriter); 1428 1429 // Let's make the inputStream buffered if it's not. 1430 if (!NS_InputStreamIsBuffered(mInputStream)) { 1431 nsCOMPtr<nsIInputStream> bufferedStream; 1432 nsresult rv = 1433 NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), 1434 mInputStream.forget(), GetBufferSize()); 1435 NS_ENSURE_SUCCESS(rv, rv); 1436 1437 mInputStream = bufferedStream; 1438 } 1439 1440 mAsyncInputStream = do_QueryInterface(mInputStream); 1441 1442 if (!mAsyncInputStream) { 1443 return WriteSync(); 1444 } 1445 1446 // Let's use mAsyncInputStream only. 1447 mInputStream = nullptr; 1448 1449 return WriteAsync(); 1450 } 1451 1452 uint64_t WrittenData() const { 1453 NS_ASSERT_OWNINGTHREAD(BufferWriter); 1454 return mWrittenData; 1455 } 1456 1457 void* StealBuffer() { 1458 NS_ASSERT_OWNINGTHREAD(BufferWriter); 1459 MOZ_ASSERT(mBufferType == eInternal); 1460 1461 void* buffer = mBuffer; 1462 1463 mBuffer = nullptr; 1464 mBufferSize = 0; 1465 1466 return buffer; 1467 } 1468 1469 private: 1470 ~BufferWriter() { 1471 if (mBuffer && mBufferType == eInternal) { 1472 free(mBuffer); 1473 } 1474 1475 if (mTaskQueue) { 1476 mTaskQueue->BeginShutdown(); 1477 } 1478 } 1479 1480 nsresult WriteSync() { 1481 NS_ASSERT_OWNINGTHREAD(BufferWriter); 1482 1483 uint64_t length = (uint64_t)mCount; 1484 1485 if (mCount == -1) { 1486 nsresult rv = mInputStream->Available(&length); 1487 NS_ENSURE_SUCCESS(rv, rv); 1488 1489 if (length == 0) { 1490 // nothing to read. 1491 return NS_OK; 1492 } 1493 } 1494 1495 if (mBufferType == eInternal) { 1496 mBuffer = malloc(length); 1497 if (NS_WARN_IF(!mBuffer)) { 1498 return NS_ERROR_OUT_OF_MEMORY; 1499 } 1500 } 1501 1502 uint32_t writtenData; 1503 nsresult rv = mInputStream->ReadSegments(NS_CopySegmentToBuffer, mBuffer, 1504 length, &writtenData); 1505 NS_ENSURE_SUCCESS(rv, rv); 1506 1507 mWrittenData = writtenData; 1508 return NS_OK; 1509 } 1510 1511 nsresult WriteAsync() { 1512 NS_ASSERT_OWNINGTHREAD(BufferWriter); 1513 1514 if (mCount > 0 && mBufferType == eInternal) { 1515 mBuffer = malloc(mCount); 1516 if (NS_WARN_IF(!mBuffer)) { 1517 return NS_ERROR_OUT_OF_MEMORY; 1518 } 1519 } 1520 1521 while (true) { 1522 if (mCount == -1 && !MaybeExpandBufferSize()) { 1523 return NS_ERROR_OUT_OF_MEMORY; 1524 } 1525 1526 uint64_t offset = mWrittenData; 1527 uint64_t length = mCount == -1 ? GetBufferSize() : mCount; 1528 1529 // Let's try to read data directly. 1530 uint32_t writtenData; 1531 nsresult rv = mAsyncInputStream->ReadSegments( 1532 NS_CopySegmentToBuffer, static_cast<char*>(mBuffer) + offset, length, 1533 &writtenData); 1534 1535 // Operation completed. Nothing more to read. 1536 if (NS_SUCCEEDED(rv) && writtenData == 0) { 1537 return NS_OK; 1538 } 1539 1540 // If we succeeded, let's try to read again. 1541 if (NS_SUCCEEDED(rv)) { 1542 mWrittenData += writtenData; 1543 if (mCount != -1) { 1544 MOZ_ASSERT(mCount >= writtenData); 1545 mCount -= writtenData; 1546 1547 // Is this the end of the reading? 1548 if (mCount == 0) { 1549 return NS_OK; 1550 } 1551 } 1552 1553 continue; 1554 } 1555 1556 // Async wait... 1557 if (rv == NS_BASE_STREAM_WOULD_BLOCK) { 1558 rv = MaybeCreateTaskQueue(); 1559 if (NS_WARN_IF(NS_FAILED(rv))) { 1560 return rv; 1561 } 1562 1563 MonitorAutoLock lock(mMonitor); 1564 1565 rv = mAsyncInputStream->AsyncWait(this, 0, length, mTaskQueue); 1566 if (NS_WARN_IF(NS_FAILED(rv))) { 1567 return rv; 1568 } 1569 1570 lock.Wait(); 1571 continue; 1572 } 1573 1574 // Otherwise, let's propagate the error. 1575 return rv; 1576 } 1577 1578 MOZ_ASSERT_UNREACHABLE("We should not be here"); 1579 return NS_ERROR_FAILURE; 1580 } 1581 1582 nsresult MaybeCreateTaskQueue() { 1583 NS_ASSERT_OWNINGTHREAD(BufferWriter); 1584 1585 if (!mTaskQueue) { 1586 nsCOMPtr<nsIEventTarget> target; 1587 target = mozilla::components::StreamTransport::Service(); 1588 if (!target) { 1589 return NS_ERROR_FAILURE; 1590 } 1591 1592 mTaskQueue = TaskQueue::Create(target.forget(), "nsNetUtil:BufferWriter"); 1593 } 1594 1595 return NS_OK; 1596 } 1597 1598 NS_IMETHOD 1599 OnInputStreamReady(nsIAsyncInputStream* aStream) override { 1600 MOZ_ASSERT(!NS_IsMainThread()); 1601 1602 // We have something to read. Let's unlock the main-thread. 1603 MonitorAutoLock lock(mMonitor); 1604 lock.Notify(); 1605 return NS_OK; 1606 } 1607 1608 bool MaybeExpandBufferSize() { 1609 NS_ASSERT_OWNINGTHREAD(BufferWriter); 1610 1611 MOZ_ASSERT(mCount == -1); 1612 1613 uint32_t bufSize = GetBufferSize(); 1614 if (mBufferSize >= mWrittenData + bufSize) { 1615 // The buffer is big enough. 1616 return true; 1617 } 1618 1619 CheckedUint32 bufferSize = 1620 std::max<uint32_t>(static_cast<uint32_t>(mWrittenData), bufSize); 1621 while (bufferSize.isValid() && 1622 bufferSize.value() < mWrittenData + bufSize) { 1623 bufferSize *= 2; 1624 } 1625 1626 if (!bufferSize.isValid()) { 1627 return false; 1628 } 1629 1630 void* buffer = realloc(mBuffer, bufferSize.value()); 1631 if (!buffer) { 1632 return false; 1633 } 1634 1635 mBuffer = buffer; 1636 mBufferSize = bufferSize.value(); 1637 return true; 1638 } 1639 1640 // All the members of this class are touched on the owning thread only. The 1641 // monitor is only used to communicate when there is more data to read. 1642 Monitor mMonitor MOZ_UNANNOTATED; 1643 1644 nsCOMPtr<nsIInputStream> mInputStream; 1645 nsCOMPtr<nsIAsyncInputStream> mAsyncInputStream; 1646 1647 RefPtr<TaskQueue> mTaskQueue; 1648 1649 void* mBuffer; 1650 int64_t mCount; 1651 uint64_t mWrittenData; 1652 1653 enum { 1654 // The buffer is allocated internally and this object must release it 1655 // in the DTOR if not stolen. The buffer can be reallocated. 1656 eInternal, 1657 1658 // The buffer is not owned by this object and it cannot be reallocated. 1659 eExternal, 1660 } mBufferType; 1661 1662 // The following set if needed for the async read. 1663 uint64_t mBufferSize; 1664 }; 1665 1666 NS_IMPL_ISUPPORTS(BufferWriter, nsIInputStreamCallback) 1667 1668 } // anonymous namespace 1669 1670 nsresult NS_ReadInputStreamToBuffer(nsIInputStream* aInputStream, void** aDest, 1671 int64_t aCount, uint64_t* aWritten) { 1672 MOZ_ASSERT(aInputStream); 1673 MOZ_ASSERT(aCount >= -1); 1674 1675 uint64_t dummyWritten; 1676 if (!aWritten) { 1677 aWritten = &dummyWritten; 1678 } 1679 1680 if (aCount == 0) { 1681 *aWritten = 0; 1682 return NS_OK; 1683 } 1684 1685 // This will take care of allocating and reallocating aDest. 1686 RefPtr<BufferWriter> writer = new BufferWriter(aInputStream, *aDest, aCount); 1687 1688 nsresult rv = writer->Write(); 1689 NS_ENSURE_SUCCESS(rv, rv); 1690 1691 *aWritten = writer->WrittenData(); 1692 1693 if (!*aDest) { 1694 *aDest = writer->StealBuffer(); 1695 } 1696 1697 return NS_OK; 1698 } 1699 1700 nsresult NS_ReadInputStreamToString(nsIInputStream* aInputStream, 1701 nsACString& aDest, int64_t aCount, 1702 uint64_t* aWritten) { 1703 uint64_t dummyWritten; 1704 if (!aWritten) { 1705 aWritten = &dummyWritten; 1706 } 1707 1708 // Nothing to do if aCount is 0. 1709 if (aCount == 0) { 1710 aDest.Truncate(); 1711 *aWritten = 0; 1712 return NS_OK; 1713 } 1714 1715 // If we have the size, we can pre-allocate the buffer. 1716 if (aCount > 0) { 1717 if (NS_WARN_IF(aCount >= INT32_MAX) || 1718 NS_WARN_IF(!aDest.SetLength(aCount, mozilla::fallible))) { 1719 return NS_ERROR_OUT_OF_MEMORY; 1720 } 1721 1722 void* dest = aDest.BeginWriting(); 1723 nsresult rv = 1724 NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten); 1725 NS_ENSURE_SUCCESS(rv, rv); 1726 1727 if ((uint64_t)aCount > *aWritten) { 1728 aDest.Truncate(*aWritten); 1729 } 1730 1731 return NS_OK; 1732 } 1733 1734 // If the size is unknown, BufferWriter will allocate the buffer. 1735 void* dest = nullptr; 1736 nsresult rv = 1737 NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten); 1738 MOZ_ASSERT_IF(NS_FAILED(rv), dest == nullptr); 1739 NS_ENSURE_SUCCESS(rv, rv); 1740 1741 if (!dest) { 1742 MOZ_ASSERT(*aWritten == 0); 1743 aDest.Truncate(); 1744 return NS_OK; 1745 } 1746 1747 aDest.Adopt(reinterpret_cast<char*>(dest), *aWritten); 1748 return NS_OK; 1749 } 1750 1751 nsresult NS_NewURI(nsIURI** result, const nsACString& spec, 1752 NotNull<const Encoding*> encoding, 1753 nsIURI* baseURI /* = nullptr */) { 1754 nsAutoCString charset; 1755 encoding->Name(charset); 1756 return NS_NewURI(result, spec, charset.get(), baseURI); 1757 } 1758 1759 nsresult NS_NewURI(nsIURI** result, const nsAString& aSpec, 1760 const char* charset /* = nullptr */, 1761 nsIURI* baseURI /* = nullptr */) { 1762 nsAutoCString spec; 1763 if (!AppendUTF16toUTF8(aSpec, spec, mozilla::fallible)) { 1764 return NS_ERROR_OUT_OF_MEMORY; 1765 } 1766 return NS_NewURI(result, spec, charset, baseURI); 1767 } 1768 1769 nsresult NS_NewURI(nsIURI** result, const nsAString& aSpec, 1770 NotNull<const Encoding*> encoding, 1771 nsIURI* baseURI /* = nullptr */) { 1772 nsAutoCString spec; 1773 if (!AppendUTF16toUTF8(aSpec, spec, mozilla::fallible)) { 1774 return NS_ERROR_OUT_OF_MEMORY; 1775 } 1776 return NS_NewURI(result, spec, encoding, baseURI); 1777 } 1778 1779 nsresult NS_NewURI(nsIURI** result, const char* spec, 1780 nsIURI* baseURI /* = nullptr */) { 1781 return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI); 1782 } 1783 1784 static nsresult NewStandardURI(const nsACString& aSpec, const char* aCharset, 1785 nsIURI* aBaseURI, int32_t aDefaultPort, 1786 nsIURI** aURI) { 1787 return NS_MutateURI(new nsStandardURL::Mutator()) 1788 .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_AUTHORITY, 1789 aDefaultPort, aSpec, aCharset, aBaseURI, nullptr) 1790 .Finalize(aURI); 1791 } 1792 1793 nsresult NS_GetSpecWithNSURLEncoding(nsACString& aResult, 1794 const nsACString& aSpec) { 1795 nsCOMPtr<nsIURI> uri; 1796 nsresult rv = NS_NewURIWithNSURLEncoding(getter_AddRefs(uri), aSpec); 1797 NS_ENSURE_SUCCESS(rv, rv); 1798 return uri->GetAsciiSpec(aResult); 1799 } 1800 1801 nsresult NS_NewURIWithNSURLEncoding(nsIURI** aResult, const nsACString& aSpec) { 1802 nsCOMPtr<nsIURI> uri; 1803 nsresult rv = NS_NewURI(getter_AddRefs(uri), aSpec); 1804 NS_ENSURE_SUCCESS(rv, rv); 1805 1806 // Escape the ref portion of the URL. NSURL is more strict about which 1807 // characters in the URL must be % encoded. For example, an unescaped '#' 1808 // to indicate the beginning of the ref component is accepted by NSURL, but 1809 // '#' characters in the ref must be escaped. Also adds encoding for other 1810 // characters not accepted by NSURL in the ref such as '{', '|', '}', and '^'. 1811 // The ref returned from GetRef() does not include the leading '#'. 1812 nsAutoCString ref, escapedRef; 1813 if (NS_SUCCEEDED(uri->GetRef(ref)) && !ref.IsEmpty()) { 1814 if (!NS_Escape(ref, escapedRef, url_NSURLRef)) { 1815 return NS_ERROR_INVALID_ARG; 1816 } 1817 rv = NS_MutateURI(uri).SetRef(escapedRef).Finalize(uri); 1818 NS_ENSURE_SUCCESS(rv, rv); 1819 } 1820 1821 uri.forget(aResult); 1822 return NS_OK; 1823 } 1824 1825 extern MOZ_THREAD_LOCAL(uint32_t) gTlsURLRecursionCount; 1826 1827 template <typename T> 1828 class TlsAutoIncrement { 1829 public: 1830 explicit TlsAutoIncrement(T& var) : mVar(var) { 1831 mValue = mVar.get(); 1832 mVar.set(mValue + 1); 1833 } 1834 ~TlsAutoIncrement() { 1835 typename T::Type value = mVar.get(); 1836 MOZ_ASSERT(value == mValue + 1); 1837 mVar.set(value - 1); 1838 } 1839 1840 typename T::Type value() { return mValue; } 1841 1842 private: 1843 typename T::Type mValue; 1844 T& mVar; 1845 }; 1846 1847 nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec, 1848 const char* aCharset /* = nullptr */, 1849 nsIURI* aBaseURI /* = nullptr */) { 1850 // we don't expect any other processes than: socket, content or parent 1851 // to be able to create a URL 1852 MOZ_ASSERT(XRE_IsSocketProcess() || XRE_IsContentProcess() || 1853 XRE_IsParentProcess()); 1854 TlsAutoIncrement<decltype(gTlsURLRecursionCount)> inc(gTlsURLRecursionCount); 1855 if (inc.value() >= MAX_RECURSION_COUNT) { 1856 return NS_ERROR_MALFORMED_URI; 1857 } 1858 1859 nsCOMPtr<nsIIOService> ioService = do_GetIOService(); 1860 if (!ioService) { 1861 // Individual protocol handlers unfortunately rely on the ioservice, let's 1862 // return an error here instead of causing unpredictable crashes later. 1863 return NS_ERROR_NOT_AVAILABLE; 1864 } 1865 1866 if (StaticPrefs::network_url_max_length() && 1867 aSpec.Length() > StaticPrefs::network_url_max_length()) { 1868 return NS_ERROR_MALFORMED_URI; 1869 } 1870 1871 nsAutoCString scheme; 1872 nsresult rv = net_ExtractURLScheme(aSpec, scheme); 1873 if (NS_FAILED(rv)) { 1874 // then aSpec is relative 1875 if (!aBaseURI) { 1876 return NS_ERROR_MALFORMED_URI; 1877 } 1878 1879 if (!aSpec.IsEmpty() && aSpec[0] == '#') { 1880 // Looks like a reference instead of a fully-specified URI. 1881 // --> initialize |uri| as a clone of |aBaseURI|, with ref appended. 1882 return NS_GetURIWithNewRef(aBaseURI, aSpec, aURI); 1883 } 1884 1885 rv = aBaseURI->GetScheme(scheme); 1886 if (NS_FAILED(rv)) return rv; 1887 } 1888 1889 // If encoding is not UTF-8 and url is not special or url’s scheme is "ws" or 1890 // "wss" then set encoding to UTF-8. 1891 if (aCharset && !scheme.IsEmpty() && 1892 (scheme.EqualsLiteral("ws") || scheme.EqualsLiteral("wss") || 1893 !SchemeIsSpecial(scheme))) { 1894 aCharset = "UTF-8"; 1895 } 1896 1897 if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("ws")) { 1898 return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT, 1899 aURI); 1900 } 1901 if (scheme.EqualsLiteral("https") || scheme.EqualsLiteral("wss")) { 1902 return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT, 1903 aURI); 1904 } 1905 if (scheme.EqualsLiteral("ftp")) { 1906 return NewStandardURI(aSpec, aCharset, aBaseURI, 21, aURI); 1907 } 1908 1909 if (scheme.EqualsLiteral("file")) { 1910 return NS_MutateURI(new nsStandardURL::Mutator()) 1911 .Apply(&nsIFileURLMutator::MarkFileURL) 1912 .Apply(&nsIStandardURLMutator::Init, 1913 nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, aSpec, aCharset, 1914 aBaseURI, nullptr) 1915 .Finalize(aURI); 1916 } 1917 1918 if (scheme.EqualsLiteral("data")) { 1919 return nsDataHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI); 1920 } 1921 1922 if (scheme.EqualsLiteral("moz-safe-about") || 1923 scheme.EqualsLiteral("page-icon") || scheme.EqualsLiteral("moz") || 1924 scheme.EqualsLiteral("cached-favicon")) { 1925 return NS_MutateURI(new nsSimpleURI::Mutator()) 1926 .SetSpec(aSpec) 1927 .Finalize(aURI); 1928 } 1929 1930 if (scheme.EqualsLiteral("chrome")) { 1931 return nsChromeProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI, 1932 aURI); 1933 } 1934 1935 if (scheme.EqualsLiteral("javascript")) { 1936 return nsJSProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI); 1937 } 1938 1939 if (scheme.EqualsLiteral("blob")) { 1940 return BlobURLProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI, 1941 aURI); 1942 } 1943 1944 if (scheme.EqualsLiteral("view-source")) { 1945 return nsViewSourceHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI); 1946 } 1947 1948 if (scheme.EqualsLiteral("resource")) { 1949 RefPtr<nsResProtocolHandler> handler = nsResProtocolHandler::GetSingleton(); 1950 if (!handler) { 1951 return NS_ERROR_NOT_AVAILABLE; 1952 } 1953 return handler->NewURI(aSpec, aCharset, aBaseURI, aURI); 1954 } 1955 1956 if (scheme.EqualsLiteral("moz-src")) { 1957 RefPtr<MozSrcProtocolHandler> handler = 1958 MozSrcProtocolHandler::GetSingleton(); 1959 if (!handler) { 1960 return NS_ERROR_NOT_AVAILABLE; 1961 } 1962 return handler->NewURI(aSpec, aCharset, aBaseURI, aURI); 1963 } 1964 1965 if (scheme.EqualsLiteral("indexeddb") || scheme.EqualsLiteral("uuid")) { 1966 return NS_MutateURI(new nsStandardURL::Mutator()) 1967 .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_AUTHORITY, 1968 0, aSpec, aCharset, aBaseURI, nullptr) 1969 .Finalize(aURI); 1970 } 1971 1972 if (scheme.EqualsLiteral("moz-extension")) { 1973 RefPtr<mozilla::net::ExtensionProtocolHandler> handler = 1974 mozilla::net::ExtensionProtocolHandler::GetSingleton(); 1975 if (!handler) { 1976 return NS_ERROR_NOT_AVAILABLE; 1977 } 1978 return handler->NewURI(aSpec, aCharset, aBaseURI, aURI); 1979 } 1980 1981 if (scheme.EqualsLiteral("moz-page-thumb")) { 1982 // The moz-page-thumb service runs JS to resolve a URI to a 1983 // storage location, so this should only ever run on the main 1984 // thread. 1985 if (!NS_IsMainThread()) { 1986 return NS_ERROR_NOT_AVAILABLE; 1987 } 1988 1989 RefPtr<mozilla::net::PageThumbProtocolHandler> handler = 1990 mozilla::net::PageThumbProtocolHandler::GetSingleton(); 1991 if (!handler) { 1992 return NS_ERROR_NOT_AVAILABLE; 1993 } 1994 return handler->NewURI(aSpec, aCharset, aBaseURI, aURI); 1995 } 1996 1997 if (scheme.EqualsLiteral("moz-newtab-wallpaper")) { 1998 RefPtr<mozilla::net::MozNewTabWallpaperProtocolHandler> handler = 1999 mozilla::net::MozNewTabWallpaperProtocolHandler::GetSingleton(); 2000 if (!handler) { 2001 return NS_ERROR_NOT_AVAILABLE; 2002 } 2003 return handler->NewURI(aSpec, aCharset, aBaseURI, aURI); 2004 } 2005 2006 if (scheme.EqualsLiteral("about")) { 2007 return nsAboutProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI, 2008 aURI); 2009 } 2010 2011 if (scheme.EqualsLiteral("jar")) { 2012 return NS_MutateURI(new nsJARURI::Mutator()) 2013 .Apply(&nsIJARURIMutator::SetSpecBaseCharset, aSpec, aBaseURI, aCharset) 2014 .Finalize(aURI); 2015 } 2016 2017 #ifndef XP_IOS 2018 if (scheme.EqualsLiteral("moz-icon")) { 2019 return NS_MutateURI(new nsMozIconURI::Mutator()) 2020 .SetSpec(aSpec) 2021 .Finalize(aURI); 2022 } 2023 #endif 2024 2025 #ifdef MOZ_WIDGET_GTK 2026 if (scheme.EqualsLiteral("smb") || scheme.EqualsLiteral("sftp")) { 2027 return NS_MutateURI(new nsStandardURL::Mutator()) 2028 .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_STANDARD, 2029 -1, aSpec, aCharset, aBaseURI, nullptr) 2030 .Finalize(aURI); 2031 } 2032 #endif 2033 2034 if (scheme.EqualsLiteral("android")) { 2035 return NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID) 2036 .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_STANDARD, 2037 -1, aSpec, aCharset, aBaseURI, nullptr) 2038 .Finalize(aURI); 2039 } 2040 2041 // web-extensions can add custom protocol implementations with standard URLs 2042 // that have notion of hostname, authority and relative URLs. Below we 2043 // manually check agains set of known protocols schemes until more general 2044 // solution is in place (See Bug 1569733) 2045 if (!StaticPrefs::network_url_useDefaultURI()) { 2046 if (scheme.EqualsLiteral("ssh")) { 2047 return NewStandardURI(aSpec, aCharset, aBaseURI, 22, aURI); 2048 } 2049 2050 if (scheme.EqualsLiteral("dweb") || scheme.EqualsLiteral("dat") || 2051 scheme.EqualsLiteral("ipfs") || scheme.EqualsLiteral("ipns") || 2052 scheme.EqualsLiteral("ssb") || scheme.EqualsLiteral("wtp")) { 2053 return NewStandardURI(aSpec, aCharset, aBaseURI, -1, aURI); 2054 } 2055 } 2056 2057 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) 2058 rv = NS_NewMailnewsURI(aURI, aSpec, aCharset, aBaseURI); 2059 if (rv != NS_ERROR_UNKNOWN_PROTOCOL) { 2060 return rv; 2061 } 2062 #endif 2063 2064 auto mustUseSimpleURI = [](const nsCString& scheme) -> bool { 2065 if (!StaticPrefs::network_url_simple_uri_unknown_schemes_enabled()) { 2066 return false; 2067 } 2068 2069 bool res = false; 2070 RefPtr<nsIIOService> ios = do_GetIOService(); 2071 MOZ_ALWAYS_SUCCEEDS(ios->IsSimpleURIUnknownScheme(scheme, &res)); 2072 return res; 2073 }; 2074 2075 if (aBaseURI) { 2076 nsAutoCString newSpec; 2077 rv = aBaseURI->Resolve(aSpec, newSpec); 2078 NS_ENSURE_SUCCESS(rv, rv); 2079 2080 nsAutoCString newScheme; 2081 rv = net_ExtractURLScheme(newSpec, newScheme); 2082 if (NS_SUCCEEDED(rv)) { 2083 // The scheme shouldn't really change at this point. 2084 MOZ_DIAGNOSTIC_ASSERT(newScheme == scheme); 2085 } 2086 2087 if (StaticPrefs::network_url_useDefaultURI()) { 2088 if (mustUseSimpleURI(scheme)) { 2089 return NS_MutateURI(new nsSimpleURI::Mutator()) 2090 .SetSpec(newSpec) 2091 .Finalize(aURI); 2092 } 2093 2094 return NS_MutateURI(new DefaultURI::Mutator()) 2095 .SetSpec(newSpec) 2096 .Finalize(aURI); 2097 } 2098 2099 return NS_MutateURI(new nsSimpleURI::Mutator()) 2100 .SetSpec(newSpec) 2101 .Finalize(aURI); 2102 } 2103 2104 if (StaticPrefs::network_url_useDefaultURI()) { 2105 if (mustUseSimpleURI(scheme)) { 2106 return NS_MutateURI(new nsSimpleURI::Mutator()) 2107 .SetSpec(aSpec) 2108 .Finalize(aURI); 2109 } 2110 return NS_MutateURI(new DefaultURI::Mutator()) 2111 .SetSpec(aSpec) 2112 .Finalize(aURI); 2113 } 2114 2115 // Falls back to external protocol handler. 2116 return NS_MutateURI(new nsSimpleURI::Mutator()).SetSpec(aSpec).Finalize(aURI); 2117 } 2118 2119 nsresult NS_GetSanitizedURIStringFromURI(nsIURI* aUri, 2120 nsACString& aSanitizedSpec) { 2121 aSanitizedSpec.Truncate(); 2122 2123 nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = do_QueryInterface(aUri); 2124 nsAutoCString cSpec; 2125 nsresult rv; 2126 if (safeUri) { 2127 rv = safeUri->GetSensitiveInfoHiddenSpec(cSpec); 2128 } else { 2129 rv = aUri->GetSpec(cSpec); 2130 } 2131 2132 if (NS_SUCCEEDED(rv)) { 2133 aSanitizedSpec.Assign(cSpec); 2134 } 2135 return rv; 2136 } 2137 2138 nsresult NS_LoadPersistentPropertiesFromURISpec( 2139 nsIPersistentProperties** outResult, const nsACString& aSpec) { 2140 nsCOMPtr<nsIURI> uri; 2141 nsresult rv = NS_NewURI(getter_AddRefs(uri), aSpec); 2142 NS_ENSURE_SUCCESS(rv, rv); 2143 2144 nsCOMPtr<nsIChannel> channel; 2145 rv = NS_NewChannel(getter_AddRefs(channel), uri, 2146 nsContentUtils::GetSystemPrincipal(), 2147 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, 2148 nsIContentPolicy::TYPE_OTHER); 2149 NS_ENSURE_SUCCESS(rv, rv); 2150 nsCOMPtr<nsIInputStream> in; 2151 rv = channel->Open(getter_AddRefs(in)); 2152 NS_ENSURE_SUCCESS(rv, rv); 2153 2154 nsCOMPtr<nsIPersistentProperties> properties = new nsPersistentProperties(); 2155 rv = properties->Load(in); 2156 NS_ENSURE_SUCCESS(rv, rv); 2157 2158 properties.swap(*outResult); 2159 return NS_OK; 2160 } 2161 2162 bool NS_UsePrivateBrowsing(nsIChannel* channel) { 2163 OriginAttributes attrs; 2164 bool result = StoragePrincipalHelper::GetOriginAttributes( 2165 channel, attrs, StoragePrincipalHelper::eRegularPrincipal); 2166 NS_ENSURE_TRUE(result, result); 2167 return attrs.IsPrivateBrowsing(); 2168 } 2169 2170 bool NS_HasBeenCrossOrigin(nsIChannel* aChannel, bool aReport) { 2171 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); 2172 // TYPE_DOCUMENT loads have a null LoadingPrincipal and can not be cross 2173 // origin. 2174 if (!loadInfo->GetLoadingPrincipal()) { 2175 return false; 2176 } 2177 2178 // Always treat tainted channels as cross-origin. 2179 if (loadInfo->GetTainting() != LoadTainting::Basic) { 2180 return true; 2181 } 2182 2183 nsCOMPtr<nsIPrincipal> loadingPrincipal = loadInfo->GetLoadingPrincipal(); 2184 uint32_t mode = loadInfo->GetSecurityMode(); 2185 bool dataInherits = 2186 mode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT || 2187 mode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT || 2188 mode == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT; 2189 2190 bool aboutBlankInherits = dataInherits && loadInfo->GetAboutBlankInherits(); 2191 2192 uint64_t innerWindowID = loadInfo->GetInnerWindowID(); 2193 2194 for (nsIRedirectHistoryEntry* redirectHistoryEntry : 2195 loadInfo->RedirectChain()) { 2196 nsCOMPtr<nsIPrincipal> principal; 2197 redirectHistoryEntry->GetPrincipal(getter_AddRefs(principal)); 2198 if (!principal) { 2199 return true; 2200 } 2201 2202 nsCOMPtr<nsIURI> uri; 2203 auto* basePrin = BasePrincipal::Cast(principal); 2204 basePrin->GetURI(getter_AddRefs(uri)); 2205 if (!uri) { 2206 return true; 2207 } 2208 2209 if (aboutBlankInherits && NS_IsAboutBlank(uri)) { 2210 continue; 2211 } 2212 2213 nsresult res; 2214 if (aReport) { 2215 res = loadingPrincipal->CheckMayLoadWithReporting(uri, dataInherits, 2216 innerWindowID); 2217 } else { 2218 res = loadingPrincipal->CheckMayLoad(uri, dataInherits); 2219 } 2220 if (NS_FAILED(res)) { 2221 return true; 2222 } 2223 } 2224 2225 nsCOMPtr<nsIURI> uri; 2226 NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); 2227 if (!uri) { 2228 return true; 2229 } 2230 2231 if (aboutBlankInherits && NS_IsAboutBlank(uri)) { 2232 return false; 2233 } 2234 2235 nsresult res; 2236 if (aReport) { 2237 res = loadingPrincipal->CheckMayLoadWithReporting(uri, dataInherits, 2238 innerWindowID); 2239 } else { 2240 res = loadingPrincipal->CheckMayLoad(uri, dataInherits); 2241 } 2242 2243 return NS_FAILED(res); 2244 } 2245 2246 bool NS_IsSafeMethodNav(nsIChannel* aChannel) { 2247 RefPtr<HttpBaseChannel> baseChan = do_QueryObject(aChannel); 2248 if (!baseChan) { 2249 return false; 2250 } 2251 nsHttpRequestHead* requestHead = baseChan->GetRequestHead(); 2252 if (!requestHead) { 2253 return false; 2254 } 2255 return requestHead->IsSafeMethod(); 2256 } 2257 2258 void NS_WrapAuthPrompt(nsIAuthPrompt* aAuthPrompt, 2259 nsIAuthPrompt2** aAuthPrompt2) { 2260 nsCOMPtr<nsIAuthPromptAdapterFactory> factory; 2261 factory = mozilla::components::AuthPromptAdapter::Service(); 2262 if (!factory) return; 2263 2264 NS_WARNING("Using deprecated nsIAuthPrompt"); 2265 factory->CreateAdapter(aAuthPrompt, aAuthPrompt2); 2266 } 2267 2268 void NS_QueryAuthPrompt2(nsIInterfaceRequestor* aCallbacks, 2269 nsIAuthPrompt2** aAuthPrompt) { 2270 CallGetInterface(aCallbacks, aAuthPrompt); 2271 if (*aAuthPrompt) return; 2272 2273 // Maybe only nsIAuthPrompt is provided and we have to wrap it. 2274 nsCOMPtr<nsIAuthPrompt> prompt(do_GetInterface(aCallbacks)); 2275 if (!prompt) return; 2276 2277 NS_WrapAuthPrompt(prompt, aAuthPrompt); 2278 } 2279 2280 void NS_QueryAuthPrompt2(nsIChannel* aChannel, nsIAuthPrompt2** aAuthPrompt) { 2281 *aAuthPrompt = nullptr; 2282 2283 // We want to use any auth prompt we can find on the channel's callbacks, 2284 // and if that fails use the loadgroup's prompt (if any) 2285 // Therefore, we can't just use NS_QueryNotificationCallbacks, because 2286 // that would prefer a loadgroup's nsIAuthPrompt2 over a channel's 2287 // nsIAuthPrompt. 2288 nsCOMPtr<nsIInterfaceRequestor> callbacks; 2289 aChannel->GetNotificationCallbacks(getter_AddRefs(callbacks)); 2290 if (callbacks) { 2291 NS_QueryAuthPrompt2(callbacks, aAuthPrompt); 2292 if (*aAuthPrompt) return; 2293 } 2294 2295 nsCOMPtr<nsILoadGroup> group; 2296 aChannel->GetLoadGroup(getter_AddRefs(group)); 2297 if (!group) return; 2298 2299 group->GetNotificationCallbacks(getter_AddRefs(callbacks)); 2300 if (!callbacks) return; 2301 NS_QueryAuthPrompt2(callbacks, aAuthPrompt); 2302 } 2303 2304 nsresult NS_NewNotificationCallbacksAggregation( 2305 nsIInterfaceRequestor* callbacks, nsILoadGroup* loadGroup, 2306 nsIEventTarget* target, nsIInterfaceRequestor** result) { 2307 nsCOMPtr<nsIInterfaceRequestor> cbs; 2308 if (loadGroup) loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs)); 2309 return NS_NewInterfaceRequestorAggregation(callbacks, cbs, target, result); 2310 } 2311 2312 nsresult NS_NewNotificationCallbacksAggregation( 2313 nsIInterfaceRequestor* callbacks, nsILoadGroup* loadGroup, 2314 nsIInterfaceRequestor** result) { 2315 return NS_NewNotificationCallbacksAggregation(callbacks, loadGroup, nullptr, 2316 result); 2317 } 2318 2319 nsresult NS_DoImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result) { 2320 MOZ_ASSERT(nestedURI, "Must have a nested URI!"); 2321 MOZ_ASSERT(!*result, "Must have null *result"); 2322 2323 nsCOMPtr<nsIURI> inner; 2324 nsresult rv = nestedURI->GetInnerURI(getter_AddRefs(inner)); 2325 NS_ENSURE_SUCCESS(rv, rv); 2326 2327 // We may need to loop here until we reach the innermost 2328 // URI. 2329 nsCOMPtr<nsINestedURI> nestedInner(do_QueryInterface(inner)); 2330 while (nestedInner) { 2331 rv = nestedInner->GetInnerURI(getter_AddRefs(inner)); 2332 NS_ENSURE_SUCCESS(rv, rv); 2333 nestedInner = do_QueryInterface(inner); 2334 } 2335 2336 // Found the innermost one if we reach here. 2337 inner.swap(*result); 2338 2339 return rv; 2340 } 2341 2342 nsresult NS_ImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result) { 2343 // Make it safe to use swap() 2344 *result = nullptr; 2345 2346 return NS_DoImplGetInnermostURI(nestedURI, result); 2347 } 2348 2349 already_AddRefed<nsIURI> NS_GetInnermostURI(nsIURI* aURI) { 2350 MOZ_ASSERT(aURI, "Must have URI"); 2351 2352 nsCOMPtr<nsIURI> uri = aURI; 2353 2354 nsCOMPtr<nsINestedURI> nestedURI(do_QueryInterface(uri)); 2355 if (!nestedURI) { 2356 return uri.forget(); 2357 } 2358 2359 nsresult rv = nestedURI->GetInnermostURI(getter_AddRefs(uri)); 2360 if (NS_FAILED(rv)) { 2361 return nullptr; 2362 } 2363 2364 return uri.forget(); 2365 } 2366 2367 nsresult NS_GetFinalChannelURI(nsIChannel* channel, nsIURI** uri) { 2368 *uri = nullptr; 2369 2370 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo(); 2371 nsCOMPtr<nsIURI> resultPrincipalURI; 2372 loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI)); 2373 if (resultPrincipalURI) { 2374 resultPrincipalURI.forget(uri); 2375 return NS_OK; 2376 } 2377 return channel->GetOriginalURI(uri); 2378 } 2379 2380 nsresult NS_URIChainHasFlags(nsIURI* uri, uint32_t flags, bool* result) { 2381 nsresult rv; 2382 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv); 2383 NS_ENSURE_SUCCESS(rv, rv); 2384 2385 return util->URIChainHasFlags(uri, flags, result); 2386 } 2387 2388 uint32_t NS_SecurityHashURI(nsIURI* aURI) { 2389 nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI); 2390 2391 nsAutoCString scheme; 2392 uint32_t schemeHash = 0; 2393 if (NS_SUCCEEDED(baseURI->GetScheme(scheme))) { 2394 schemeHash = mozilla::HashString(scheme); 2395 } 2396 2397 // TODO figure out how to hash file:// URIs 2398 if (scheme.EqualsLiteral("file")) return schemeHash; // sad face 2399 2400 #if IS_ORIGIN_IS_FULL_SPEC_DEFINED 2401 bool hasFlag; 2402 if (NS_FAILED(NS_URIChainHasFlags( 2403 baseURI, nsIProtocolHandler::ORIGIN_IS_FULL_SPEC, &hasFlag)) || 2404 hasFlag) { 2405 nsAutoCString spec; 2406 uint32_t specHash; 2407 nsresult res = baseURI->GetSpec(spec); 2408 if (NS_SUCCEEDED(res)) 2409 specHash = mozilla::HashString(spec); 2410 else 2411 specHash = static_cast<uint32_t>(res); 2412 return specHash; 2413 } 2414 #endif 2415 2416 nsAutoCString host; 2417 uint32_t hostHash = 0; 2418 if (NS_SUCCEEDED(baseURI->GetAsciiHost(host))) { 2419 hostHash = mozilla::HashString(host); 2420 } 2421 2422 return mozilla::AddToHash(schemeHash, hostHash, NS_GetRealPort(baseURI)); 2423 } 2424 2425 bool NS_SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI, 2426 bool aStrictFileOriginPolicy) { 2427 nsresult rv; 2428 2429 // Note that this is not an Equals() test on purpose -- for URIs that don't 2430 // support host/port, we want equality to basically be object identity, for 2431 // security purposes. Otherwise, for example, two javascript: URIs that 2432 // are otherwise unrelated could end up "same origin", which would be 2433 // unfortunate. 2434 if (aSourceURI && aSourceURI == aTargetURI) { 2435 return true; 2436 } 2437 2438 if (!aTargetURI || !aSourceURI) { 2439 return false; 2440 } 2441 2442 // If either URI is a nested URI, get the base URI 2443 nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI); 2444 nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI); 2445 2446 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) 2447 // Check if either URI has a special origin. 2448 nsCOMPtr<nsIURI> origin; 2449 nsCOMPtr<nsIURIWithSpecialOrigin> uriWithSpecialOrigin = 2450 do_QueryInterface(sourceBaseURI); 2451 if (uriWithSpecialOrigin) { 2452 rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin)); 2453 if (NS_WARN_IF(NS_FAILED(rv))) { 2454 return false; 2455 } 2456 MOZ_ASSERT(origin); 2457 sourceBaseURI = origin; 2458 } 2459 uriWithSpecialOrigin = do_QueryInterface(targetBaseURI); 2460 if (uriWithSpecialOrigin) { 2461 rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin)); 2462 if (NS_WARN_IF(NS_FAILED(rv))) { 2463 return false; 2464 } 2465 MOZ_ASSERT(origin); 2466 targetBaseURI = origin; 2467 } 2468 #endif 2469 2470 nsCOMPtr<nsIPrincipal> sourceBlobPrincipal; 2471 if (BlobURLProtocolHandler::GetBlobURLPrincipal( 2472 sourceBaseURI, getter_AddRefs(sourceBlobPrincipal))) { 2473 nsCOMPtr<nsIURI> sourceBlobOwnerURI; 2474 auto* basePrin = BasePrincipal::Cast(sourceBlobPrincipal); 2475 rv = basePrin->GetURI(getter_AddRefs(sourceBlobOwnerURI)); 2476 if (NS_SUCCEEDED(rv)) { 2477 sourceBaseURI = sourceBlobOwnerURI; 2478 } 2479 } 2480 2481 nsCOMPtr<nsIPrincipal> targetBlobPrincipal; 2482 if (BlobURLProtocolHandler::GetBlobURLPrincipal( 2483 targetBaseURI, getter_AddRefs(targetBlobPrincipal))) { 2484 nsCOMPtr<nsIURI> targetBlobOwnerURI; 2485 auto* basePrin = BasePrincipal::Cast(targetBlobPrincipal); 2486 rv = basePrin->GetURI(getter_AddRefs(targetBlobOwnerURI)); 2487 if (NS_SUCCEEDED(rv)) { 2488 targetBaseURI = targetBlobOwnerURI; 2489 } 2490 } 2491 2492 if (!sourceBaseURI || !targetBaseURI) return false; 2493 2494 // Compare schemes 2495 nsAutoCString targetScheme; 2496 bool sameScheme = false; 2497 if (NS_FAILED(targetBaseURI->GetScheme(targetScheme)) || 2498 NS_FAILED(sourceBaseURI->SchemeIs(targetScheme.get(), &sameScheme)) || 2499 !sameScheme) { 2500 // Not same-origin if schemes differ 2501 return false; 2502 } 2503 2504 // For file scheme, reject unless the files are identical. 2505 if (targetScheme.EqualsLiteral("file")) { 2506 // in traditional unsafe behavior all files are the same origin 2507 if (!aStrictFileOriginPolicy) return true; 2508 2509 nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(sourceBaseURI)); 2510 nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(targetBaseURI)); 2511 2512 if (!sourceFileURL || !targetFileURL) return false; 2513 2514 nsCOMPtr<nsIFile> sourceFile, targetFile; 2515 2516 sourceFileURL->GetFile(getter_AddRefs(sourceFile)); 2517 targetFileURL->GetFile(getter_AddRefs(targetFile)); 2518 2519 if (!sourceFile || !targetFile) return false; 2520 2521 // Otherwise they had better match 2522 bool filesAreEqual = false; 2523 rv = sourceFile->Equals(targetFile, &filesAreEqual); 2524 return NS_SUCCEEDED(rv) && filesAreEqual; 2525 } 2526 2527 #if IS_ORIGIN_IS_FULL_SPEC_DEFINED 2528 bool hasFlag; 2529 if (NS_FAILED(NS_URIChainHasFlags( 2530 targetBaseURI, nsIProtocolHandler::ORIGIN_IS_FULL_SPEC, &hasFlag)) || 2531 hasFlag) { 2532 // URIs with this flag have the whole spec as a distinct trust 2533 // domain; use the whole spec for comparison 2534 nsAutoCString targetSpec; 2535 nsAutoCString sourceSpec; 2536 return (NS_SUCCEEDED(targetBaseURI->GetSpec(targetSpec)) && 2537 NS_SUCCEEDED(sourceBaseURI->GetSpec(sourceSpec)) && 2538 targetSpec.Equals(sourceSpec)); 2539 } 2540 #endif 2541 2542 // Compare hosts 2543 nsAutoCString targetHost; 2544 nsAutoCString sourceHost; 2545 if (NS_FAILED(targetBaseURI->GetAsciiHost(targetHost)) || 2546 NS_FAILED(sourceBaseURI->GetAsciiHost(sourceHost))) { 2547 return false; 2548 } 2549 2550 nsCOMPtr<nsIStandardURL> targetURL(do_QueryInterface(targetBaseURI)); 2551 nsCOMPtr<nsIStandardURL> sourceURL(do_QueryInterface(sourceBaseURI)); 2552 if (!targetURL || !sourceURL) { 2553 return false; 2554 } 2555 2556 if (!targetHost.Equals(sourceHost, nsCaseInsensitiveCStringComparator)) { 2557 return false; 2558 } 2559 2560 return NS_GetRealPort(targetBaseURI) == NS_GetRealPort(sourceBaseURI); 2561 } 2562 2563 bool NS_URIIsLocalFile(nsIURI* aURI) { 2564 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(); 2565 2566 bool isFile; 2567 return util && 2568 NS_SUCCEEDED(util->ProtocolHasFlags( 2569 aURI, nsIProtocolHandler::URI_IS_LOCAL_FILE, &isFile)) && 2570 isFile; 2571 } 2572 2573 bool NS_IsInternalSameURIRedirect(nsIChannel* aOldChannel, 2574 nsIChannel* aNewChannel, uint32_t aFlags) { 2575 if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) { 2576 return false; 2577 } 2578 2579 nsCOMPtr<nsIURI> oldURI, newURI; 2580 aOldChannel->GetURI(getter_AddRefs(oldURI)); 2581 aNewChannel->GetURI(getter_AddRefs(newURI)); 2582 2583 if (!oldURI || !newURI) { 2584 return false; 2585 } 2586 2587 bool res; 2588 return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res; 2589 } 2590 2591 bool NS_IsHSTSUpgradeRedirect(nsIChannel* aOldChannel, nsIChannel* aNewChannel, 2592 uint32_t aFlags) { 2593 if (!(aFlags & nsIChannelEventSink::REDIRECT_STS_UPGRADE)) { 2594 return false; 2595 } 2596 2597 nsCOMPtr<nsIURI> oldURI, newURI; 2598 aOldChannel->GetURI(getter_AddRefs(oldURI)); 2599 aNewChannel->GetURI(getter_AddRefs(newURI)); 2600 2601 if (!oldURI || !newURI) { 2602 return false; 2603 } 2604 2605 if (!oldURI->SchemeIs("http")) { 2606 return false; 2607 } 2608 2609 nsCOMPtr<nsIURI> upgradedURI; 2610 nsresult rv = NS_GetSecureUpgradedURI(oldURI, getter_AddRefs(upgradedURI)); 2611 if (NS_FAILED(rv)) { 2612 return false; 2613 } 2614 2615 bool res; 2616 return NS_SUCCEEDED(upgradedURI->Equals(newURI, &res)) && res; 2617 } 2618 2619 bool NS_ShouldRemoveAuthHeaderOnRedirect(nsIChannel* aOldChannel, 2620 nsIChannel* aNewChannel, 2621 uint32_t aFlags) { 2622 // we need to strip Authentication headers for external cross-origin redirects 2623 // Howerver, we should NOT strip auth headers for 2624 // - internal redirects/HSTS upgrades 2625 // - same origin redirects 2626 // Ref: https://fetch.spec.whatwg.org/#http-redirect-fetch 2627 if ((aFlags & (nsIChannelEventSink::REDIRECT_STS_UPGRADE | 2628 nsIChannelEventSink::REDIRECT_INTERNAL))) { 2629 // this is an internal redirect do not strip auth header 2630 return false; 2631 } 2632 nsCOMPtr<nsIURI> oldUri; 2633 MOZ_ALWAYS_SUCCEEDS( 2634 NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldUri))); 2635 2636 nsCOMPtr<nsIURI> newUri; 2637 MOZ_ALWAYS_SUCCEEDS( 2638 NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newUri))); 2639 2640 nsresult rv = nsContentUtils::GetSecurityManager()->CheckSameOriginURI( 2641 newUri, oldUri, false, false); 2642 2643 return NS_FAILED(rv); 2644 } 2645 2646 nsresult NS_LinkRedirectChannels(uint64_t channelId, 2647 nsIParentChannel* parentChannel, 2648 nsIChannel** _result) { 2649 nsCOMPtr<nsIRedirectChannelRegistrar> registrar = 2650 RedirectChannelRegistrar::GetOrCreate(); 2651 MOZ_ASSERT(registrar); 2652 2653 return registrar->LinkChannels(channelId, parentChannel, _result); 2654 } 2655 2656 nsILoadInfo::CrossOriginEmbedderPolicy 2657 NS_GetCrossOriginEmbedderPolicyFromHeader( 2658 const nsACString& aHeader, bool aIsOriginTrialCoepCredentiallessEnabled) { 2659 nsCOMPtr<nsISFVService> sfv = GetSFVService(); 2660 2661 nsCOMPtr<nsISFVItem> item; 2662 nsresult rv = sfv->ParseItem(aHeader, getter_AddRefs(item)); 2663 if (NS_FAILED(rv)) { 2664 return nsILoadInfo::EMBEDDER_POLICY_NULL; 2665 } 2666 2667 nsCOMPtr<nsISFVBareItem> value; 2668 rv = item->GetValue(getter_AddRefs(value)); 2669 if (NS_FAILED(rv)) { 2670 return nsILoadInfo::EMBEDDER_POLICY_NULL; 2671 } 2672 2673 nsCOMPtr<nsISFVToken> token = do_QueryInterface(value); 2674 if (!token) { 2675 return nsILoadInfo::EMBEDDER_POLICY_NULL; 2676 } 2677 2678 nsAutoCString embedderPolicy; 2679 rv = token->GetValue(embedderPolicy); 2680 if (NS_FAILED(rv)) { 2681 return nsILoadInfo::EMBEDDER_POLICY_NULL; 2682 } 2683 2684 if (embedderPolicy.EqualsLiteral("require-corp")) { 2685 return nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP; 2686 } else if (embedderPolicy.EqualsLiteral("credentialless") && 2687 IsCoepCredentiallessEnabled( 2688 aIsOriginTrialCoepCredentiallessEnabled)) { 2689 return nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS; 2690 } 2691 2692 return nsILoadInfo::EMBEDDER_POLICY_NULL; 2693 } 2694 2695 bool NS_GetForceLoadAtTopFromHeader(const nsACString& aHeader) { 2696 nsCOMPtr<nsISFVService> sfv = mozilla::net::GetSFVService(); 2697 2698 nsCOMPtr<nsISFVDictionary> dict; 2699 if (NS_FAILED(sfv->ParseDictionary(aHeader, getter_AddRefs(dict)))) { 2700 return false; 2701 } 2702 nsCOMPtr<nsISFVItemOrInnerList> iil; 2703 if (NS_FAILED(dict->Get("force-load-at-top"_ns, getter_AddRefs(iil)))) { 2704 return false; 2705 } 2706 2707 nsCOMPtr<nsISFVItem> item(do_QueryInterface(iil)); 2708 if (!item) { 2709 return false; 2710 } 2711 2712 nsCOMPtr<nsISFVBareItem> bareItem; 2713 if (NS_FAILED(item->GetValue(getter_AddRefs(bareItem)))) { 2714 return false; 2715 } 2716 2717 int32_t type; 2718 if (NS_FAILED(bareItem->GetType(&type))) { 2719 return false; 2720 } 2721 2722 nsCOMPtr<nsISFVBool> boolItem(do_QueryInterface(bareItem)); 2723 if (!boolItem) { 2724 return false; 2725 } 2726 2727 bool b; 2728 if (NS_FAILED(boolItem->GetValue(&b))) { 2729 return false; 2730 } 2731 2732 return b; 2733 } 2734 2735 /** Given the first (disposition) token from a Content-Disposition header, 2736 * tell whether it indicates the content is inline or attachment 2737 * @param aDispToken the disposition token from the content-disposition header 2738 */ 2739 uint32_t NS_GetContentDispositionFromToken(const nsAString& aDispToken) { 2740 // RFC 2183, section 2.8 says that an unknown disposition 2741 // value should be treated as "attachment" 2742 // If all of these tests eval to false, then we have a content-disposition of 2743 // "attachment" or unknown 2744 if (aDispToken.IsEmpty() || aDispToken.LowerCaseEqualsLiteral("inline") || 2745 // Broken sites just send 2746 // Content-Disposition: filename="file" 2747 // without a disposition token... screen those out. 2748 StringHead(aDispToken, 8).LowerCaseEqualsLiteral("filename")) { 2749 return nsIChannel::DISPOSITION_INLINE; 2750 } 2751 2752 return nsIChannel::DISPOSITION_ATTACHMENT; 2753 } 2754 2755 uint32_t NS_GetContentDispositionFromHeader(const nsACString& aHeader, 2756 nsIChannel* aChan /* = nullptr */) { 2757 nsresult rv; 2758 nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar; 2759 mimehdrpar = mozilla::components::MimeHeaderParam::Service(&rv); 2760 if (NS_FAILED(rv)) return nsIChannel::DISPOSITION_ATTACHMENT; 2761 2762 nsAutoString dispToken; 2763 rv = mimehdrpar->GetParameterHTTP(aHeader, "", ""_ns, true, nullptr, 2764 dispToken); 2765 2766 if (NS_FAILED(rv)) { 2767 // special case (see bug 272541): empty disposition type handled as "inline" 2768 if (rv == NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY) { 2769 return nsIChannel::DISPOSITION_INLINE; 2770 } 2771 return nsIChannel::DISPOSITION_ATTACHMENT; 2772 } 2773 2774 return NS_GetContentDispositionFromToken(dispToken); 2775 } 2776 2777 nsresult NS_GetFilenameFromDisposition(nsAString& aFilename, 2778 const nsACString& aDisposition) { 2779 aFilename.Truncate(); 2780 2781 nsresult rv; 2782 nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar; 2783 mimehdrpar = mozilla::components::MimeHeaderParam::Service(&rv); 2784 if (NS_FAILED(rv)) return rv; 2785 2786 // Get the value of 'filename' parameter 2787 rv = mimehdrpar->GetParameterHTTP(aDisposition, "filename", ""_ns, true, 2788 nullptr, aFilename); 2789 2790 if (NS_FAILED(rv)) { 2791 aFilename.Truncate(); 2792 return rv; 2793 } 2794 2795 if (aFilename.IsEmpty()) return NS_ERROR_NOT_AVAILABLE; 2796 2797 // Filename may still be percent-encoded. Fix: 2798 if (aFilename.FindChar('%') != -1) { 2799 nsCOMPtr<nsITextToSubURI> textToSubURI; 2800 textToSubURI = mozilla::components::TextToSubURI::Service(&rv); 2801 if (NS_SUCCEEDED(rv)) { 2802 nsAutoString unescaped; 2803 textToSubURI->UnEscapeURIForUI(NS_ConvertUTF16toUTF8(aFilename), 2804 /* dontEscape = */ true, unescaped); 2805 aFilename.Assign(unescaped); 2806 } 2807 } 2808 2809 return NS_OK; 2810 } 2811 2812 void net_EnsurePSMInit() { 2813 if (XRE_IsSocketProcess()) { 2814 EnsureNSSInitializedChromeOrContent(); 2815 return; 2816 } 2817 2818 MOZ_ASSERT(XRE_IsParentProcess()); 2819 MOZ_ASSERT(NS_IsMainThread()); 2820 2821 DebugOnly<bool> rv = EnsureNSSInitializedChromeOrContent(); 2822 MOZ_ASSERT(rv); 2823 } 2824 2825 bool NS_IsAboutBlank(nsIURI* uri) { 2826 // GetSpec can be expensive for some URIs, so check the scheme first. 2827 if (!uri->SchemeIs("about")) { 2828 return false; 2829 } 2830 2831 nsAutoCString spec; 2832 if (NS_FAILED(uri->GetSpec(spec))) { 2833 return false; 2834 } 2835 2836 return spec.EqualsLiteral("about:blank"); 2837 } 2838 2839 bool NS_IsAboutBlankAllowQueryAndFragment(nsIURI* uri) { 2840 // GetSpec can be expensive for some URIs, so check the scheme first. 2841 if (!uri->SchemeIs("about")) { 2842 return false; 2843 } 2844 2845 nsAutoCString name; 2846 if (NS_FAILED(NS_GetAboutModuleName(uri, name))) { 2847 return false; 2848 } 2849 2850 return name.EqualsLiteral("blank"); 2851 } 2852 2853 bool NS_IsAboutSrcdoc(nsIURI* uri) { 2854 // GetSpec can be expensive for some URIs, so check the scheme first. 2855 if (!uri->SchemeIs("about")) { 2856 return false; 2857 } 2858 2859 nsAutoCString spec; 2860 if (NS_FAILED(uri->GetSpec(spec))) { 2861 return false; 2862 } 2863 2864 return spec.EqualsLiteral("about:srcdoc"); 2865 } 2866 2867 // https://fetch.spec.whatwg.org/#fetch-scheme 2868 bool NS_IsFetchScheme(nsIURI* uri) { 2869 for (const auto& scheme : { 2870 "http", 2871 "https", 2872 "about", 2873 "blob", 2874 "data", 2875 "file", 2876 }) { 2877 if (uri->SchemeIs(scheme)) { 2878 return true; 2879 } 2880 } 2881 2882 return false; 2883 } 2884 2885 nsresult NS_GenerateHostPort(const nsCString& host, int32_t port, 2886 nsACString& hostLine) { 2887 if (strchr(host.get(), ':')) { 2888 // host is an IPv6 address literal and must be encapsulated in []'s 2889 hostLine.Assign('['); 2890 // scope id is not needed for Host header. 2891 int scopeIdPos = host.FindChar('%'); 2892 if (scopeIdPos == -1) { 2893 hostLine.Append(host); 2894 } else if (scopeIdPos > 0) { 2895 hostLine.Append(Substring(host, 0, scopeIdPos)); 2896 } else { 2897 return NS_ERROR_MALFORMED_URI; 2898 } 2899 hostLine.Append(']'); 2900 } else { 2901 hostLine.Assign(host); 2902 } 2903 if (port != -1) { 2904 hostLine.Append(':'); 2905 hostLine.AppendInt(port); 2906 } 2907 return NS_OK; 2908 } 2909 2910 void NS_SniffContent(const char* aSnifferType, nsIRequest* aRequest, 2911 const uint8_t* aData, uint32_t aLength, 2912 nsACString& aSniffedType) { 2913 using ContentSnifferCache = nsCategoryCache<nsIContentSniffer>; 2914 extern ContentSnifferCache* gNetSniffers; 2915 extern ContentSnifferCache* gDataSniffers; 2916 extern ContentSnifferCache* gORBSniffers; 2917 extern ContentSnifferCache* gNetAndORBSniffers; 2918 ContentSnifferCache* cache = nullptr; 2919 if (!strcmp(aSnifferType, NS_CONTENT_SNIFFER_CATEGORY)) { 2920 if (!gNetSniffers) { 2921 gNetSniffers = new ContentSnifferCache(NS_CONTENT_SNIFFER_CATEGORY); 2922 } 2923 cache = gNetSniffers; 2924 } else if (!strcmp(aSnifferType, NS_DATA_SNIFFER_CATEGORY)) { 2925 if (!gDataSniffers) { 2926 gDataSniffers = new ContentSnifferCache(NS_DATA_SNIFFER_CATEGORY); 2927 } 2928 cache = gDataSniffers; 2929 } else if (!strcmp(aSnifferType, NS_ORB_SNIFFER_CATEGORY)) { 2930 if (!gORBSniffers) { 2931 gORBSniffers = new ContentSnifferCache(NS_ORB_SNIFFER_CATEGORY); 2932 } 2933 cache = gORBSniffers; 2934 } else if (!strcmp(aSnifferType, NS_CONTENT_AND_ORB_SNIFFER_CATEGORY)) { 2935 if (!gNetAndORBSniffers) { 2936 gNetAndORBSniffers = 2937 new ContentSnifferCache(NS_CONTENT_AND_ORB_SNIFFER_CATEGORY); 2938 } 2939 cache = gNetAndORBSniffers; 2940 } else { 2941 // Invalid content sniffer type was requested 2942 MOZ_ASSERT(false); 2943 return; 2944 } 2945 2946 // In case XCTO nosniff was present, we could just skip sniffing here 2947 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); 2948 if (channel) { 2949 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo(); 2950 if (loadInfo->GetSkipContentSniffing()) { 2951 /* Bug 1571742 2952 * We cannot skip snffing if the current MIME-Type might be a JSON. 2953 * The JSON-Viewer relies on its own sniffer to determine, if it can 2954 * render the page, so we need to make an exception if the Server provides 2955 * a application/ mime, as it might be json. 2956 */ 2957 nsAutoCString currentContentType; 2958 channel->GetContentType(currentContentType); 2959 if (!StringBeginsWith(currentContentType, "application/"_ns)) { 2960 return; 2961 } 2962 } 2963 } 2964 nsCOMArray<nsIContentSniffer> sniffers; 2965 cache->GetEntries(sniffers); 2966 for (int32_t i = 0; i < sniffers.Count(); ++i) { 2967 nsresult rv = sniffers[i]->GetMIMETypeFromContent(aRequest, aData, aLength, 2968 aSniffedType); 2969 if (NS_SUCCEEDED(rv) && !aSniffedType.IsEmpty()) { 2970 return; 2971 } 2972 } 2973 2974 aSniffedType.Truncate(); 2975 } 2976 2977 bool NS_IsSrcdocChannel(nsIChannel* aChannel) { 2978 bool isSrcdoc; 2979 nsCOMPtr<nsIInputStreamChannel> isr = do_QueryInterface(aChannel); 2980 if (isr) { 2981 isr->GetIsSrcdocChannel(&isSrcdoc); 2982 return isSrcdoc; 2983 } 2984 nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(aChannel); 2985 if (vsc) { 2986 nsresult rv = vsc->GetIsSrcdocChannel(&isSrcdoc); 2987 if (NS_SUCCEEDED(rv)) { 2988 return isSrcdoc; 2989 } 2990 } 2991 return false; 2992 } 2993 2994 // helper function for NS_ShouldSecureUpgrade for checking HSTS 2995 bool handleResultFunc(bool aAllowSTS, bool aIsStsHost) { 2996 if (aIsStsHost) { 2997 LOG(("nsHttpChannel::Connect() STS permissions found\n")); 2998 if (aAllowSTS) { 2999 return true; 3000 } 3001 } 3002 return false; 3003 }; 3004 // That function is a helper function of NS_ShouldSecureUpgrade to check if 3005 // CSP upgrade-insecure-requests, Mixed content auto upgrading or HTTPs-Only/- 3006 // First should upgrade the given request. 3007 static bool ShouldSecureUpgradeNoHSTS(nsIURI* aURI, nsILoadInfo* aLoadInfo) { 3008 // 2. CSP upgrade-insecure-requests 3009 if (aLoadInfo->GetUpgradeInsecureRequests()) { 3010 // let's log a message to the console that we are upgrading a request 3011 nsAutoCString scheme; 3012 aURI->GetScheme(scheme); 3013 // append the additional 's' for security to the scheme :-) 3014 scheme.AppendLiteral("s"); 3015 NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault()); 3016 NS_ConvertUTF8toUTF16 reportScheme(scheme); 3017 AutoTArray<nsString, 2> params = {reportSpec, reportScheme}; 3018 uint64_t innerWindowId = aLoadInfo->GetInnerWindowID(); 3019 CSP_LogLocalizedStr("upgradeInsecureRequest", params, 3020 ""_ns, // aSourceFile 3021 u""_ns, // aScriptSample 3022 0, // aLineNumber 3023 1, // aColumnNumber 3024 nsIScriptError::warningFlag, 3025 "upgradeInsecureRequest"_ns, innerWindowId, 3026 aLoadInfo->GetOriginAttributes().IsPrivateBrowsing()); 3027 aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::CSP_UIR); 3028 return true; 3029 } 3030 // 3. Mixed content auto upgrading 3031 if (aLoadInfo->GetBrowserUpgradeInsecureRequests()) { 3032 // let's log a message to the console that we are upgrading a request 3033 nsAutoCString scheme; 3034 aURI->GetScheme(scheme); 3035 // append the additional 's' for security to the scheme :-) 3036 scheme.AppendLiteral("s"); 3037 NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault()); 3038 NS_ConvertUTF8toUTF16 reportScheme(scheme); 3039 AutoTArray<nsString, 2> params = {reportSpec, reportScheme}; 3040 3041 nsAutoString localizedMsg; 3042 nsContentUtils::FormatLocalizedString(nsContentUtils::eSECURITY_PROPERTIES, 3043 "MixedContentAutoUpgrade", params, 3044 localizedMsg); 3045 3046 // Prepending ixed Content to the outgoing console message 3047 nsString message; 3048 message.AppendLiteral(u"Mixed Content: "); 3049 message.Append(localizedMsg); 3050 3051 uint64_t innerWindowId = aLoadInfo->GetInnerWindowID(); 3052 nsContentUtils::ReportToConsoleByWindowID( 3053 message, nsIScriptError::warningFlag, "Mixed Content Message"_ns, 3054 innerWindowId, SourceLocation(aURI)); 3055 3056 // Set this flag so we know we'll upgrade because of 3057 // 'security.mixed_content.upgrade_display_content'. 3058 aLoadInfo->SetBrowserDidUpgradeInsecureRequests(true); 3059 return true; 3060 } 3061 3062 // 4. Https-Only 3063 if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, aLoadInfo)) { 3064 aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::HTTPS_ONLY_UPGRADE); 3065 return true; 3066 } 3067 // 4.a Https-First 3068 if (nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(aURI, aLoadInfo)) { 3069 if (aLoadInfo->GetSchemelessInput() == 3070 nsILoadInfo::SchemelessInputTypeSchemeless) { 3071 aLoadInfo->SetHttpsUpgradeTelemetry( 3072 nsILoadInfo::HTTPS_FIRST_SCHEMELESS_UPGRADE); 3073 } else { 3074 aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::HTTPS_FIRST_UPGRADE); 3075 } 3076 return true; 3077 } 3078 return false; 3079 } 3080 3081 // Check if channel should be upgraded. check in the following order: 3082 // 1. HSTS 3083 // 2. CSP upgrade-insecure-requests 3084 // 3. Mixed content auto upgrading 3085 // 4. Https-Only / first 3086 // (5. Https RR - will be checked in nsHttpChannel) 3087 nsresult NS_ShouldSecureUpgrade( 3088 nsIURI* aURI, nsILoadInfo* aLoadInfo, nsIPrincipal* aChannelResultPrincipal, 3089 bool aAllowSTS, const OriginAttributes& aOriginAttributes, 3090 bool& aShouldUpgrade, std::function<void(bool, nsresult)>&& aResultCallback, 3091 bool& aWillCallback) { 3092 MOZ_ASSERT(XRE_IsParentProcess()); 3093 if (!XRE_IsParentProcess()) { 3094 return NS_ERROR_NOT_AVAILABLE; 3095 } 3096 3097 aWillCallback = false; 3098 aShouldUpgrade = false; 3099 3100 // Even if we're in private browsing mode, we still enforce existing STS 3101 // data (it is read-only). 3102 // if the connection is not using SSL and either the exact host matches or 3103 // a superdomain wants to force HTTPS, do it. 3104 bool isHttps = aURI->SchemeIs("https"); 3105 3106 // If request is https, then there is nothing to do here. 3107 if (isHttps) { 3108 aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::ALREADY_HTTPS); 3109 aShouldUpgrade = false; 3110 return NS_OK; 3111 } 3112 // If it is a mixed content trustworthy loopback, then we shouldn't upgrade 3113 // it. 3114 if (nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(aURI) || 3115 nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(aURI)) { 3116 aShouldUpgrade = false; 3117 return NS_OK; 3118 } 3119 // If no loadInfo exist there is nothing to upgrade here. 3120 if (!aLoadInfo) { 3121 aShouldUpgrade = false; 3122 return NS_OK; 3123 } 3124 // The loadInfo indicates no HTTPS upgrade. 3125 bool skipHTTPSUpgrade = false; 3126 (void)aLoadInfo->GetSkipHTTPSUpgrade(&skipHTTPSUpgrade); 3127 if (skipHTTPSUpgrade) { 3128 aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::SKIP_HTTPS_UPGRADE); 3129 aShouldUpgrade = false; 3130 return NS_OK; 3131 } 3132 MOZ_ASSERT(!aURI->SchemeIs("https")); 3133 3134 // enforce Strict-Transport-Security 3135 nsISiteSecurityService* sss = gHttpHandler->GetSSService(); 3136 NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY); 3137 3138 bool isStsHost = false; 3139 // Calling |IsSecureURI| before the storage is ready to read will 3140 // block the main thread. Once the storage is ready, we can call it 3141 // from main thread. 3142 static Atomic<bool, Relaxed> storageReady(false); 3143 if (!storageReady && gSocketTransportService && aResultCallback) { 3144 nsCOMPtr<nsILoadInfo> loadInfo = aLoadInfo; 3145 nsCOMPtr<nsIURI> uri = aURI; 3146 auto callbackWrapper = [resultCallback{std::move(aResultCallback)}, uri, 3147 loadInfo](bool aShouldUpgrade, nsresult aStatus) { 3148 MOZ_ASSERT(NS_IsMainThread()); 3149 3150 // 1. HSTS upgrade 3151 if (aShouldUpgrade || NS_FAILED(aStatus)) { 3152 resultCallback(aShouldUpgrade, aStatus); 3153 return; 3154 } 3155 // Check if we need to upgrade because of other reasons. 3156 // 2. CSP upgrade-insecure-requests 3157 // 3. Mixed content auto upgrading 3158 // 4. Https-Only / first 3159 bool shouldUpgrade = ShouldSecureUpgradeNoHSTS(uri, loadInfo); 3160 resultCallback(shouldUpgrade, aStatus); 3161 }; 3162 nsCOMPtr<nsISiteSecurityService> service = sss; 3163 nsresult rv = gSocketTransportService->Dispatch( 3164 NS_NewRunnableFunction( 3165 "net::NS_ShouldSecureUpgrade", 3166 [service{std::move(service)}, uri{std::move(uri)}, 3167 originAttributes(aOriginAttributes), 3168 handleResultFunc{std::move(handleResultFunc)}, 3169 callbackWrapper{std::move(callbackWrapper)}, 3170 allowSTS{std::move(aAllowSTS)}]() mutable { 3171 bool isStsHost = false; 3172 nsresult rv = 3173 service->IsSecureURI(uri, originAttributes, &isStsHost); 3174 3175 // Successfully get the result from |IsSecureURI| implies that 3176 // the storage is ready to read. 3177 storageReady = NS_SUCCEEDED(rv); 3178 bool shouldUpgrade = handleResultFunc(allowSTS, isStsHost); 3179 // Check if request should be upgraded. 3180 NS_DispatchToMainThread(NS_NewRunnableFunction( 3181 "net::NS_ShouldSecureUpgrade::ResultCallback", 3182 [rv, shouldUpgrade, 3183 callbackWrapper{std::move(callbackWrapper)}]() { 3184 callbackWrapper(shouldUpgrade, rv); 3185 })); 3186 }), 3187 NS_DISPATCH_NORMAL); 3188 aWillCallback = NS_SUCCEEDED(rv); 3189 return rv; 3190 } 3191 3192 nsresult rv = sss->IsSecureURI(aURI, aOriginAttributes, &isStsHost); 3193 3194 // if the SSS check fails, it's likely because this load is on a 3195 // malformed URI or something else in the setup is wrong, so any error 3196 // should be reported. 3197 NS_ENSURE_SUCCESS(rv, rv); 3198 3199 aShouldUpgrade = handleResultFunc(aAllowSTS, isStsHost); 3200 // we can't pass the loadinfo to handleResultFunc since it's not threadsafe 3201 // hence we set the http telemetry information on the loadinfo here. 3202 if (aShouldUpgrade) { 3203 aLoadInfo->SetHttpsUpgradeTelemetry(nsILoadInfo::HSTS); 3204 } 3205 if (!aShouldUpgrade) { 3206 // Check for CSP upgrade-insecure-requests, Mixed content auto upgrading 3207 // and Https-Only / -First. 3208 aShouldUpgrade = ShouldSecureUpgradeNoHSTS(aURI, aLoadInfo); 3209 } 3210 return rv; 3211 } 3212 3213 nsresult NS_GetSecureUpgradedURI(nsIURI* aURI, nsIURI** aUpgradedURI) { 3214 NS_MutateURI mutator(aURI); 3215 mutator.SetScheme("https"_ns); // Change the scheme to HTTPS: 3216 3217 // Change the default port to 443: 3218 nsCOMPtr<nsIStandardURL> stdURL = do_QueryInterface(aURI); 3219 if (stdURL) { 3220 mutator.Apply(&nsIStandardURLMutator::SetDefaultPort, 443, nullptr); 3221 } else { 3222 // If we don't have a nsStandardURL, fall back to using GetPort/SetPort. 3223 // XXXdholbert Is this function even called with a non-nsStandardURL arg, 3224 // in practice? 3225 NS_WARNING("Calling NS_GetSecureUpgradedURI for non nsStandardURL"); 3226 int32_t oldPort = -1; 3227 nsresult rv = aURI->GetPort(&oldPort); 3228 if (NS_FAILED(rv)) return rv; 3229 3230 // Keep any nonstandard ports so only the scheme is changed. 3231 // For example: 3232 // http://foo.com:80 -> https://foo.com:443 3233 // http://foo.com:81 -> https://foo.com:81 3234 3235 if (oldPort == 80 || oldPort == -1) { 3236 mutator.SetPort(-1); 3237 } else { 3238 mutator.SetPort(oldPort); 3239 } 3240 } 3241 3242 return mutator.Finalize(aUpgradedURI); 3243 } 3244 3245 nsresult NS_CompareLoadInfoAndLoadContext(nsIChannel* aChannel) { 3246 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); 3247 3248 nsCOMPtr<nsILoadContext> loadContext; 3249 NS_QueryNotificationCallbacks(aChannel, loadContext); 3250 if (!loadContext) { 3251 return NS_OK; 3252 } 3253 3254 // We try to skip about:newtab. 3255 // about:newtab will use SystemPrincipal to download thumbnails through 3256 // https:// and blob URLs. 3257 bool isAboutPage = false; 3258 nsINode* node = loadInfo->LoadingNode(); 3259 if (node) { 3260 nsIURI* uri = node->OwnerDoc()->GetDocumentURI(); 3261 isAboutPage = uri->SchemeIs("about"); 3262 } 3263 3264 if (isAboutPage) { 3265 return NS_OK; 3266 } 3267 3268 // We skip the favicon loading here. The favicon loading might be 3269 // triggered by the XUL image. For that case, the loadContext will have 3270 // default originAttributes since the XUL image uses SystemPrincipal, but 3271 // the loadInfo will use originAttributes from the content. Thus, the 3272 // originAttributes between loadInfo and loadContext will be different. 3273 // That's why we have to skip the comparison for the favicon loading. 3274 if (loadInfo->GetLoadingPrincipal() && 3275 loadInfo->GetLoadingPrincipal()->IsSystemPrincipal() && 3276 loadInfo->InternalContentPolicyType() == 3277 nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) { 3278 return NS_OK; 3279 } 3280 3281 OriginAttributes originAttrsLoadInfo = loadInfo->GetOriginAttributes(); 3282 OriginAttributes originAttrsLoadContext; 3283 loadContext->GetOriginAttributes(originAttrsLoadContext); 3284 3285 LOG( 3286 ("NS_CompareLoadInfoAndLoadContext - loadInfo: %d, %d; " 3287 "loadContext: %d, %d. [channel=%p]", 3288 originAttrsLoadInfo.mUserContextId, 3289 originAttrsLoadInfo.mPrivateBrowsingId, 3290 originAttrsLoadContext.mUserContextId, 3291 originAttrsLoadContext.mPrivateBrowsingId, aChannel)); 3292 3293 MOZ_ASSERT(originAttrsLoadInfo.mUserContextId == 3294 originAttrsLoadContext.mUserContextId, 3295 "The value of mUserContextId in the loadContext and in the " 3296 "loadInfo are not the same!"); 3297 3298 MOZ_ASSERT(originAttrsLoadInfo.mPrivateBrowsingId == 3299 originAttrsLoadContext.mPrivateBrowsingId, 3300 "The value of mPrivateBrowsingId in the loadContext and in the " 3301 "loadInfo are not the same!"); 3302 3303 return NS_OK; 3304 } 3305 3306 nsresult NS_SetRequestBlockingReason(nsIChannel* channel, uint32_t reason) { 3307 NS_ENSURE_ARG(channel); 3308 3309 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo(); 3310 return NS_SetRequestBlockingReason(loadInfo, reason); 3311 } 3312 3313 nsresult NS_SetRequestBlockingReason(nsILoadInfo* loadInfo, uint32_t reason) { 3314 NS_ENSURE_ARG(loadInfo); 3315 3316 return loadInfo->SetRequestBlockingReason(reason); 3317 } 3318 3319 nsresult NS_SetRequestBlockingReasonIfNull(nsILoadInfo* loadInfo, 3320 uint32_t reason) { 3321 NS_ENSURE_ARG(loadInfo); 3322 3323 uint32_t existingReason; 3324 if (NS_SUCCEEDED(loadInfo->GetRequestBlockingReason(&existingReason)) && 3325 existingReason != nsILoadInfo::BLOCKING_REASON_NONE) { 3326 return NS_OK; 3327 } 3328 3329 return loadInfo->SetRequestBlockingReason(reason); 3330 } 3331 3332 bool NS_IsOffline() { 3333 bool offline = true; 3334 bool connectivity = true; 3335 nsCOMPtr<nsIIOService> ios = do_GetIOService(); 3336 if (ios) { 3337 ios->GetOffline(&offline); 3338 ios->GetConnectivity(&connectivity); 3339 } 3340 return offline || !connectivity; 3341 } 3342 3343 /** 3344 * This function returns true if this channel should be classified by 3345 * the URL Classifier, false otherwise. There are two types of classification: 3346 * 1. SafeBrowsing 3347 * 2. Enhanced Tracking Protection (ETP) 3348 * 3349 * The idea of the algorithm to determine if a channel should be 3350 * classified is based on: 3351 * 1. Channels created by non-privileged code should be classified for 3352 * ETP. For SafeBrowsing, it depends on the pref 3353 * "browser.safebrowsing.only_top_level" to decide if it should be 3354 * classified. 3355 * 2. Top-level document’s channels, if loaded by privileged code 3356 * (system principal), should be classified for both types. 3357 * 3. Any other channel, created by privileged code, is considered safe. 3358 * 3359 * A bad/hacked/corrupted safebrowsing database, plus a mistakenly 3360 * classified critical channel (this may result from a bug in the exemption 3361 * rules or incorrect information being passed into) can cause serious 3362 * problems. For example, if the updater channel is classified and blocked 3363 * by the Safe Browsing, Firefox can't update itself, and there is no way to 3364 * recover from that. 3365 * 3366 * So two safeguards are added to ensure critical channels are never 3367 * automatically classified either because there is a bug in the algorithm 3368 * or the data in loadinfo is wrong. 3369 * 1. beConservative, this is set by ServiceRequest and we treat 3370 * channel created for ServiceRequest as critical channels. 3371 * 2. nsIChannel::LOAD_BYPASS_URL_CLASSIFIER, channel's opener can use this 3372 * flag to enforce bypassing the URL classifier check. 3373 */ 3374 bool NS_ShouldClassifyChannel(nsIChannel* aChannel, ClassifyType aType) { 3375 auto pref = 3376 static_cast<ClassifierMode>(StaticPrefs::urlclassifier_enabled_mode()); 3377 if (pref == ClassifierMode::Disabled) { 3378 return false; 3379 } 3380 if (aType == ClassifyType::SafeBrowsing && 3381 pref == ClassifierMode::AntiTracking) { 3382 return false; 3383 } 3384 if (aType == ClassifyType::ETP && pref == ClassifierMode::SafeBrowsing) { 3385 return false; 3386 } 3387 3388 nsLoadFlags loadFlags; 3389 (void)aChannel->GetLoadFlags(&loadFlags); 3390 // If our load flags dictate that we must let this channel through without 3391 // URL classification, obey that here without performing more checks. 3392 if (loadFlags & nsIChannel::LOAD_BYPASS_URL_CLASSIFIER) { 3393 return false; 3394 } 3395 3396 nsCOMPtr<nsIHttpChannelInternal> httpChannel(do_QueryInterface(aChannel)); 3397 if (httpChannel) { 3398 bool beConservative; 3399 nsresult rv = httpChannel->GetBeConservative(&beConservative); 3400 3401 // beConservative flag, set by ServiceRequest to ensure channels that 3402 // fetch update use conservative TLS setting, are used here to identify 3403 // channels are critical to bypass classification. for channels don't 3404 // support beConservative, continue to apply the exemption rules. 3405 if (NS_SUCCEEDED(rv) && beConservative) { 3406 return false; 3407 } 3408 } 3409 3410 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); 3411 ExtContentPolicyType type = loadInfo->GetExternalContentPolicyType(); 3412 3413 // Skip classifying channel for safe browsing unless it is a top-level. 3414 if (aType == ClassifyType::SafeBrowsing && 3415 (StaticPrefs::browser_safebrowsing_only_top_level() && 3416 ExtContentPolicy::TYPE_DOCUMENT != type)) { 3417 return false; 3418 } 3419 3420 // Skip classifying channel triggered by system unless it is a top-level 3421 // load. 3422 return !(loadInfo->TriggeringPrincipal()->IsSystemPrincipal() && 3423 ExtContentPolicy::TYPE_DOCUMENT != type); 3424 } 3425 3426 namespace mozilla { 3427 namespace net { 3428 3429 bool InScriptableRange(int64_t val) { 3430 return (val <= kJS_MAX_SAFE_INTEGER) && (val >= kJS_MIN_SAFE_INTEGER); 3431 } 3432 3433 bool InScriptableRange(uint64_t val) { return val <= kJS_MAX_SAFE_UINTEGER; } 3434 3435 nsresult GetParameterHTTP(const nsACString& aHeaderVal, const char* aParamName, 3436 nsAString& aResult) { 3437 return nsMIMEHeaderParamImpl::GetParameterHTTP(aHeaderVal, aParamName, 3438 aResult); 3439 } 3440 3441 bool ChannelIsPost(nsIChannel* aChannel) { 3442 if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) { 3443 nsAutoCString method; 3444 (void)httpChannel->GetRequestMethod(method); 3445 return method.EqualsLiteral("POST"); 3446 } 3447 return false; 3448 } 3449 3450 bool SchemeIsHttpOrHttps(nsIURI* aURI) { 3451 MOZ_ASSERT(aURI); 3452 return aURI->SchemeIs("http") || aURI->SchemeIs("https"); 3453 } 3454 3455 bool SchemeIsSpecial(const nsACString& aScheme) { 3456 // See https://url.spec.whatwg.org/#special-scheme 3457 return aScheme.EqualsIgnoreCase("ftp") || aScheme.EqualsIgnoreCase("file") || 3458 aScheme.EqualsIgnoreCase("http") || 3459 aScheme.EqualsIgnoreCase("https") || aScheme.EqualsIgnoreCase("ws") || 3460 aScheme.EqualsIgnoreCase("wss"); 3461 } 3462 3463 bool IsSchemeChangePermitted(nsIURI* aOldURI, const nsACString& newScheme) { 3464 // See step 2.1 in https://url.spec.whatwg.org/#special-scheme 3465 // Note: The spec text uses "buffer" instead of newScheme, and "url" 3466 MOZ_ASSERT(aOldURI); 3467 3468 nsAutoCString tmp; 3469 nsresult rv = aOldURI->GetScheme(tmp); 3470 // If url's scheme is a special scheme and buffer is not a 3471 // special scheme, then return. 3472 // If url's scheme is not a special scheme and buffer is a 3473 // special scheme, then return. 3474 if (NS_FAILED(rv) || SchemeIsSpecial(tmp) != SchemeIsSpecial(newScheme)) { 3475 return false; 3476 } 3477 3478 // If url's scheme is "file" and its host is an empty host, then return. 3479 if (aOldURI->SchemeIs("file")) { 3480 rv = aOldURI->GetHost(tmp); 3481 if (NS_FAILED(rv) || tmp.IsEmpty()) { 3482 return false; 3483 } 3484 } 3485 3486 // URL Spec: If url includes credentials or has a non-null port, and 3487 // buffer is "file", then return. 3488 if (newScheme.EqualsIgnoreCase("file")) { 3489 bool hasUserPass; 3490 if (NS_FAILED(aOldURI->GetHasUserPass(&hasUserPass)) || hasUserPass) { 3491 return false; 3492 } 3493 int32_t port; 3494 rv = aOldURI->GetPort(&port); 3495 if (NS_FAILED(rv) || port != -1) { 3496 return false; 3497 } 3498 } 3499 3500 return true; 3501 } 3502 3503 already_AddRefed<nsIURI> TryChangeProtocol(nsIURI* aURI, 3504 const nsACString& aProtocol) { 3505 MOZ_ASSERT(aURI); 3506 3507 nsACString::const_iterator start; 3508 aProtocol.BeginReading(start); 3509 3510 nsACString::const_iterator end; 3511 aProtocol.EndReading(end); 3512 3513 nsACString::const_iterator iter(start); 3514 FindCharInReadable(':', iter, end); 3515 3516 // Changing the protocol of a URL, changes the "nature" of the URI 3517 // implementation. In order to do this properly, we have to serialize the 3518 // existing URL and reparse it in a new object. 3519 nsCOMPtr<nsIURI> clone; 3520 nsresult rv = 3521 NS_MutateURI(aURI).SetScheme(Substring(start, iter)).Finalize(clone); 3522 if (NS_WARN_IF(NS_FAILED(rv))) { 3523 return nullptr; 3524 } 3525 3526 nsAutoCString newScheme; 3527 rv = clone->GetScheme(newScheme); 3528 if (NS_FAILED(rv) || !net::IsSchemeChangePermitted(aURI, newScheme)) { 3529 nsAutoCString url; 3530 (void)clone->GetSpec(url); 3531 AutoTArray<nsString, 2> params; 3532 params.AppendElement(NS_ConvertUTF8toUTF16(url)); 3533 params.AppendElement(NS_ConvertUTF8toUTF16(newScheme)); 3534 nsContentUtils::ReportToConsole( 3535 nsIScriptError::warningFlag, "Strict Url Protocol Setter"_ns, nullptr, 3536 nsContentUtils::eNECKO_PROPERTIES, "StrictUrlProtocolSetter", params); 3537 return nullptr; 3538 } 3539 3540 nsAutoCString href; 3541 rv = clone->GetSpec(href); 3542 if (NS_WARN_IF(NS_FAILED(rv))) { 3543 return nullptr; 3544 } 3545 3546 RefPtr<nsIURI> uri; 3547 rv = NS_NewURI(getter_AddRefs(uri), href); 3548 if (NS_WARN_IF(NS_FAILED(rv))) { 3549 return nullptr; 3550 } 3551 return uri.forget(); 3552 } 3553 3554 // Decode a parameter value using the encoding defined in RFC 5987 (in place) 3555 // 3556 // charset "'" [ language ] "'" value-chars 3557 // 3558 // returns true when decoding happened successfully (otherwise leaves 3559 // passed value alone) 3560 static bool Decode5987Format(nsAString& aEncoded) { 3561 nsresult rv; 3562 nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar; 3563 mimehdrpar = mozilla::components::MimeHeaderParam::Service(&rv); 3564 if (NS_FAILED(rv)) return false; 3565 3566 nsAutoCString asciiValue; 3567 3568 const char16_t* encstart = aEncoded.BeginReading(); 3569 const char16_t* encend = aEncoded.EndReading(); 3570 3571 // create a plain ASCII string, aborting if we can't do that 3572 // converted form is always shorter than input 3573 while (encstart != encend) { 3574 if (*encstart > 0 && *encstart < 128) { 3575 asciiValue.Append((char)*encstart); 3576 } else { 3577 return false; 3578 } 3579 encstart++; 3580 } 3581 3582 nsAutoString decoded; 3583 nsAutoCString language; 3584 3585 rv = mimehdrpar->DecodeRFC5987Param(asciiValue, language, decoded); 3586 if (NS_FAILED(rv)) return false; 3587 3588 aEncoded = decoded; 3589 return true; 3590 } 3591 3592 LinkHeader::LinkHeader() { mCrossOrigin.SetIsVoid(true); } 3593 3594 void LinkHeader::Reset() { 3595 mHref.Truncate(); 3596 mRel.Truncate(); 3597 mTitle.Truncate(); 3598 mNonce.Truncate(); 3599 mIntegrity.Truncate(); 3600 mSrcset.Truncate(); 3601 mSizes.Truncate(); 3602 mType.Truncate(); 3603 mMedia.Truncate(); 3604 mAnchor.Truncate(); 3605 mCrossOrigin.Truncate(); 3606 mReferrerPolicy.Truncate(); 3607 mAs.Truncate(); 3608 mCrossOrigin.SetIsVoid(true); 3609 mFetchPriority.Truncate(); 3610 } 3611 3612 nsresult LinkHeader::NewResolveHref(nsIURI** aOutURI, nsIURI* aBaseURI) const { 3613 if (mAnchor.IsEmpty()) { 3614 // use the base uri 3615 return NS_NewURI(aOutURI, mHref, nullptr, aBaseURI); 3616 } 3617 3618 // compute the anchored URI 3619 nsCOMPtr<nsIURI> anchoredURI; 3620 nsresult rv = 3621 NS_NewURI(getter_AddRefs(anchoredURI), mAnchor, nullptr, aBaseURI); 3622 NS_ENSURE_SUCCESS(rv, rv); 3623 3624 return NS_NewURI(aOutURI, mHref, nullptr, anchoredURI); 3625 } 3626 3627 bool LinkHeader::operator==(const LinkHeader& rhs) const { 3628 return mHref == rhs.mHref && mRel == rhs.mRel && mTitle == rhs.mTitle && 3629 mNonce == rhs.mNonce && mIntegrity == rhs.mIntegrity && 3630 mSrcset == rhs.mSrcset && mSizes == rhs.mSizes && mType == rhs.mType && 3631 mMedia == rhs.mMedia && mAnchor == rhs.mAnchor && 3632 mCrossOrigin == rhs.mCrossOrigin && 3633 mReferrerPolicy == rhs.mReferrerPolicy && mAs == rhs.mAs && 3634 mFetchPriority == rhs.mFetchPriority; 3635 } 3636 3637 constexpr auto kTitleStar = "title*"_ns; 3638 3639 nsTArray<LinkHeader> ParseLinkHeader(const nsAString& aLinkData) { 3640 nsTArray<LinkHeader> linkHeaders; 3641 3642 // keep track where we are within the header field 3643 bool seenParameters = false; 3644 3645 // parse link content and add to array 3646 LinkHeader header; 3647 nsAutoString titleStar; 3648 3649 // copy to work buffer 3650 nsAutoString stringList(aLinkData); 3651 3652 // put an extra null at the end 3653 stringList.Append(kNullCh); 3654 3655 char16_t* start = stringList.BeginWriting(); 3656 3657 while (*start != kNullCh) { 3658 // parse link content and call process style link 3659 3660 // skip leading space 3661 while ((*start != kNullCh) && nsCRT::IsAsciiSpace(*start)) { 3662 ++start; 3663 } 3664 3665 char16_t* end = start; 3666 char16_t* last = end - 1; 3667 3668 bool wasQuotedString = false; 3669 3670 // look for semicolon or comma 3671 while (*end != kNullCh && *end != kSemicolon && *end != kComma) { 3672 char16_t ch = *end; 3673 3674 if (ch == kQuote || ch == kLessThan) { 3675 // quoted string 3676 3677 char16_t quote = ch; 3678 if (quote == kLessThan) { 3679 quote = kGreaterThan; 3680 } 3681 3682 wasQuotedString = (ch == kQuote); 3683 3684 char16_t* closeQuote = (end + 1); 3685 3686 // seek closing quote 3687 while (*closeQuote != kNullCh && quote != *closeQuote) { 3688 // in quoted-string, "\" is an escape character 3689 if (wasQuotedString && *closeQuote == kBackSlash && 3690 *(closeQuote + 1) != kNullCh) { 3691 ++closeQuote; 3692 } 3693 3694 ++closeQuote; 3695 } 3696 3697 if (quote == *closeQuote) { 3698 // found closer 3699 3700 // skip to close quote 3701 end = closeQuote; 3702 3703 last = end - 1; 3704 3705 ch = *(end + 1); 3706 3707 if (ch != kNullCh && ch != kSemicolon && ch != kComma) { 3708 // end string here 3709 *(++end) = kNullCh; 3710 3711 ch = *(end + 1); 3712 3713 // keep going until semi or comma 3714 while (ch != kNullCh && ch != kSemicolon && ch != kComma) { 3715 ++end; 3716 3717 ch = *(end + 1); 3718 } 3719 } 3720 } 3721 } 3722 3723 ++end; 3724 ++last; 3725 } 3726 3727 char16_t endCh = *end; 3728 3729 // end string here 3730 *end = kNullCh; 3731 3732 if (start < end) { 3733 if ((*start == kLessThan) && (*last == kGreaterThan)) { 3734 *last = kNullCh; 3735 3736 // first instance of <...> wins 3737 // also, do not allow hrefs after the first param was seen 3738 if (header.mHref.IsEmpty() && !seenParameters) { 3739 header.mHref = (start + 1); 3740 header.mHref.StripWhitespace(); 3741 } 3742 } else { 3743 char16_t* equals = start; 3744 seenParameters = true; 3745 3746 while ((*equals != kNullCh) && (*equals != kEqual)) { 3747 equals++; 3748 } 3749 3750 const bool hadEquals = *equals != kNullCh; 3751 *equals = kNullCh; 3752 nsAutoString attr(start); 3753 attr.StripWhitespace(); 3754 3755 char16_t* value = hadEquals ? ++equals : equals; 3756 while (nsCRT::IsAsciiSpace(*value)) { 3757 value++; 3758 } 3759 3760 if ((*value == kQuote) && (*value == *last)) { 3761 *last = kNullCh; 3762 value++; 3763 } 3764 3765 if (wasQuotedString) { 3766 // unescape in-place 3767 char16_t* unescaped = value; 3768 char16_t* src = value; 3769 3770 while (*src != kNullCh) { 3771 if (*src == kBackSlash && *(src + 1) != kNullCh) { 3772 src++; 3773 } 3774 *unescaped++ = *src++; 3775 } 3776 3777 *unescaped = kNullCh; 3778 } 3779 3780 if (attr.LowerCaseEqualsASCII(kTitleStar.get())) { 3781 if (titleStar.IsEmpty() && !wasQuotedString) { 3782 // RFC 5987 encoding; uses token format only, so skip if we get 3783 // here with a quoted-string 3784 nsAutoString tmp; 3785 tmp = value; 3786 if (Decode5987Format(tmp)) { 3787 titleStar = tmp; 3788 titleStar.CompressWhitespace(); 3789 } else { 3790 // header value did not parse, throw it away 3791 titleStar.Truncate(); 3792 } 3793 } 3794 } else { 3795 header.MaybeUpdateAttribute(attr, value); 3796 } 3797 } 3798 } 3799 3800 if (endCh == kComma) { 3801 // hit a comma, process what we've got so far 3802 3803 header.mHref.Trim(" \t\n\r\f"); // trim HTML5 whitespace 3804 if (!header.mHref.IsEmpty() && !header.mRel.IsEmpty()) { 3805 if (!titleStar.IsEmpty()) { 3806 // prefer RFC 5987 variant over non-I18zed version 3807 header.mTitle = titleStar; 3808 } 3809 linkHeaders.AppendElement(header); 3810 } 3811 3812 titleStar.Truncate(); 3813 header.Reset(); 3814 3815 seenParameters = false; 3816 } 3817 3818 start = ++end; 3819 } 3820 3821 header.mHref.Trim(" \t\n\r\f"); // trim HTML5 whitespace 3822 if (!header.mHref.IsEmpty() && !header.mRel.IsEmpty()) { 3823 if (!titleStar.IsEmpty()) { 3824 // prefer RFC 5987 variant over non-I18zed version 3825 header.mTitle = titleStar; 3826 } 3827 linkHeaders.AppendElement(header); 3828 } 3829 3830 return linkHeaders; 3831 } 3832 3833 void LinkHeader::MaybeUpdateAttribute(const nsAString& aAttribute, 3834 const char16_t* aValue) { 3835 MOZ_ASSERT(!aAttribute.LowerCaseEqualsASCII(kTitleStar.get())); 3836 3837 if (aAttribute.LowerCaseEqualsLiteral("rel")) { 3838 if (mRel.IsEmpty()) { 3839 mRel = aValue; 3840 mRel.CompressWhitespace(); 3841 } 3842 } else if (aAttribute.LowerCaseEqualsLiteral("title")) { 3843 if (mTitle.IsEmpty()) { 3844 mTitle = aValue; 3845 mTitle.CompressWhitespace(); 3846 } 3847 } else if (aAttribute.LowerCaseEqualsLiteral("type")) { 3848 if (mType.IsEmpty()) { 3849 mType = aValue; 3850 mType.StripWhitespace(); 3851 } 3852 } else if (aAttribute.LowerCaseEqualsLiteral("media")) { 3853 if (mMedia.IsEmpty()) { 3854 mMedia = aValue; 3855 3856 // The HTML5 spec is formulated in terms of the CSS3 spec, 3857 // which specifies that media queries are case insensitive. 3858 nsContentUtils::ASCIIToLower(mMedia); 3859 } 3860 } else if (aAttribute.LowerCaseEqualsLiteral("anchor")) { 3861 if (mAnchor.IsEmpty()) { 3862 mAnchor = aValue; 3863 mAnchor.StripWhitespace(); 3864 } 3865 } else if (aAttribute.LowerCaseEqualsLiteral("crossorigin")) { 3866 if (mCrossOrigin.IsVoid()) { 3867 mCrossOrigin.SetIsVoid(false); 3868 mCrossOrigin = aValue; 3869 mCrossOrigin.StripWhitespace(); 3870 } 3871 } else if (aAttribute.LowerCaseEqualsLiteral("as")) { 3872 if (mAs.IsEmpty()) { 3873 mAs = aValue; 3874 mAs.CompressWhitespace(); 3875 } 3876 } else if (aAttribute.LowerCaseEqualsLiteral("referrerpolicy")) { 3877 // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#referrer-policy-attribute 3878 // Specs says referrer policy attribute is an enumerated attribute, 3879 // case insensitive and includes the empty string 3880 // We will parse the aValue with AttributeReferrerPolicyFromString 3881 // later, which will handle parsing it as an enumerated attribute. 3882 if (mReferrerPolicy.IsEmpty()) { 3883 mReferrerPolicy = aValue; 3884 } 3885 3886 } else if (aAttribute.LowerCaseEqualsLiteral("nonce")) { 3887 if (mNonce.IsEmpty()) { 3888 mNonce = aValue; 3889 } 3890 } else if (aAttribute.LowerCaseEqualsLiteral("integrity")) { 3891 if (mIntegrity.IsEmpty()) { 3892 mIntegrity = aValue; 3893 } 3894 } else if (aAttribute.LowerCaseEqualsLiteral("imagesrcset")) { 3895 if (mSrcset.IsEmpty()) { 3896 mSrcset = aValue; 3897 } 3898 } else if (aAttribute.LowerCaseEqualsLiteral("imagesizes")) { 3899 if (mSizes.IsEmpty()) { 3900 mSizes = aValue; 3901 } 3902 } else if (aAttribute.LowerCaseEqualsLiteral("fetchpriority")) { 3903 if (mFetchPriority.IsEmpty()) { 3904 LOG(("Update fetchPriority to \"%s\"", 3905 NS_ConvertUTF16toUTF8(aValue).get())); 3906 mFetchPriority = aValue; 3907 } 3908 } 3909 } 3910 3911 // We will use official mime-types from: 3912 // https://www.iana.org/assignments/media-types/media-types.xhtml#font 3913 // We do not support old deprecated mime-types for preload feature. 3914 // (We currectly do not support font/collection) 3915 static uint32_t StyleLinkElementFontMimeTypesNum = 5; 3916 static const char* StyleLinkElementFontMimeTypes[] = { 3917 "font/otf", "font/sfnt", "font/ttf", "font/woff", "font/woff2"}; 3918 3919 bool IsFontMimeType(const nsAString& aType) { 3920 if (aType.IsEmpty()) { 3921 return true; 3922 } 3923 for (uint32_t i = 0; i < StyleLinkElementFontMimeTypesNum; i++) { 3924 if (aType.EqualsASCII(StyleLinkElementFontMimeTypes[i])) { 3925 return true; 3926 } 3927 } 3928 return false; 3929 } 3930 3931 static constexpr nsAttrValue::EnumTableEntry kAsAttributeTable[] = { 3932 {"", DESTINATION_INVALID}, {"audio", DESTINATION_AUDIO}, 3933 {"font", DESTINATION_FONT}, {"image", DESTINATION_IMAGE}, 3934 {"script", DESTINATION_SCRIPT}, {"style", DESTINATION_STYLE}, 3935 {"track", DESTINATION_TRACK}, {"video", DESTINATION_VIDEO}, 3936 {"fetch", DESTINATION_FETCH}, {"json", DESTINATION_JSON}, 3937 }; 3938 3939 void ParseAsValue(const nsAString& aValue, nsAttrValue& aResult) { 3940 DebugOnly<bool> success = 3941 aResult.ParseEnumValue(aValue, kAsAttributeTable, false, 3942 // default value is a empty string 3943 // if aValue is not a value we 3944 // understand 3945 &kAsAttributeTable[0]); 3946 MOZ_ASSERT(success); 3947 } 3948 3949 nsContentPolicyType AsValueToContentPolicy(const nsAttrValue& aValue) { 3950 switch (aValue.GetEnumValue()) { 3951 case DESTINATION_INVALID: 3952 return nsIContentPolicy::TYPE_INVALID; 3953 case DESTINATION_AUDIO: 3954 return nsIContentPolicy::TYPE_INTERNAL_AUDIO; 3955 case DESTINATION_TRACK: 3956 return nsIContentPolicy::TYPE_INTERNAL_TRACK; 3957 case DESTINATION_VIDEO: 3958 return nsIContentPolicy::TYPE_INTERNAL_VIDEO; 3959 case DESTINATION_FONT: 3960 return nsIContentPolicy::TYPE_FONT; 3961 case DESTINATION_IMAGE: 3962 return nsIContentPolicy::TYPE_IMAGE; 3963 case DESTINATION_SCRIPT: 3964 return nsIContentPolicy::TYPE_SCRIPT; 3965 case DESTINATION_STYLE: 3966 return nsIContentPolicy::TYPE_STYLESHEET; 3967 case DESTINATION_FETCH: 3968 return nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD; 3969 case DESTINATION_JSON: 3970 return nsIContentPolicy::TYPE_JSON; 3971 } 3972 return nsIContentPolicy::TYPE_INVALID; 3973 } 3974 3975 // TODO: implement this using nsAttrValue's destination enums when support for 3976 // the new destinations is added; see this diff for a possible start: 3977 // https://phabricator.services.mozilla.com/D172368?vs=705114&id=708720 3978 bool IsScriptLikeOrInvalid(const nsAString& aAs) { 3979 return !( 3980 aAs.LowerCaseEqualsASCII("fetch") || aAs.LowerCaseEqualsASCII("audio") || 3981 aAs.LowerCaseEqualsASCII("document") || 3982 aAs.LowerCaseEqualsASCII("embed") || aAs.LowerCaseEqualsASCII("font") || 3983 aAs.LowerCaseEqualsASCII("frame") || aAs.LowerCaseEqualsASCII("iframe") || 3984 aAs.LowerCaseEqualsASCII("image") || 3985 aAs.LowerCaseEqualsASCII("manifest") || 3986 aAs.LowerCaseEqualsASCII("object") || 3987 aAs.LowerCaseEqualsASCII("report") || aAs.LowerCaseEqualsASCII("style") || 3988 aAs.LowerCaseEqualsASCII("track") || aAs.LowerCaseEqualsASCII("video") || 3989 aAs.LowerCaseEqualsASCII("webidentity") || 3990 aAs.LowerCaseEqualsASCII("xslt") || aAs.LowerCaseEqualsASCII("json")); 3991 } 3992 3993 bool CheckPreloadAttrs(const nsAttrValue& aAs, const nsAString& aType, 3994 const nsAString& aMedia, 3995 mozilla::dom::Document* aDocument) { 3996 nsContentPolicyType policyType = AsValueToContentPolicy(aAs); 3997 if (policyType == nsIContentPolicy::TYPE_INVALID) { 3998 return false; 3999 } 4000 4001 // Check if media attribute is valid. 4002 if (!aMedia.IsEmpty()) { 4003 RefPtr<mozilla::dom::MediaList> mediaList = 4004 mozilla::dom::MediaList::Create(NS_ConvertUTF16toUTF8(aMedia)); 4005 if (!mediaList->Matches(*aDocument)) { 4006 return false; 4007 } 4008 } 4009 4010 if (aType.IsEmpty()) { 4011 return true; 4012 } 4013 4014 if (policyType == nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD) { 4015 return true; 4016 } 4017 4018 nsAutoString type(aType); 4019 ToLowerCase(type); 4020 if (policyType == nsIContentPolicy::TYPE_MEDIA) { 4021 if (aAs.GetEnumValue() == DESTINATION_TRACK) { 4022 return type.EqualsASCII("text/vtt"); 4023 } 4024 Maybe<MediaContainerType> mimeType = MakeMediaContainerType(aType); 4025 if (!mimeType) { 4026 return false; 4027 } 4028 DecoderDoctorDiagnostics diagnostics; 4029 CanPlayStatus status = 4030 DecoderTraits::CanHandleContainerType(*mimeType, &diagnostics); 4031 // Preload if this return CANPLAY_YES and CANPLAY_MAYBE. 4032 return status != CANPLAY_NO; 4033 } 4034 if (policyType == nsIContentPolicy::TYPE_FONT) { 4035 return IsFontMimeType(type); 4036 } 4037 if (policyType == nsIContentPolicy::TYPE_IMAGE) { 4038 return imgLoader::SupportImageWithMimeType( 4039 NS_ConvertUTF16toUTF8(type), AcceptedMimeTypes::IMAGES_AND_DOCUMENTS); 4040 } 4041 if (policyType == nsIContentPolicy::TYPE_SCRIPT) { 4042 return nsContentUtils::IsJavascriptMIMEType(type); 4043 } 4044 if (policyType == nsIContentPolicy::TYPE_STYLESHEET) { 4045 return type.EqualsASCII("text/css"); 4046 } 4047 if (policyType == nsIContentPolicy::TYPE_JSON) { 4048 return nsContentUtils::IsJsonMimeType(type); 4049 } 4050 return false; 4051 } 4052 4053 void WarnIgnoredPreload(const mozilla::dom::Document& aDoc, nsIURI& aURI) { 4054 AutoTArray<nsString, 1> params; 4055 { 4056 nsCString uri = nsContentUtils::TruncatedURLForDisplay(&aURI); 4057 AppendUTF8toUTF16(uri, *params.AppendElement()); 4058 } 4059 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns, &aDoc, 4060 nsContentUtils::eDOM_PROPERTIES, 4061 "PreloadIgnoredInvalidAttr", params); 4062 } 4063 4064 bool NS_ParseUseAsDictionary(const nsACString& aValue, nsACString& aMatch, 4065 nsACString& aMatchId, 4066 nsTArray<nsCString>& aMatchDestItems, 4067 nsACString& aType) { 4068 // Note: match= is required 4069 // Use-As-Dictionary = %s"match" / 4070 // %il"match-dest" / 4071 // %s"id" / 4072 // %t"type" ; case-sensitive 4073 4074 nsCOMPtr<nsISFVService> sfv = GetSFVService(); 4075 4076 nsCOMPtr<nsISFVDictionary> parsedHeader; 4077 nsresult rv; 4078 if (NS_FAILED( 4079 rv = sfv->ParseDictionary(aValue, getter_AddRefs(parsedHeader)))) { 4080 return false; 4081 } 4082 4083 nsCOMPtr<nsISFVItemOrInnerList> match; 4084 rv = parsedHeader->Get("match"_ns, getter_AddRefs(match)); 4085 if (NS_FAILED(rv)) { 4086 return false; // match is required, fail if not found 4087 } 4088 if (nsCOMPtr<nsISFVItem> listItem = do_QueryInterface(match)) { 4089 nsCOMPtr<nsISFVBareItem> value; 4090 rv = listItem->GetValue(getter_AddRefs(value)); 4091 if (NS_FAILED(rv)) { 4092 return false; 4093 } 4094 if (nsCOMPtr<nsISFVString> stringVal = do_QueryInterface(value)) { 4095 if (NS_FAILED(stringVal->GetValue(aMatch))) { 4096 return false; 4097 } 4098 if (aMatch.IsEmpty()) { 4099 return false; // match is required, fail if not found 4100 } 4101 } else { 4102 return false; 4103 } 4104 } else { 4105 return false; 4106 } 4107 4108 nsCOMPtr<nsISFVItemOrInnerList> matchdest; 4109 rv = parsedHeader->Get("match-dest"_ns, getter_AddRefs(matchdest)); 4110 if (NS_SUCCEEDED(rv)) { 4111 if (nsCOMPtr<nsISFVInnerList> innerList = do_QueryInterface(matchdest)) { 4112 // Extract the first entry of each inner list, which should contain the 4113 // endpoint's URL string 4114 nsTArray<RefPtr<nsISFVItem>> items; 4115 if (NS_FAILED(innerList->GetItems(items))) { 4116 return false; 4117 } 4118 // Don't check items.IsEmpty() because an empty list is valid 4119 4120 for (auto& item : items) { 4121 nsCOMPtr<nsISFVBareItem> value; 4122 if (NS_FAILED(item->GetValue(getter_AddRefs(value)))) { 4123 return false; 4124 } 4125 if (nsCOMPtr<nsISFVString> stringVal = do_QueryInterface(value)) { 4126 nsAutoCString string; 4127 if (NS_FAILED(stringVal->GetValue(string))) { 4128 return false; 4129 } 4130 aMatchDestItems.AppendElement(string); 4131 } else { 4132 return false; // match-dest is an inner list of strings 4133 } 4134 } 4135 } 4136 } 4137 4138 nsCOMPtr<nsISFVItemOrInnerList> matchid; 4139 rv = parsedHeader->Get("id"_ns, getter_AddRefs(matchid)); 4140 if (NS_SUCCEEDED(rv)) { 4141 if (nsCOMPtr<nsISFVItem> listItem = do_QueryInterface(matchid)) { 4142 nsCOMPtr<nsISFVBareItem> value; 4143 rv = listItem->GetValue(getter_AddRefs(value)); 4144 if (NS_FAILED(rv)) { 4145 return false; 4146 } 4147 if (nsCOMPtr<nsISFVString> stringVal = do_QueryInterface(value)) { 4148 if (NS_FAILED(stringVal->GetValue(aMatchId))) { 4149 return false; 4150 } 4151 } else { 4152 return false; 4153 } 4154 } else { 4155 return false; 4156 } 4157 } 4158 4159 nsCOMPtr<nsISFVItemOrInnerList> type; 4160 rv = parsedHeader->Get("type"_ns, getter_AddRefs(type)); 4161 if (NS_SUCCEEDED(rv)) { 4162 if (nsCOMPtr<nsISFVItem> listItem = do_QueryInterface(type)) { 4163 nsCOMPtr<nsISFVBareItem> value; 4164 rv = listItem->GetValue(getter_AddRefs(value)); 4165 if (NS_FAILED(rv)) { 4166 return false; 4167 } 4168 if (nsCOMPtr<nsISFVToken> tokenVal = do_QueryInterface(value)) { 4169 if (NS_FAILED(tokenVal->GetValue(aType))) { 4170 return false; 4171 } 4172 if (!aType.Equals("raw"_ns)) { 4173 return false; 4174 } 4175 } else { 4176 return false; 4177 } 4178 } else { 4179 return false; 4180 } 4181 } 4182 4183 return true; 4184 } 4185 4186 nsresult HasRootDomain(const nsACString& aInput, const nsACString& aHost, 4187 bool* aResult) { 4188 if (NS_WARN_IF(!aResult)) { 4189 return NS_ERROR_FAILURE; 4190 } 4191 4192 *aResult = false; 4193 4194 // If the strings are the same, we obviously have a match. 4195 if (aInput == aHost) { 4196 *aResult = true; 4197 return NS_OK; 4198 } 4199 4200 // If aHost is not found, we know we do not have it as a root domain. 4201 int32_t index = nsAutoCString(aInput).Find(aHost); 4202 if (index == kNotFound) { 4203 return NS_OK; 4204 } 4205 4206 // Otherwise, we have aHost as our root domain iff the index of aHost is 4207 // aHost.length subtracted from our length and (since we do not have an 4208 // exact match) the character before the index is a dot or slash. 4209 *aResult = index > 0 && (uint32_t)index == aInput.Length() - aHost.Length() && 4210 (aInput[index - 1] == '.' || aInput[index - 1] == '/'); 4211 return NS_OK; 4212 } 4213 4214 void CheckForBrokenChromeURL(nsILoadInfo* aLoadInfo, nsIURI* aURI) { 4215 if (!aURI) { 4216 return; 4217 } 4218 nsAutoCString scheme; 4219 aURI->GetScheme(scheme); 4220 if (!scheme.EqualsLiteral("chrome") && !scheme.EqualsLiteral("resource")) { 4221 return; 4222 } 4223 nsAutoCString host; 4224 aURI->GetHost(host); 4225 // Ignore test hits. 4226 if (host.EqualsLiteral("mochitests") || host.EqualsLiteral("reftest")) { 4227 return; 4228 } 4229 4230 nsAutoCString filePath; 4231 aURI->GetFilePath(filePath); 4232 // Fluent likes checking for files everywhere and expects failure. 4233 if (StringEndsWith(filePath, ".ftl"_ns)) { 4234 return; 4235 } 4236 4237 // Ignore fetches/xhrs, as they are frequently used in a way where 4238 // non-existence is OK (ie with fallbacks). This risks false negatives (ie 4239 // files that *should* be there but aren't) - which we accept for now. 4240 ExtContentPolicy policy = aLoadInfo 4241 ? aLoadInfo->GetExternalContentPolicyType() 4242 : ExtContentPolicy::TYPE_OTHER; 4243 if (policy == ExtContentPolicy::TYPE_FETCH || 4244 policy == ExtContentPolicy::TYPE_XMLHTTPREQUEST) { 4245 return; 4246 } 4247 4248 nsCString spec; 4249 aURI->GetSpec(spec); 4250 4251 #ifdef ANDROID 4252 // Various toolkit files use this and are shipped on android, but 4253 // info-pages.css and aboutLicense.css are not - bug 1808987 4254 if (StringEndsWith(spec, "info-pages.css"_ns) || 4255 StringEndsWith(spec, "aboutLicense.css"_ns) || 4256 // Error page CSS is also missing: bug 1810039 4257 StringEndsWith(spec, "aboutNetError.css"_ns) || 4258 StringEndsWith(spec, "aboutHttpsOnlyError.css"_ns) || 4259 StringEndsWith(spec, "error-pages.css"_ns) || 4260 // popup.css is used in a single mochitest: bug 1810577 4261 StringEndsWith(spec, "/popup.css"_ns) || 4262 // Used by an extension installation test - bug 1809650 4263 StringBeginsWith(spec, "resource://android/assets/web_extensions/"_ns)) { 4264 return; 4265 } 4266 #endif 4267 4268 // DTD files from gre may not exist when requested by tests. 4269 if (StringBeginsWith(spec, "resource://gre/res/dtd/"_ns)) { 4270 return; 4271 } 4272 4273 // The background task machinery allows the caller to specify a JSM on the 4274 // command line, which is then looked up in both app-specific and toolkit-wide 4275 // locations. 4276 if (spec.Find("backgroundtasks") != kNotFound) { 4277 return; 4278 } 4279 4280 if (xpc::IsInAutomation()) { 4281 #ifdef DEBUG 4282 if (NS_IsMainThread()) { 4283 nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect(); 4284 (void)xpc->DebugDumpJSStack(false, false, false); 4285 } 4286 #endif 4287 MOZ_CRASH_UNSAFE_PRINTF("Missing chrome or resource URLs: %s", spec.get()); 4288 } else { 4289 printf_stderr("Missing chrome or resource URL: %s\n", spec.get()); 4290 } 4291 } 4292 4293 bool IsCoepCredentiallessEnabled(bool aIsOriginTrialCoepCredentiallessEnabled) { 4294 return StaticPrefs:: 4295 browser_tabs_remote_coep_credentialless_DoNotUseDirectly() || 4296 aIsOriginTrialCoepCredentiallessEnabled; 4297 } 4298 4299 nsresult AddExtraHeaders(nsIHttpChannel* aHttpChannel, 4300 const nsACString& aExtraHeaders, 4301 bool aMerge /* = true */) { 4302 nsresult rv; 4303 nsAutoCString oneHeader; 4304 nsAutoCString headerName; 4305 nsAutoCString headerValue; 4306 int32_t crlf = 0; 4307 int32_t colon = 0; 4308 const char* kWhitespace = "\b\t\r\n "; 4309 nsAutoCString extraHeaders(aExtraHeaders); 4310 while (true) { 4311 crlf = extraHeaders.Find("\r\n"); 4312 if (crlf == -1) break; 4313 extraHeaders.Mid(oneHeader, 0, crlf); 4314 extraHeaders.Cut(0, crlf + 2); 4315 colon = oneHeader.Find(":"); 4316 if (colon == -1) break; // Should have a colon. 4317 oneHeader.Left(headerName, colon); 4318 colon++; 4319 oneHeader.Mid(headerValue, colon, oneHeader.Length() - colon); 4320 headerName.Trim(kWhitespace); 4321 headerValue.Trim(kWhitespace); 4322 // Add the header (merging if required). 4323 rv = aHttpChannel->SetRequestHeader(headerName, headerValue, aMerge); 4324 NS_ENSURE_SUCCESS(rv, rv); 4325 } 4326 return NS_OK; 4327 } 4328 4329 bool IsLocalHostAccess( 4330 const nsILoadInfo::IPAddressSpace aParentIPAddressSpace, 4331 const nsILoadInfo::IPAddressSpace aTargetIPAddressSpace) { 4332 // Determine if the request is moving to a more private address space 4333 // i.e. Public -> LocalHost 4334 // Private -> LocalHost 4335 4336 return ((aTargetIPAddressSpace == nsILoadInfo::IPAddressSpace::Local) && 4337 (aParentIPAddressSpace == nsILoadInfo::IPAddressSpace::Public || 4338 aParentIPAddressSpace == nsILoadInfo::IPAddressSpace::Private)); 4339 } 4340 4341 bool IsPrivateNetworkAccess( 4342 const nsILoadInfo::IPAddressSpace aParentIPAddressSpace, 4343 const nsILoadInfo::IPAddressSpace aTargetIPAddressSpace) { 4344 // Determine if the request is moving from public to private address space 4345 4346 return ((aTargetIPAddressSpace == nsILoadInfo::IPAddressSpace::Private) && 4347 (aParentIPAddressSpace == nsILoadInfo::IPAddressSpace::Public)); 4348 } 4349 4350 bool IsLocalOrPrivateNetworkAccess( 4351 const nsILoadInfo::IPAddressSpace aParentIPAddressSpace, 4352 const nsILoadInfo::IPAddressSpace aTargetIPAddressSpace) { 4353 // Determine if the request is moving to a more private address space 4354 // i.e. Public -> Private or Local 4355 // Private -> Local 4356 // Refer 4357 // https://wicg.github.io/private-network-access/#private-network-request-heading 4358 // for private network access 4359 // XXX (sunil) add link to LNA spec once it is published 4360 4361 return IsPrivateNetworkAccess(aParentIPAddressSpace, aTargetIPAddressSpace) || 4362 IsLocalHostAccess(aParentIPAddressSpace, aTargetIPAddressSpace); 4363 } 4364 4365 Result<ActivateStorageAccess, nsresult> ParseActivateStorageAccess( 4366 const nsACString& aActivateStorageAcess) { 4367 nsCOMPtr<nsISFVService> sfv = GetSFVService(); 4368 4369 // Parse storage acces values 4370 // * Activate-Storage-Access: load 4371 // * Activate-Storage-Access: retry; allowed-origin="https://foo.bar" 4372 // * Activate-Storage-Access: retry; allowed-origin=* 4373 // into ActivateStorageAccess struct. See ActivateStorageAccessVariant for 4374 // documentation on fields 4375 nsCOMPtr<nsISFVItem> parsedHeader; 4376 MOZ_TRY(sfv->ParseItem(aActivateStorageAcess, getter_AddRefs(parsedHeader))); 4377 4378 nsCOMPtr<nsISFVBareItem> value; 4379 MOZ_TRY(parsedHeader->GetValue(getter_AddRefs(value))); 4380 4381 nsCOMPtr<nsISFVToken> token = do_QueryInterface(value); 4382 if (!token) { 4383 return Err(NS_ERROR_FAILURE); 4384 } 4385 nsAutoCString tokenValue; 4386 token->GetValue(tokenValue); 4387 4388 if (tokenValue.EqualsLiteral("load")) { 4389 return ActivateStorageAccess{ 4390 ActivateStorageAccessVariant::Load, 4391 }; 4392 } 4393 if (!tokenValue.EqualsLiteral("retry")) { 4394 return Err(NS_ERROR_FAILURE); 4395 } 4396 nsCOMPtr<nsISFVParams> params; 4397 MOZ_TRY(parsedHeader->GetParams(getter_AddRefs(params))); 4398 4399 nsCOMPtr<nsISFVBareItem> item; 4400 MOZ_TRY(params->Get("allowed-origin"_ns, getter_AddRefs(item))); 4401 4402 // Evaluate whether the token value is a wildcard symbol. 4403 nsCOMPtr<nsISFVToken> itemToken = do_QueryInterface(item); 4404 if (itemToken) { 4405 itemToken->GetValue(tokenValue); 4406 if (!tokenValue.EqualsLiteral("*")) { 4407 return Err(NS_ERROR_FAILURE); 4408 } 4409 return ActivateStorageAccess{ 4410 ActivateStorageAccessVariant::RetryAny, 4411 }; 4412 } 4413 4414 // Evaluate whether the token value is an origin. 4415 nsCOMPtr<nsISFVString> itemString = do_QueryInterface(item); 4416 if (!itemString) { 4417 return Err(NS_ERROR_FAILURE); 4418 } 4419 ActivateStorageAccess result{ActivateStorageAccessVariant::RetryOrigin}; 4420 itemString->GetValue(result.origin); 4421 return result; 4422 } 4423 4424 } // namespace net 4425 } // namespace mozilla