nsBaseChannel.cpp (27874B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set sw=2 sts=2 ts=8 et tw=80 : */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "nsBaseChannel.h" 8 #include "nsContentUtils.h" 9 #include "nsURLHelper.h" 10 #include "nsNetCID.h" 11 #include "nsUnknownDecoder.h" 12 #include "nsIScriptSecurityManager.h" 13 #include "nsMimeTypes.h" 14 #include "nsICancelable.h" 15 #include "nsIChannelEventSink.h" 16 #include "nsIStreamConverterService.h" 17 #include "nsChannelClassifier.h" 18 #include "nsAsyncRedirectVerifyHelper.h" 19 #include "nsProxyRelease.h" 20 #include "nsXULAppAPI.h" 21 #include "nsContentSecurityManager.h" 22 #include "LoadInfo.h" 23 #include "nsServiceManagerUtils.h" 24 #include "nsRedirectHistoryEntry.h" 25 #include "mozilla/AntiTrackingUtils.h" 26 #include "mozilla/BasePrincipal.h" 27 28 using namespace mozilla; 29 30 // This class is used to suspend a request across a function scope. 31 class ScopedRequestSuspender { 32 public: 33 explicit ScopedRequestSuspender(nsIRequest* request) : mRequest(request) { 34 if (mRequest && NS_FAILED(mRequest->Suspend())) { 35 NS_WARNING("Couldn't suspend pump"); 36 mRequest = nullptr; 37 } 38 } 39 ~ScopedRequestSuspender() { 40 if (mRequest) mRequest->Resume(); 41 } 42 43 private: 44 nsIRequest* mRequest; 45 }; 46 47 // Used to suspend data events from mRequest within a function scope. This is 48 // usually needed when a function makes callbacks that could process events. 49 #define SUSPEND_PUMP_FOR_SCOPE() \ 50 ScopedRequestSuspender pump_suspender__(mRequest) 51 52 //----------------------------------------------------------------------------- 53 // nsBaseChannel 54 55 nsBaseChannel::nsBaseChannel() : NeckoTargetHolder(nullptr) { 56 mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE); 57 } 58 59 nsBaseChannel::~nsBaseChannel() { 60 NS_ReleaseOnMainThread("nsBaseChannel::mLoadInfo", mLoadInfo.forget()); 61 } 62 63 nsresult nsBaseChannel::Redirect(nsIChannel* newChannel, uint32_t redirectFlags, 64 bool openNewChannel) { 65 SUSPEND_PUMP_FOR_SCOPE(); 66 67 // Transfer properties 68 69 newChannel->SetLoadGroup(mLoadGroup); 70 newChannel->SetNotificationCallbacks(mCallbacks); 71 newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE); 72 73 // make a copy of the loadinfo, append to the redirectchain 74 // and set it on the new channel 75 nsSecurityFlags secFlags = 76 mLoadInfo->GetSecurityFlags() & ~nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; 77 nsCOMPtr<nsILoadInfo> newLoadInfo = 78 static_cast<net::LoadInfo*>(mLoadInfo.get()) 79 ->CloneWithNewSecFlags(secFlags); 80 81 bool isInternalRedirect = 82 (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL | 83 nsIChannelEventSink::REDIRECT_STS_UPGRADE)); 84 85 newLoadInfo->AppendRedirectHistoryEntry(this, isInternalRedirect); 86 87 // Ensure the channel's loadInfo's result principal URI so that it's 88 // either non-null or updated to the redirect target URI. 89 // We must do this because in case the loadInfo's result principal URI 90 // is null, it would be taken from OriginalURI of the channel. But we 91 // overwrite it with the whole redirect chain first URI before opening 92 // the target channel, hence the information would be lost. 93 // If the protocol handler that created the channel wants to use 94 // the originalURI of the channel as the principal URI, it has left 95 // the result principal URI on the load info null. 96 nsCOMPtr<nsIURI> resultPrincipalURI; 97 98 nsCOMPtr<nsILoadInfo> existingLoadInfo = newChannel->LoadInfo(); 99 if (existingLoadInfo) { 100 existingLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI)); 101 } 102 if (!resultPrincipalURI) { 103 newChannel->GetOriginalURI(getter_AddRefs(resultPrincipalURI)); 104 } 105 106 newLoadInfo->SetResultPrincipalURI(resultPrincipalURI); 107 108 newChannel->SetLoadInfo(newLoadInfo); 109 110 // Preserve the privacy bit if it has been overridden 111 if (mPrivateBrowsingOverriden) { 112 nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel = 113 do_QueryInterface(newChannel); 114 if (newPBChannel) { 115 newPBChannel->SetPrivate(mPrivateBrowsing); 116 } 117 } 118 119 if (nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel)) { 120 nsHashPropertyBag::CopyFrom(bag, static_cast<nsIPropertyBag2*>(this)); 121 } 122 123 // Notify consumer, giving chance to cancel redirect. 124 125 auto redirectCallbackHelper = MakeRefPtr<net::nsAsyncRedirectVerifyHelper>(); 126 127 bool checkRedirectSynchronously = !openNewChannel; 128 nsCOMPtr<nsIEventTarget> target = GetNeckoTarget(); 129 130 mRedirectChannel = newChannel; 131 mRedirectFlags = redirectFlags; 132 mOpenRedirectChannel = openNewChannel; 133 nsresult rv = redirectCallbackHelper->Init( 134 this, newChannel, redirectFlags, target, checkRedirectSynchronously); 135 if (NS_FAILED(rv)) return rv; 136 137 if (checkRedirectSynchronously && NS_FAILED(mStatus)) return mStatus; 138 139 return NS_OK; 140 } 141 142 nsresult nsBaseChannel::ContinueRedirect() { 143 // Make sure to do this _after_ making all the OnChannelRedirect calls 144 mRedirectChannel->SetOriginalURI(OriginalURI()); 145 146 // If we fail to open the new channel, then we want to leave this channel 147 // unaffected, so we defer tearing down our channel until we have succeeded 148 // with the redirect. 149 150 if (mOpenRedirectChannel) { 151 nsresult rv = NS_OK; 152 rv = mRedirectChannel->AsyncOpen(mListener); 153 NS_ENSURE_SUCCESS(rv, rv); 154 } 155 156 mRedirectChannel = nullptr; 157 158 // close down this channel 159 Cancel(NS_BINDING_REDIRECTED); 160 ChannelDone(); 161 162 return NS_OK; 163 } 164 165 bool nsBaseChannel::HasContentTypeHint() const { 166 NS_ASSERTION(!Pending(), "HasContentTypeHint called too late"); 167 return !mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE); 168 } 169 170 nsresult nsBaseChannel::BeginPumpingData() { 171 nsresult rv; 172 173 rv = BeginAsyncRead(this, getter_AddRefs(mRequest), 174 getter_AddRefs(mCancelableAsyncRequest)); 175 if (NS_SUCCEEDED(rv)) { 176 MOZ_ASSERT(mRequest || mCancelableAsyncRequest, 177 "should have got a request or cancelable"); 178 mPumpingData = true; 179 return NS_OK; 180 } 181 if (rv != NS_ERROR_NOT_IMPLEMENTED) { 182 return rv; 183 } 184 185 nsCOMPtr<nsIInputStream> stream; 186 nsCOMPtr<nsIChannel> channel; 187 rv = OpenContentStream(true, getter_AddRefs(stream), getter_AddRefs(channel)); 188 if (NS_FAILED(rv)) return rv; 189 190 NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?"); 191 192 if (channel) { 193 nsCOMPtr<nsIRunnable> runnable = new RedirectRunnable(this, channel); 194 rv = Dispatch(runnable.forget()); 195 if (NS_SUCCEEDED(rv)) mWaitingOnAsyncRedirect = true; 196 return rv; 197 } 198 199 // By assigning mPump, we flag this channel as pending (see Pending). It's 200 // important that the pending flag is set when we call into the stream (the 201 // call to AsyncRead results in the stream's AsyncWait method being called) 202 // and especially when we call into the loadgroup. Our caller takes care to 203 // release mPump if we return an error. 204 205 nsCOMPtr<nsISerialEventTarget> target = GetNeckoTarget(); 206 rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, 0, 0, true, 207 target); 208 if (NS_FAILED(rv)) { 209 return rv; 210 } 211 212 mPumpingData = true; 213 mRequest = mPump; 214 rv = mPump->AsyncRead(this); 215 if (NS_FAILED(rv)) { 216 return rv; 217 } 218 219 RefPtr<BlockingPromise> promise; 220 rv = ListenerBlockingPromise(getter_AddRefs(promise)); 221 if (NS_FAILED(rv)) { 222 return rv; 223 } 224 225 if (promise) { 226 mPump->Suspend(); 227 228 RefPtr<nsBaseChannel> self(this); 229 230 promise->Then( 231 target, __func__, 232 [self, this](nsresult rv) { 233 MOZ_ASSERT(mPump); 234 MOZ_ASSERT(NS_SUCCEEDED(rv)); 235 mPump->Resume(); 236 }, 237 [self, this](nsresult rv) { 238 MOZ_ASSERT(mPump); 239 MOZ_ASSERT(NS_FAILED(rv)); 240 Cancel(rv); 241 mPump->Resume(); 242 }); 243 } 244 245 return NS_OK; 246 } 247 248 void nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel) { 249 NS_ASSERTION(!mPumpingData, "Shouldn't have gotten here"); 250 251 nsresult rv = mStatus; 252 if (NS_SUCCEEDED(mStatus)) { 253 rv = Redirect(newChannel, nsIChannelEventSink::REDIRECT_TEMPORARY, true); 254 if (NS_SUCCEEDED(rv)) { 255 // OnRedirectVerifyCallback will be called asynchronously 256 return; 257 } 258 } 259 260 ContinueHandleAsyncRedirect(rv); 261 } 262 263 void nsBaseChannel::ContinueHandleAsyncRedirect(nsresult result) { 264 mWaitingOnAsyncRedirect = false; 265 266 if (NS_FAILED(result)) Cancel(result); 267 268 if (NS_FAILED(result) && mListener) { 269 // Notify our consumer ourselves 270 mListener->OnStartRequest(this); 271 mListener->OnStopRequest(this, mStatus); 272 ChannelDone(); 273 } 274 275 if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus); 276 277 // Drop notification callbacks to prevent cycles. 278 mCallbacks = nullptr; 279 CallbacksChanged(); 280 } 281 282 void nsBaseChannel::ClassifyURI() { 283 // For channels created in the child process, delegate to the parent to 284 // classify URIs. 285 if (!XRE_IsParentProcess()) { 286 return; 287 } 288 289 if (NS_ShouldClassifyChannel(this, ClassifyType::SafeBrowsing)) { 290 auto classifier = MakeRefPtr<net::nsChannelClassifier>(this); 291 classifier->Start(); 292 } 293 } 294 295 //----------------------------------------------------------------------------- 296 // nsBaseChannel::nsISupports 297 298 NS_IMPL_ADDREF(nsBaseChannel) 299 NS_IMPL_RELEASE(nsBaseChannel) 300 301 NS_INTERFACE_MAP_BEGIN(nsBaseChannel) 302 NS_INTERFACE_MAP_ENTRY(nsIRequest) 303 NS_INTERFACE_MAP_ENTRY(nsIChannel) 304 NS_INTERFACE_MAP_ENTRY(nsIBaseChannel) 305 NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest) 306 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) 307 NS_INTERFACE_MAP_ENTRY(nsITransportEventSink) 308 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) 309 NS_INTERFACE_MAP_ENTRY(nsIStreamListener) 310 NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableStreamListener) 311 NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback) 312 NS_INTERFACE_MAP_ENTRY(nsIPrivateBrowsingChannel) 313 NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag) 314 315 //----------------------------------------------------------------------------- 316 // nsBaseChannel::nsIRequest 317 318 NS_IMETHODIMP 319 nsBaseChannel::GetName(nsACString& result) { 320 if (!mURI) { 321 result.Truncate(); 322 return NS_OK; 323 } 324 return mURI->GetSpec(result); 325 } 326 327 NS_IMETHODIMP 328 nsBaseChannel::IsPending(bool* result) { 329 *result = Pending(); 330 return NS_OK; 331 } 332 333 NS_IMETHODIMP 334 nsBaseChannel::GetStatus(nsresult* status) { 335 if (mRequest && NS_SUCCEEDED(mStatus)) { 336 mRequest->GetStatus(status); 337 } else { 338 *status = mStatus; 339 } 340 return NS_OK; 341 } 342 343 NS_IMETHODIMP nsBaseChannel::SetCanceledReason(const nsACString& aReason) { 344 return SetCanceledReasonImpl(aReason); 345 } 346 347 NS_IMETHODIMP nsBaseChannel::GetCanceledReason(nsACString& aReason) { 348 return GetCanceledReasonImpl(aReason); 349 } 350 351 NS_IMETHODIMP nsBaseChannel::CancelWithReason(nsresult aStatus, 352 const nsACString& aReason) { 353 return CancelWithReasonImpl(aStatus, aReason); 354 } 355 356 NS_IMETHODIMP 357 nsBaseChannel::Cancel(nsresult status) { 358 // Ignore redundant cancelation 359 if (mCanceled) { 360 return NS_OK; 361 } 362 363 mCanceled = true; 364 mStatus = status; 365 366 if (mCancelableAsyncRequest) { 367 mCancelableAsyncRequest->Cancel(status); 368 } 369 370 if (mRequest) { 371 mRequest->Cancel(status); 372 } 373 374 return NS_OK; 375 } 376 377 NS_IMETHODIMP 378 nsBaseChannel::Suspend() { 379 NS_ENSURE_TRUE(mPumpingData, NS_ERROR_NOT_INITIALIZED); 380 NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_IMPLEMENTED); 381 return mRequest->Suspend(); 382 } 383 384 NS_IMETHODIMP 385 nsBaseChannel::Resume() { 386 NS_ENSURE_TRUE(mPumpingData, NS_ERROR_NOT_INITIALIZED); 387 NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_IMPLEMENTED); 388 return mRequest->Resume(); 389 } 390 391 NS_IMETHODIMP 392 nsBaseChannel::GetLoadFlags(nsLoadFlags* aLoadFlags) { 393 *aLoadFlags = mLoadFlags; 394 return NS_OK; 395 } 396 397 NS_IMETHODIMP 398 nsBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags) { 399 mLoadFlags = aLoadFlags; 400 return NS_OK; 401 } 402 403 NS_IMETHODIMP 404 nsBaseChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) { 405 return GetTRRModeImpl(aTRRMode); 406 } 407 408 NS_IMETHODIMP 409 nsBaseChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) { 410 return SetTRRModeImpl(aTRRMode); 411 } 412 413 NS_IMETHODIMP 414 nsBaseChannel::GetLoadGroup(nsILoadGroup** aLoadGroup) { 415 nsCOMPtr<nsILoadGroup> loadGroup(mLoadGroup); 416 loadGroup.forget(aLoadGroup); 417 return NS_OK; 418 } 419 420 NS_IMETHODIMP 421 nsBaseChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) { 422 if (!CanSetLoadGroup(aLoadGroup)) { 423 return NS_ERROR_FAILURE; 424 } 425 426 mLoadGroup = aLoadGroup; 427 CallbacksChanged(); 428 UpdatePrivateBrowsing(); 429 return NS_OK; 430 } 431 432 //----------------------------------------------------------------------------- 433 // nsBaseChannel::nsIChannel 434 435 NS_IMETHODIMP 436 nsBaseChannel::GetOriginalURI(nsIURI** aURI) { 437 RefPtr<nsIURI> uri = OriginalURI(); 438 uri.forget(aURI); 439 return NS_OK; 440 } 441 442 NS_IMETHODIMP 443 nsBaseChannel::SetOriginalURI(nsIURI* aURI) { 444 NS_ENSURE_ARG_POINTER(aURI); 445 mOriginalURI = aURI; 446 return NS_OK; 447 } 448 449 NS_IMETHODIMP 450 nsBaseChannel::GetURI(nsIURI** aURI) { 451 nsCOMPtr<nsIURI> uri(mURI); 452 uri.forget(aURI); 453 return NS_OK; 454 } 455 456 NS_IMETHODIMP 457 nsBaseChannel::GetOwner(nsISupports** aOwner) { 458 nsCOMPtr<nsISupports> owner(mOwner); 459 owner.forget(aOwner); 460 return NS_OK; 461 } 462 463 NS_IMETHODIMP 464 nsBaseChannel::SetOwner(nsISupports* aOwner) { 465 mOwner = aOwner; 466 return NS_OK; 467 } 468 469 NS_IMETHODIMP 470 nsBaseChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) { 471 MOZ_RELEASE_ASSERT(aLoadInfo, "loadinfo can't be null"); 472 mLoadInfo = aLoadInfo; 473 474 // Need to update |mNeckoTarget| when load info has changed. 475 SetupNeckoTarget(); 476 return NS_OK; 477 } 478 479 NS_IMETHODIMP 480 nsBaseChannel::GetLoadInfo(nsILoadInfo** aLoadInfo) { 481 nsCOMPtr<nsILoadInfo> loadInfo(mLoadInfo); 482 loadInfo.forget(aLoadInfo); 483 return NS_OK; 484 } 485 486 NS_IMETHODIMP 487 nsBaseChannel::GetIsDocument(bool* aIsDocument) { 488 return NS_GetIsDocumentChannel(this, aIsDocument); 489 } 490 491 NS_IMETHODIMP 492 nsBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks) { 493 nsCOMPtr<nsIInterfaceRequestor> callbacks(mCallbacks); 494 callbacks.forget(aCallbacks); 495 return NS_OK; 496 } 497 498 NS_IMETHODIMP 499 nsBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) { 500 if (!CanSetCallbacks(aCallbacks)) { 501 return NS_ERROR_FAILURE; 502 } 503 504 mCallbacks = aCallbacks; 505 CallbacksChanged(); 506 UpdatePrivateBrowsing(); 507 return NS_OK; 508 } 509 510 NS_IMETHODIMP 511 nsBaseChannel::GetSecurityInfo(nsITransportSecurityInfo** aSecurityInfo) { 512 *aSecurityInfo = do_AddRef(mSecurityInfo).take(); 513 return NS_OK; 514 } 515 516 NS_IMETHODIMP 517 nsBaseChannel::GetContentType(nsACString& aContentType) { 518 aContentType = mContentType; 519 return NS_OK; 520 } 521 522 NS_IMETHODIMP 523 nsBaseChannel::SetContentType(const nsACString& aContentType) { 524 // mContentCharset is unchanged if not parsed 525 bool dummy; 526 net_ParseContentType(aContentType, mContentType, mContentCharset, &dummy); 527 return NS_OK; 528 } 529 530 NS_IMETHODIMP 531 nsBaseChannel::GetContentCharset(nsACString& aContentCharset) { 532 aContentCharset = mContentCharset; 533 if (mContentCharset.IsEmpty() && (mOriginalURI->SchemeIs("chrome") || 534 mOriginalURI->SchemeIs("resource"))) { 535 aContentCharset.AssignLiteral("UTF-8"); 536 } 537 return NS_OK; 538 } 539 540 NS_IMETHODIMP 541 nsBaseChannel::SetContentCharset(const nsACString& aContentCharset) { 542 mContentCharset = aContentCharset; 543 return NS_OK; 544 } 545 546 NS_IMETHODIMP 547 nsBaseChannel::GetContentDisposition(uint32_t* aContentDisposition) { 548 // preserve old behavior, fail unless explicitly set. 549 if (mContentDispositionHint == UINT32_MAX) { 550 return NS_ERROR_NOT_AVAILABLE; 551 } 552 553 *aContentDisposition = mContentDispositionHint; 554 return NS_OK; 555 } 556 557 NS_IMETHODIMP 558 nsBaseChannel::SetContentDisposition(uint32_t aContentDisposition) { 559 mContentDispositionHint = aContentDisposition; 560 return NS_OK; 561 } 562 563 NS_IMETHODIMP 564 nsBaseChannel::GetContentDispositionFilename( 565 nsAString& aContentDispositionFilename) { 566 if (!mContentDispositionFilename) { 567 return NS_ERROR_NOT_AVAILABLE; 568 } 569 570 aContentDispositionFilename = *mContentDispositionFilename; 571 return NS_OK; 572 } 573 574 NS_IMETHODIMP 575 nsBaseChannel::SetContentDispositionFilename( 576 const nsAString& aContentDispositionFilename) { 577 mContentDispositionFilename = 578 MakeUnique<nsString>(aContentDispositionFilename); 579 580 // For safety reasons ensure the filename doesn't contain null characters and 581 // replace them with underscores. We may later pass the extension to system 582 // MIME APIs that expect null terminated strings. 583 mContentDispositionFilename->ReplaceChar(char16_t(0), '_'); 584 585 return NS_OK; 586 } 587 588 NS_IMETHODIMP 589 nsBaseChannel::GetContentDispositionHeader( 590 nsACString& aContentDispositionHeader) { 591 return NS_ERROR_NOT_AVAILABLE; 592 } 593 594 NS_IMETHODIMP 595 nsBaseChannel::GetContentLength(int64_t* aContentLength) { 596 *aContentLength = mContentLength; 597 return NS_OK; 598 } 599 600 NS_IMETHODIMP 601 nsBaseChannel::SetContentLength(int64_t aContentLength) { 602 mContentLength = aContentLength; 603 return NS_OK; 604 } 605 606 NS_IMETHODIMP 607 nsBaseChannel::Open(nsIInputStream** aStream) { 608 nsCOMPtr<nsIStreamListener> listener; 609 nsresult rv = 610 nsContentSecurityManager::doContentSecurityCheck(this, listener); 611 NS_ENSURE_SUCCESS(rv, rv); 612 613 NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED); 614 NS_ENSURE_TRUE(!mPumpingData, NS_ERROR_IN_PROGRESS); 615 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS); 616 617 nsCOMPtr<nsIChannel> chan; 618 rv = OpenContentStream(false, aStream, getter_AddRefs(chan)); 619 NS_ASSERTION(!chan || !*aStream, "Got both a channel and a stream?"); 620 if (NS_SUCCEEDED(rv) && chan) { 621 rv = Redirect(chan, nsIChannelEventSink::REDIRECT_INTERNAL, false); 622 if (NS_FAILED(rv)) return rv; 623 rv = chan->Open(aStream); 624 } else if (rv == NS_ERROR_NOT_IMPLEMENTED) { 625 return NS_ImplementChannelOpen(this, aStream); 626 } 627 628 if (NS_SUCCEEDED(rv)) { 629 mWasOpened = true; 630 ClassifyURI(); 631 } 632 633 return rv; 634 } 635 636 NS_IMETHODIMP 637 nsBaseChannel::AsyncOpen(nsIStreamListener* aListener) { 638 nsCOMPtr<nsIStreamListener> listener = aListener; 639 640 nsresult rv = 641 nsContentSecurityManager::doContentSecurityCheck(this, listener); 642 if (NS_FAILED(rv)) { 643 mCallbacks = nullptr; 644 return rv; 645 } 646 647 MOZ_ASSERT( 648 mLoadInfo->GetSecurityMode() == 0 || 649 mLoadInfo->GetInitialSecurityCheckDone() || 650 (mLoadInfo->GetSecurityMode() == 651 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL && 652 mLoadInfo->GetLoadingPrincipal() && 653 mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()), 654 "security flags in loadInfo but doContentSecurityCheck() not called"); 655 656 NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED); 657 NS_ENSURE_TRUE(!mPumpingData, NS_ERROR_IN_PROGRESS); 658 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); 659 NS_ENSURE_ARG(listener); 660 661 SetupNeckoTarget(); 662 663 // Skip checking for chrome:// sub-resources. 664 nsAutoCString scheme; 665 mURI->GetScheme(scheme); 666 if (!scheme.EqualsLiteral("file")) { 667 NS_CompareLoadInfoAndLoadContext(this); 668 } 669 670 // Ensure that this is an allowed port before proceeding. 671 rv = NS_CheckPortSafety(mURI); 672 if (NS_FAILED(rv)) { 673 mCallbacks = nullptr; 674 return rv; 675 } 676 677 AntiTrackingUtils::UpdateAntiTrackingInfoForChannel(this); 678 679 // Store the listener and context early so that OpenContentStream and the 680 // stream's AsyncWait method (called by AsyncRead) can have access to them 681 // via the StreamListener methods. However, since 682 // this typically introduces a reference cycle between this and the listener, 683 // we need to be sure to break the reference if this method does not succeed. 684 mListener = listener; 685 686 // This method assigns mPump as a side-effect. We need to clear mPump if 687 // this method fails. 688 rv = BeginPumpingData(); 689 if (NS_FAILED(rv)) { 690 mPump = nullptr; 691 mRequest = nullptr; 692 mPumpingData = false; 693 ChannelDone(); 694 mCallbacks = nullptr; 695 return rv; 696 } 697 698 // At this point, we are going to return success no matter what. 699 700 mWasOpened = true; 701 702 SUSPEND_PUMP_FOR_SCOPE(); 703 704 if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr); 705 706 ClassifyURI(); 707 708 return NS_OK; 709 } 710 711 //----------------------------------------------------------------------------- 712 // nsBaseChannel::nsITransportEventSink 713 714 NS_IMETHODIMP 715 nsBaseChannel::OnTransportStatus(nsITransport* transport, nsresult status, 716 int64_t progress, int64_t progressMax) { 717 // In some cases, we may wish to suppress transport-layer status events. 718 719 if (!mPumpingData || NS_FAILED(mStatus)) { 720 return NS_OK; 721 } 722 723 SUSPEND_PUMP_FOR_SCOPE(); 724 725 // Lazily fetch mProgressSink 726 if (!mProgressSink) { 727 if (mQueriedProgressSink) { 728 return NS_OK; 729 } 730 GetCallback(mProgressSink); 731 mQueriedProgressSink = true; 732 if (!mProgressSink) { 733 return NS_OK; 734 } 735 } 736 737 if (!HasLoadFlag(LOAD_BACKGROUND)) { 738 nsAutoString statusArg; 739 if (GetStatusArg(status, statusArg)) { 740 mProgressSink->OnStatus(this, status, statusArg.get()); 741 } 742 } 743 744 if (progress) { 745 mProgressSink->OnProgress(this, progress, progressMax); 746 } 747 748 return NS_OK; 749 } 750 751 //----------------------------------------------------------------------------- 752 // nsBaseChannel::nsIInterfaceRequestor 753 754 NS_IMETHODIMP 755 nsBaseChannel::GetInterface(const nsIID& iid, void** result) { 756 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, iid, result); 757 return *result ? NS_OK : NS_ERROR_NO_INTERFACE; 758 } 759 760 //----------------------------------------------------------------------------- 761 // nsBaseChannel::nsIRequestObserver 762 763 static void CallTypeSniffers(void* aClosure, const uint8_t* aData, 764 uint32_t aCount) { 765 nsIChannel* chan = static_cast<nsIChannel*>(aClosure); 766 767 nsAutoCString newType; 768 NS_SniffContent(NS_CONTENT_SNIFFER_CATEGORY, chan, aData, aCount, newType); 769 if (!newType.IsEmpty()) { 770 chan->SetContentType(newType); 771 } 772 } 773 774 static void CallUnknownTypeSniffer(void* aClosure, const uint8_t* aData, 775 uint32_t aCount) { 776 nsIChannel* chan = static_cast<nsIChannel*>(aClosure); 777 778 RefPtr<nsUnknownDecoder> sniffer = new nsUnknownDecoder(); 779 780 nsAutoCString detected; 781 nsresult rv = sniffer->GetMIMETypeFromContent(chan, aData, aCount, detected); 782 if (NS_SUCCEEDED(rv)) chan->SetContentType(detected); 783 } 784 785 NS_IMETHODIMP 786 nsBaseChannel::OnStartRequest(nsIRequest* request) { 787 MOZ_ASSERT_IF(mRequest, request == mRequest); 788 MOZ_ASSERT_IF(mCancelableAsyncRequest, !mRequest); 789 790 if (mPump) { 791 // If our content type is unknown, use the content type 792 // sniffer. If the sniffer is not available for some reason, then we just 793 // keep going as-is. 794 if (NS_SUCCEEDED(mStatus) && 795 mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) { 796 mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this)); 797 } 798 799 // Now, the general type sniffers. Skip this if we have none. 800 if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { 801 mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this)); 802 } 803 } 804 805 SUSPEND_PUMP_FOR_SCOPE(); 806 807 if (mListener) { // null in case of redirect 808 return mListener->OnStartRequest(this); 809 } 810 return NS_OK; 811 } 812 813 NS_IMETHODIMP 814 nsBaseChannel::OnStopRequest(nsIRequest* request, nsresult status) { 815 // If both mStatus and status are failure codes, we keep mStatus as-is since 816 // that is consistent with our GetStatus and Cancel methods. 817 if (NS_SUCCEEDED(mStatus)) mStatus = status; 818 819 // Cause Pending to return false. 820 mPump = nullptr; 821 mRequest = nullptr; 822 mCancelableAsyncRequest = nullptr; 823 mPumpingData = false; 824 825 if (mListener) { // null in case of redirect 826 mListener->OnStopRequest(this, mStatus); 827 } 828 ChannelDone(); 829 830 // No need to suspend pump in this scope since we will not be receiving 831 // any more events from it. 832 833 if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus); 834 835 // Drop notification callbacks to prevent cycles. 836 mCallbacks = nullptr; 837 CallbacksChanged(); 838 839 return NS_OK; 840 } 841 842 //----------------------------------------------------------------------------- 843 // nsBaseChannel::nsIStreamListener 844 845 NS_IMETHODIMP 846 nsBaseChannel::OnDataAvailable(nsIRequest* request, nsIInputStream* stream, 847 uint64_t offset, uint32_t count) { 848 SUSPEND_PUMP_FOR_SCOPE(); 849 850 nsresult rv = mListener->OnDataAvailable(this, stream, offset, count); 851 if (mSynthProgressEvents && NS_SUCCEEDED(rv)) { 852 int64_t prog = offset + count; 853 if (NS_IsMainThread()) { 854 OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, mContentLength); 855 } else { 856 class OnTransportStatusAsyncEvent : public Runnable { 857 RefPtr<nsBaseChannel> mChannel; 858 int64_t mProgress; 859 int64_t mContentLength; 860 861 public: 862 OnTransportStatusAsyncEvent(nsBaseChannel* aChannel, int64_t aProgress, 863 int64_t aContentLength) 864 : Runnable("OnTransportStatusAsyncEvent"), 865 mChannel(aChannel), 866 mProgress(aProgress), 867 mContentLength(aContentLength) {} 868 869 NS_IMETHOD Run() override { 870 return mChannel->OnTransportStatus(nullptr, NS_NET_STATUS_READING, 871 mProgress, mContentLength); 872 } 873 }; 874 875 nsCOMPtr<nsIRunnable> runnable = 876 new OnTransportStatusAsyncEvent(this, prog, mContentLength); 877 Dispatch(runnable.forget()); 878 } 879 } 880 881 return rv; 882 } 883 884 NS_IMETHODIMP 885 nsBaseChannel::OnRedirectVerifyCallback(nsresult result) { 886 if (NS_SUCCEEDED(result)) result = ContinueRedirect(); 887 888 if (NS_FAILED(result) && !mWaitingOnAsyncRedirect) { 889 if (NS_SUCCEEDED(mStatus)) mStatus = result; 890 return NS_OK; 891 } 892 893 if (mWaitingOnAsyncRedirect) ContinueHandleAsyncRedirect(result); 894 895 return NS_OK; 896 } 897 898 NS_IMETHODIMP 899 nsBaseChannel::RetargetDeliveryTo(nsISerialEventTarget* aEventTarget) { 900 MOZ_ASSERT(NS_IsMainThread()); 901 902 if (!mRequest) { 903 return NS_ERROR_NOT_INITIALIZED; 904 } 905 906 nsCOMPtr<nsIThreadRetargetableRequest> req; 907 if (mAllowThreadRetargeting) { 908 req = do_QueryInterface(mRequest); 909 } 910 911 NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED); 912 913 return req->RetargetDeliveryTo(aEventTarget); 914 } 915 916 NS_IMETHODIMP 917 nsBaseChannel::GetDeliveryTarget(nsISerialEventTarget** aEventTarget) { 918 MOZ_ASSERT(NS_IsMainThread()); 919 920 NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_INITIALIZED); 921 922 nsCOMPtr<nsIThreadRetargetableRequest> req; 923 req = do_QueryInterface(mRequest); 924 925 NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED); 926 return req->GetDeliveryTarget(aEventTarget); 927 } 928 929 NS_IMETHODIMP 930 nsBaseChannel::CheckListenerChain() { 931 MOZ_ASSERT(NS_IsMainThread()); 932 933 if (!mAllowThreadRetargeting) { 934 return NS_ERROR_NOT_IMPLEMENTED; 935 } 936 937 nsCOMPtr<nsIThreadRetargetableStreamListener> listener = 938 do_QueryInterface(mListener); 939 if (!listener) { 940 return NS_ERROR_NO_INTERFACE; 941 } 942 943 return listener->CheckListenerChain(); 944 } 945 946 NS_IMETHODIMP 947 nsBaseChannel::OnDataFinished(nsresult aStatus) { 948 if (!mListener) { 949 return NS_ERROR_FAILURE; 950 } 951 952 if (!mAllowThreadRetargeting) { 953 return NS_ERROR_NOT_IMPLEMENTED; 954 } 955 956 nsCOMPtr<nsIThreadRetargetableStreamListener> listener = 957 do_QueryInterface(mListener); 958 if (listener) { 959 return listener->OnDataFinished(aStatus); 960 } 961 962 return NS_OK; 963 } 964 965 NS_IMETHODIMP nsBaseChannel::GetCanceled(bool* aCanceled) { 966 *aCanceled = mCanceled; 967 return NS_OK; 968 } 969 970 void nsBaseChannel::SetupNeckoTarget() { 971 mNeckoTarget = GetMainThreadSerialEventTarget(); 972 } 973 974 NS_IMETHODIMP nsBaseChannel::GetContentRange( 975 RefPtr<mozilla::net::ContentRange>* aRange) { 976 if (aRange) { 977 *aRange = mContentRange; 978 } 979 return NS_OK; 980 } 981 982 NS_IMETHODIMP nsBaseChannel::SetContentRange( 983 RefPtr<mozilla::net::ContentRange> aRange) { 984 mContentRange = aRange; 985 return NS_OK; 986 } 987 988 NS_IMETHODIMP nsBaseChannel::GetFullMimeType(RefPtr<TMimeType<char>>* aOut) { 989 if (aOut) { 990 *aOut = mFullMimeType; 991 } 992 return NS_OK; 993 } 994 995 NS_IMETHODIMP nsBaseChannel::SetFullMimeType(RefPtr<TMimeType<char>> aType) { 996 mFullMimeType = aType; 997 return NS_OK; 998 }