FetchService.cpp (30968B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "mozilla/dom/FetchService.h" 6 7 #include "FetchLog.h" 8 #include "FetchParent.h" 9 #include "mozilla/BasePrincipal.h" 10 #include "mozilla/ClearOnShutdown.h" 11 #include "mozilla/SchedulerGroup.h" 12 #include "mozilla/UniquePtr.h" 13 #include "mozilla/dom/ClientInfo.h" 14 #include "mozilla/dom/InternalRequest.h" 15 #include "mozilla/dom/InternalResponse.h" 16 #include "mozilla/dom/PerformanceStorage.h" 17 #include "mozilla/dom/PerformanceTiming.h" 18 #include "mozilla/dom/ServiceWorkerDescriptor.h" 19 #include "mozilla/ipc/BackgroundUtils.h" 20 #include "mozilla/net/CookieJarSettings.h" 21 #include "nsContentUtils.h" 22 #include "nsIContentSecurityPolicy.h" 23 #include "nsICookieJarSettings.h" 24 #include "nsIIOService.h" 25 #include "nsILoadGroup.h" 26 #include "nsILoadInfo.h" 27 #include "nsIObserverService.h" 28 #include "nsIPrincipal.h" 29 #include "nsIScriptSecurityManager.h" 30 #include "nsNetUtil.h" 31 #include "nsThreadUtils.h" 32 #include "nsXULAppAPI.h" 33 34 namespace mozilla::dom { 35 36 mozilla::LazyLogModule gFetchLog("Fetch"); 37 38 // FetchServicePromises 39 40 FetchServicePromises::FetchServicePromises() 41 : mAvailablePromise( 42 MakeRefPtr<FetchServiceResponseAvailablePromise::Private>(__func__)), 43 mTimingPromise( 44 MakeRefPtr<FetchServiceResponseTimingPromise::Private>(__func__)), 45 mEndPromise( 46 MakeRefPtr<FetchServiceResponseEndPromise::Private>(__func__)) { 47 mAvailablePromise->UseDirectTaskDispatch(__func__); 48 mTimingPromise->UseDirectTaskDispatch(__func__); 49 mEndPromise->UseDirectTaskDispatch(__func__); 50 } 51 52 RefPtr<FetchServiceResponseAvailablePromise> 53 FetchServicePromises::GetResponseAvailablePromise() { 54 return mAvailablePromise; 55 } 56 57 RefPtr<FetchServiceResponseTimingPromise> 58 FetchServicePromises::GetResponseTimingPromise() { 59 return mTimingPromise; 60 } 61 62 RefPtr<FetchServiceResponseEndPromise> 63 FetchServicePromises::GetResponseEndPromise() { 64 return mEndPromise; 65 } 66 67 void FetchServicePromises::ResolveResponseAvailablePromise( 68 FetchServiceResponse&& aResponse, StaticString aMethodName) { 69 if (mAvailablePromise) { 70 mAvailablePromiseResolved = true; 71 mAvailablePromise->Resolve(std::move(aResponse), aMethodName); 72 } 73 } 74 75 void FetchServicePromises::RejectResponseAvailablePromise( 76 const CopyableErrorResult&& aError, StaticString aMethodName) { 77 if (mAvailablePromise) { 78 mAvailablePromise->Reject(aError, aMethodName); 79 } 80 } 81 82 void FetchServicePromises::ResolveResponseTimingPromise( 83 ResponseTiming&& aTiming, StaticString aMethodName) { 84 if (mTimingPromise) { 85 mTimingPromiseResolved = true; 86 mTimingPromise->Resolve(std::move(aTiming), aMethodName); 87 } 88 } 89 90 void FetchServicePromises::RejectResponseTimingPromise( 91 const CopyableErrorResult&& aError, StaticString aMethodName) { 92 if (mTimingPromise) { 93 mTimingPromise->Reject(aError, aMethodName); 94 } 95 } 96 97 void FetchServicePromises::ResolveResponseEndPromise(ResponseEndArgs&& aArgs, 98 StaticString aMethodName) { 99 if (mEndPromise) { 100 mEndPromiseResolved = true; 101 mEndPromise->Resolve(std::move(aArgs), aMethodName); 102 } 103 } 104 105 void FetchServicePromises::RejectResponseEndPromise( 106 const CopyableErrorResult&& aError, StaticString aMethodName) { 107 if (mEndPromise) { 108 mEndPromise->Reject(aError, aMethodName); 109 } 110 } 111 112 // FetchInstance 113 114 nsresult FetchService::FetchInstance::Initialize(FetchArgs&& aArgs) { 115 MOZ_ASSERT(XRE_IsParentProcess()); 116 MOZ_ASSERT(NS_IsMainThread()); 117 MOZ_ASSERT(!aArgs.is<UnknownArgs>() && mArgs.is<UnknownArgs>()); 118 119 mArgs = std::move(aArgs); 120 121 // Get needed information for FetchDriver from passed-in channel. 122 if (mArgs.is<NavigationPreloadArgs>()) { 123 mRequest = mArgs.as<NavigationPreloadArgs>().mRequest.clonePtr(); 124 mArgsType = FetchArgsType::NavigationPreload; 125 nsIChannel* channel = mArgs.as<NavigationPreloadArgs>().mChannel; 126 FETCH_LOG(("FetchInstance::Initialize [%p] request[%p], channel[%p]", this, 127 mRequest.unsafeGetRawPtr(), channel)); 128 129 nsresult rv; 130 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo(); 131 MOZ_ASSERT(loadInfo); 132 133 nsCOMPtr<nsIURI> channelURI; 134 rv = channel->GetURI(getter_AddRefs(channelURI)); 135 if (NS_WARN_IF(NS_FAILED(rv))) { 136 return rv; 137 } 138 139 nsIScriptSecurityManager* securityManager = 140 nsContentUtils::GetSecurityManager(); 141 if (securityManager) { 142 securityManager->GetChannelResultPrincipal(channel, 143 getter_AddRefs(mPrincipal)); 144 } 145 146 if (!mPrincipal) { 147 return NS_ERROR_UNEXPECTED; 148 } 149 150 // Get loadGroup from channel 151 rv = channel->GetLoadGroup(getter_AddRefs(mLoadGroup)); 152 if (NS_WARN_IF(NS_FAILED(rv))) { 153 return rv; 154 } 155 if (!mLoadGroup) { 156 rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), mPrincipal); 157 if (NS_WARN_IF(NS_FAILED(rv))) { 158 return rv; 159 } 160 } 161 162 // Get CookieJarSettings from channel 163 rv = loadInfo->GetCookieJarSettings(getter_AddRefs(mCookieJarSettings)); 164 if (NS_WARN_IF(NS_FAILED(rv))) { 165 return rv; 166 } 167 168 // Get PerformanceStorage from channel 169 mPerformanceStorage = loadInfo->GetPerformanceStorage(); 170 } else if (mArgs.is<MainThreadFetchArgs>()) { 171 mArgsType = FetchArgsType::MainThreadFetch; 172 173 mRequest = mArgs.as<MainThreadFetchArgs>().mRequest.clonePtr(); 174 175 FETCH_LOG(("FetchInstance::Initialize [%p] request[%p]", this, 176 mRequest.unsafeGetRawPtr())); 177 178 auto principalOrErr = PrincipalInfoToPrincipal( 179 mArgs.as<MainThreadFetchArgs>().mPrincipalInfo); 180 if (principalOrErr.isErr()) { 181 return principalOrErr.unwrapErr(); 182 } 183 mPrincipal = principalOrErr.unwrap(); 184 nsresult rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), mPrincipal); 185 if (NS_WARN_IF(NS_FAILED(rv))) { 186 return rv; 187 } 188 189 if (mArgs.as<MainThreadFetchArgs>().mCookieJarSettings.isSome()) { 190 net::CookieJarSettings::Deserialize( 191 mArgs.as<MainThreadFetchArgs>().mCookieJarSettings.ref(), 192 getter_AddRefs(mCookieJarSettings)); 193 } 194 195 return NS_OK; 196 197 } else { 198 mRequest = mArgs.as<WorkerFetchArgs>().mRequest.clonePtr(); 199 mArgsType = FetchArgsType::WorkerFetch; 200 201 FETCH_LOG(("FetchInstance::Initialize [%p] request[%p]", this, 202 mRequest.unsafeGetRawPtr())); 203 204 auto principalOrErr = 205 PrincipalInfoToPrincipal(mArgs.as<WorkerFetchArgs>().mPrincipalInfo); 206 if (principalOrErr.isErr()) { 207 return principalOrErr.unwrapErr(); 208 } 209 mPrincipal = principalOrErr.unwrap(); 210 nsresult rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), mPrincipal); 211 if (NS_WARN_IF(NS_FAILED(rv))) { 212 return rv; 213 } 214 215 if (mArgs.as<WorkerFetchArgs>().mCookieJarSettings.isSome()) { 216 net::CookieJarSettings::Deserialize( 217 mArgs.as<WorkerFetchArgs>().mCookieJarSettings.ref(), 218 getter_AddRefs(mCookieJarSettings)); 219 } 220 } 221 222 return NS_OK; 223 } 224 225 RefPtr<FetchServicePromises> FetchService::FetchInstance::Fetch() { 226 MOZ_ASSERT(XRE_IsParentProcess()); 227 MOZ_ASSERT(NS_IsMainThread()); 228 229 MOZ_ASSERT(mPrincipal); 230 MOZ_ASSERT(mLoadGroup); 231 232 nsAutoCString principalSpec; 233 MOZ_ALWAYS_SUCCEEDS(mPrincipal->GetAsciiSpec(principalSpec)); 234 nsAutoCString requestURL; 235 mRequest->GetURL(requestURL); 236 FETCH_LOG(("FetchInstance::Fetch [%p], mRequest URL: %s mPrincipal: %s", this, 237 requestURL.BeginReading(), principalSpec.BeginReading())); 238 239 nsresult rv; 240 241 if (mRequest->GetKeepalive()) { 242 nsAutoCString origin; 243 MOZ_ASSERT(mPrincipal); 244 mPrincipal->GetOrigin(origin); 245 246 RefPtr<FetchService> fetchService = FetchService::GetInstance(); 247 MOZ_ASSERT(fetchService); 248 if (fetchService->DoesExceedsKeepaliveResourceLimits(origin)) { 249 FETCH_LOG(("FetchInstance::Fetch Keepalive request exceeds limit")); 250 return FetchService::NetworkErrorResponse(NS_ERROR_DOM_ABORT_ERR, mArgs); 251 } 252 fetchService->IncrementKeepAliveRequestCount(origin); 253 } 254 255 // Create a FetchDriver instance 256 mFetchDriver = MakeRefPtr<FetchDriver>( 257 mRequest.clonePtr(), // Fetch Request 258 mPrincipal, // Principal 259 mLoadGroup, // LoadGroup 260 GetMainThreadSerialEventTarget(), // MainThreadEventTarget 261 mCookieJarSettings, // CookieJarSettings 262 mPerformanceStorage, // PerformanceStorage 263 // For service workers we set 264 // tracking fetch to false, but for Keepalive 265 // requests from main thread this needs to be 266 // changed. See Bug 1892406 267 net::ClassificationFlags({0, 0}) // TrackingFlags 268 ); 269 270 if (mArgsType == FetchArgsType::WorkerFetch) { 271 auto& args = mArgs.as<WorkerFetchArgs>(); 272 mFetchDriver->SetWorkerScript(args.mWorkerScript); 273 MOZ_ASSERT(args.mClientInfo.isSome()); 274 mFetchDriver->SetClientInfo(args.mClientInfo.ref()); 275 mFetchDriver->SetController(args.mController); 276 if (args.mCSPEventListener) { 277 mFetchDriver->SetCSPEventListener(args.mCSPEventListener); 278 } 279 mFetchDriver->SetAssociatedBrowsingContextID( 280 args.mAssociatedBrowsingContextID); 281 mFetchDriver->SetIsThirdPartyContext(Some(args.mIsThirdPartyContext)); 282 mFetchDriver->SetIsOn3PCBExceptionList(args.mIsOn3PCBExceptionList); 283 } 284 285 if (mArgsType == FetchArgsType::MainThreadFetch) { 286 auto& args = mArgs.as<MainThreadFetchArgs>(); 287 mFetchDriver->SetAssociatedBrowsingContextID( 288 args.mAssociatedBrowsingContextID); 289 mFetchDriver->SetIsThirdPartyContext(Some(args.mIsThirdPartyContext)); 290 } 291 292 mFetchDriver->EnableNetworkInterceptControl(); 293 mPromises = MakeRefPtr<FetchServicePromises>(); 294 295 // Call FetchDriver::Fetch to start fetching. 296 // Pass AbortSignalImpl as nullptr since we no need support AbortSignalImpl 297 // with FetchService. AbortSignalImpl related information should be passed 298 // through PFetch or InterceptedHttpChannel, then call 299 // FetchService::CancelFetch() to abort the running fetch. 300 rv = mFetchDriver->Fetch(nullptr, this); 301 if (NS_WARN_IF(NS_FAILED(rv))) { 302 FETCH_LOG( 303 ("FetchInstance::Fetch FetchDriver::Fetch failed(0x%X)", (uint32_t)rv)); 304 return FetchService::NetworkErrorResponse(rv, mArgs); 305 } 306 307 return mPromises; 308 } 309 310 bool FetchService::FetchInstance::IsLocalHostFetch() const { 311 if (!mPrincipal) { 312 return false; 313 } 314 bool res; 315 nsresult rv = mPrincipal->GetIsLoopbackHost(&res); 316 if (NS_WARN_IF(NS_FAILED(rv))) { 317 return false; 318 } 319 return res; 320 } 321 322 void FetchService::FetchInstance::Cancel(bool aForceAbort) { 323 MOZ_ASSERT(XRE_IsParentProcess()); 324 MOZ_ASSERT(NS_IsMainThread()); 325 326 FETCH_LOG(("FetchInstance::Cancel() [%p]", this)); 327 328 // If mFetchDriver is not null here, FetchInstance::Fetch() has already 329 // started, let mFetchDriver::RunAbortAlgorithm() to call 330 // FetchInstance::OnResponseEnd() to resolve the pending promises. 331 // Otherwise, resolving the pending promises here. 332 if (mFetchDriver) { 333 // if keepalive is active and it is NOT user initiated Abort, then 334 // do not cancel the request. 335 if (mRequest->GetKeepalive() && !aForceAbort) { 336 FETCH_LOG(("Cleaning up the worker for keepalive[%p]", this)); 337 338 MOZ_ASSERT(mArgs.is<WorkerFetchArgs>()); 339 if (mArgs.is<WorkerFetchArgs>()) { 340 // delete the actors for cleanup for worker keep-alive requests. 341 // Non-worker keepalive requests need actors to be active until request 342 // completion, because we update request quota per load-group in 343 // FetchChild::ActorDestroy. 344 MOZ_ASSERT((mArgs.as<WorkerFetchArgs>().mFetchParentPromise)); 345 if (mArgs.as<WorkerFetchArgs>().mResponseEndPromiseHolder.Exists()) { 346 FETCH_LOG( 347 ("FetchInstance::Cancel() [%p] mResponseEndPromiseHolder exists", 348 this)); 349 350 mArgs.as<WorkerFetchArgs>().mResponseEndPromiseHolder.Disconnect(); 351 352 // the parent promise resolution leads to deleting of actors 353 // mActorDying prevents further access to FetchParent 354 mActorDying = true; 355 mArgs.as<WorkerFetchArgs>().mFetchParentPromise->Resolve(true, 356 __func__); 357 } 358 } 359 return; 360 } 361 mFetchDriver->RunAbortAlgorithm(); 362 return; 363 } 364 365 MOZ_ASSERT(mPromises); 366 367 mPromises->ResolveResponseAvailablePromise( 368 InternalResponse::NetworkError(NS_ERROR_DOM_ABORT_ERR), __func__); 369 370 mPromises->ResolveResponseTimingPromise(ResponseTiming(), __func__); 371 372 mPromises->ResolveResponseEndPromise( 373 ResponseEndArgs(FetchDriverObserver::eAborted), __func__); 374 } 375 376 void FetchService::FetchInstance::OnResponseEnd( 377 FetchDriverObserver::EndReason aReason, 378 JS::Handle<JS::Value> aReasonDetails) { 379 FETCH_LOG(("FetchInstance::OnResponseEnd [%p] %s", this, 380 aReason == eAborted ? "eAborted" : "eNetworking")); 381 382 if (mRequest->GetKeepalive()) { 383 nsAutoCString origin; 384 MOZ_ASSERT(mPrincipal); 385 mPrincipal->GetOrigin(origin); 386 RefPtr<FetchService> fetchService = FetchService::GetInstance(); 387 fetchService->DecrementKeepAliveRequestCount(origin); 388 } 389 390 MOZ_ASSERT(mRequest); 391 if (mArgsType != FetchArgsType::NavigationPreload) { 392 FlushConsoleReport(); 393 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( 394 __func__, 395 [endArgs = ResponseEndArgs(aReason), actorID = GetActorID()]() { 396 FETCH_LOG(("FetchInstance::OnResponseEnd, Runnable")); 397 RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID); 398 if (actor) { 399 actor->OnResponseEnd(std::move(endArgs)); 400 } 401 }); 402 MOZ_ALWAYS_SUCCEEDS( 403 GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL)); 404 } 405 406 MOZ_ASSERT(mPromises); 407 408 if (mArgs.is<WorkerFetchArgs>() && 409 mArgs.as<WorkerFetchArgs>().mResponseEndPromiseHolder.Exists()) { 410 mArgs.as<WorkerFetchArgs>().mResponseEndPromiseHolder.Complete(); 411 } 412 413 if (aReason == eAborted) { 414 // If ResponseAvailablePromise has not resolved yet, resolved with 415 // NS_ERROR_DOM_ABORT_ERR response. If the promise is already resolved, 416 // this will have no effect. 417 mPromises->ResolveResponseAvailablePromise( 418 InternalResponse::NetworkError(NS_ERROR_DOM_ABORT_ERR), __func__); 419 420 // If ResponseTimingPromise has not resolved yet, resolved with empty 421 // ResponseTiming. If the promise is already resolved, this has no effect. 422 mPromises->ResolveResponseTimingPromise(ResponseTiming(), __func__); 423 // Resolve the ResponseEndPromise 424 mPromises->ResolveResponseEndPromise(ResponseEndArgs(aReason), __func__); 425 return; 426 } 427 428 MOZ_ASSERT(mPromises->IsResponseAvailablePromiseResolved() && 429 mPromises->IsResponseTimingPromiseResolved()); 430 431 // Resolve the ResponseEndPromise 432 mPromises->ResolveResponseEndPromise(ResponseEndArgs(aReason), __func__); 433 434 // Remove the FetchInstance from FetchInstanceTable 435 RefPtr<FetchService> fetchService = FetchService::GetInstance(); 436 MOZ_ASSERT(fetchService); 437 auto entry = fetchService->mFetchInstanceTable.Lookup(mPromises); 438 if (entry) { 439 entry.Remove(); 440 FETCH_LOG( 441 ("FetchInstance::OnResponseEnd entry of responsePromise[%p] is " 442 "removed", 443 mPromises.get())); 444 } 445 } 446 447 void FetchService::FetchInstance::OnResponseAvailableInternal( 448 SafeRefPtr<InternalResponse> aResponse) { 449 FETCH_LOG(("FetchInstance::OnResponseAvailableInternal [%p]", this)); 450 mResponse = std::move(aResponse); 451 452 nsCOMPtr<nsIInputStream> body; 453 mResponse->GetUnfilteredBody(getter_AddRefs(body)); 454 FETCH_LOG( 455 ("FetchInstance::OnResponseAvailableInternal [%p] response body: %p", 456 this, body.get())); 457 MOZ_ASSERT(mRequest); 458 459 if (mArgsType != FetchArgsType::NavigationPreload && !mActorDying) { 460 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( 461 __func__, 462 [response = mResponse.clonePtr(), actorID = GetActorID()]() mutable { 463 FETCH_LOG(("FetchInstance::OnResponseAvailableInternal Runnable")); 464 RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID); 465 if (actor) { 466 actor->OnResponseAvailableInternal(std::move(response)); 467 } 468 }); 469 MOZ_ALWAYS_SUCCEEDS( 470 GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL)); 471 } 472 473 MOZ_ASSERT(mPromises); 474 475 // Resolve the ResponseAvailablePromise 476 mPromises->ResolveResponseAvailablePromise(mResponse.clonePtr(), __func__); 477 } 478 479 bool FetchService::FetchInstance::NeedOnDataAvailable() { 480 if (mArgs.is<WorkerFetchArgs>()) { 481 return mArgs.as<WorkerFetchArgs>().mNeedOnDataAvailable; 482 } 483 484 if (mArgs.is<MainThreadFetchArgs>()) { 485 return mArgs.as<MainThreadFetchArgs>().mNeedOnDataAvailable; 486 } 487 488 return false; 489 } 490 491 void FetchService::FetchInstance::OnDataAvailable() { 492 FETCH_LOG(("FetchInstance::OnDataAvailable [%p]", this)); 493 494 if (!NeedOnDataAvailable()) { 495 return; 496 } 497 498 MOZ_ASSERT(mRequest); 499 500 if (mArgsType != FetchArgsType::NavigationPreload && !mActorDying) { 501 nsCOMPtr<nsIRunnable> r = 502 NS_NewRunnableFunction(__func__, [actorID = GetActorID()]() { 503 FETCH_LOG(("FetchInstance::OnDataAvailable, Runnable")); 504 RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID); 505 if (actor) { 506 actor->OnDataAvailable(); 507 } 508 }); 509 MOZ_ALWAYS_SUCCEEDS( 510 GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL)); 511 } 512 } 513 514 void FetchService::FetchInstance::FlushConsoleReport() { 515 FETCH_LOG(("FetchInstance::FlushConsoleReport [%p]", this)); 516 517 if (mArgsType != FetchArgsType::NavigationPreload && !mActorDying) { 518 if (!mReporter) { 519 return; 520 } 521 nsTArray<net::ConsoleReportCollected> reports; 522 mReporter->StealConsoleReports(reports); 523 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( 524 __func__, 525 [actorID = GetActorID(), consoleReports = std::move(reports)]() { 526 FETCH_LOG(("FetchInstance::FlushConsolReport, Runnable")); 527 RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID); 528 if (actor) { 529 actor->OnFlushConsoleReport(std::move(consoleReports)); 530 } 531 }); 532 MOZ_ALWAYS_SUCCEEDS( 533 GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL)); 534 } 535 } 536 537 void FetchService::FetchInstance::OnReportPerformanceTiming() { 538 FETCH_LOG(("FetchInstance::OnReportPerformanceTiming [%p]", this)); 539 MOZ_ASSERT(mFetchDriver); 540 MOZ_ASSERT(mPromises); 541 542 if (mPromises->IsResponseTimingPromiseResolved()) { 543 return; 544 } 545 546 ResponseTiming timing; 547 UniquePtr<PerformanceTimingData> performanceTiming( 548 mFetchDriver->GetPerformanceTimingData(timing.initiatorType(), 549 timing.entryName())); 550 // FetchDriver has no corresponding performance timing when fetch() failed. 551 // Resolve the ResponseTimingPromise with empty timing. 552 if (!performanceTiming) { 553 mPromises->ResolveResponseTimingPromise(ResponseTiming(), __func__); 554 return; 555 } 556 timing.timingData() = performanceTiming->ToIPC(); 557 // Force replace initiatorType for ServiceWorkerNavgationPreload. 558 if (mArgsType == FetchArgsType::NavigationPreload) { 559 timing.initiatorType() = u"navigation"_ns; 560 } else if (!mActorDying) { 561 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( 562 __func__, [actorID = GetActorID(), timing = timing]() { 563 FETCH_LOG(("FetchInstance::OnReportPerformanceTiming, Runnable")); 564 RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID); 565 if (actor) { 566 actor->OnReportPerformanceTiming(std::move(timing)); 567 } 568 }); 569 MOZ_ALWAYS_SUCCEEDS( 570 GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL)); 571 } 572 573 mPromises->ResolveResponseTimingPromise(std::move(timing), __func__); 574 } 575 576 void FetchService::FetchInstance::OnNotifyNetworkMonitorAlternateStack( 577 uint64_t aChannelID) { 578 FETCH_LOG(("FetchInstance::OnNotifyNetworkMonitorAlternateStack [%p]", this)); 579 MOZ_ASSERT(mFetchDriver); 580 MOZ_ASSERT(mPromises); 581 582 if (mArgsType != FetchArgsType::WorkerFetch && 583 mArgsType != FetchArgsType::MainThreadFetch) { 584 // Fetch type not supported 585 return; 586 } 587 588 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( 589 __func__, [actorID = GetActorID(), channelID = aChannelID]() { 590 FETCH_LOG( 591 ("FetchInstance::OnNotifyNetworkMonitorAlternateStack, Runnable")); 592 RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID); 593 if (actor) { 594 actor->OnNotifyNetworkMonitorAlternateStack(channelID); 595 } 596 }); 597 598 MOZ_ALWAYS_SUCCEEDS( 599 GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL)); 600 } 601 602 nsID FetchService::FetchInstance::GetActorID() { 603 if (mArgsType == FetchArgsType::WorkerFetch) { 604 return mArgs.as<WorkerFetchArgs>().mActorID; 605 } 606 607 if (mArgsType == FetchArgsType::MainThreadFetch) { 608 return mArgs.as<MainThreadFetchArgs>().mActorID; 609 } 610 611 MOZ_ASSERT_UNREACHABLE("GetActorID called for unexpected mArgsType"); 612 613 return {}; 614 } 615 616 nsCOMPtr<nsISerialEventTarget> 617 FetchService::FetchInstance::GetBackgroundEventTarget() { 618 if (mArgsType == FetchArgsType::WorkerFetch) { 619 return mArgs.as<WorkerFetchArgs>().mEventTarget; 620 } 621 622 if (mArgsType == FetchArgsType::MainThreadFetch) { 623 return mArgs.as<MainThreadFetchArgs>().mEventTarget; 624 } 625 626 MOZ_ASSERT_UNREACHABLE( 627 "GetBackgroundEventTarget called for unexpected mArgsType"); 628 629 return {}; 630 } 631 632 // FetchService 633 634 NS_IMPL_ISUPPORTS(FetchService, nsIObserver) 635 636 StaticRefPtr<FetchService> gInstance; 637 638 /*static*/ 639 already_AddRefed<FetchService> FetchService::GetInstance() { 640 MOZ_ASSERT(XRE_IsParentProcess()); 641 MOZ_ASSERT(NS_IsMainThread()); 642 643 if (!gInstance) { 644 gInstance = MakeRefPtr<FetchService>(); 645 nsresult rv = gInstance->RegisterNetworkObserver(); 646 if (NS_WARN_IF(NS_FAILED(rv))) { 647 gInstance = nullptr; 648 return nullptr; 649 } 650 ClearOnShutdown(&gInstance); 651 } 652 RefPtr<FetchService> service = gInstance; 653 return service.forget(); 654 } 655 656 /*static*/ 657 RefPtr<FetchServicePromises> FetchService::NetworkErrorResponse( 658 nsresult aRv, const FetchArgs& aArgs) { 659 if (aArgs.is<WorkerFetchArgs>()) { 660 const WorkerFetchArgs& args = aArgs.as<WorkerFetchArgs>(); 661 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( 662 __func__, [aRv, actorID = args.mActorID]() mutable { 663 FETCH_LOG( 664 ("FetchService::PropagateErrorResponse runnable aError: 0x%X", 665 (uint32_t)aRv)); 666 RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID); 667 if (actor) { 668 actor->OnResponseAvailableInternal( 669 InternalResponse::NetworkError(aRv)); 670 actor->OnResponseEnd( 671 ResponseEndArgs(FetchDriverObserver::eAborted)); 672 } 673 }); 674 MOZ_ALWAYS_SUCCEEDS( 675 args.mEventTarget->Dispatch(r, nsIThread::DISPATCH_NORMAL)); 676 } else if (aArgs.is<MainThreadFetchArgs>()) { 677 const MainThreadFetchArgs& args = aArgs.as<MainThreadFetchArgs>(); 678 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( 679 __func__, [aRv, actorID = args.mActorID]() mutable { 680 FETCH_LOG( 681 ("FetchService::PropagateErrorResponse runnable aError: 0x%X", 682 (uint32_t)aRv)); 683 RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID); 684 if (actor) { 685 actor->OnResponseAvailableInternal( 686 InternalResponse::NetworkError(aRv)); 687 actor->OnResponseEnd( 688 ResponseEndArgs(FetchDriverObserver::eAborted)); 689 } 690 }); 691 MOZ_ALWAYS_SUCCEEDS( 692 args.mEventTarget->Dispatch(r, nsIThread::DISPATCH_NORMAL)); 693 } 694 695 RefPtr<FetchServicePromises> promises = MakeRefPtr<FetchServicePromises>(); 696 promises->ResolveResponseAvailablePromise(InternalResponse::NetworkError(aRv), 697 __func__); 698 promises->ResolveResponseTimingPromise(ResponseTiming(), __func__); 699 promises->ResolveResponseEndPromise( 700 ResponseEndArgs(FetchDriverObserver::eAborted), __func__); 701 return promises; 702 } 703 704 FetchService::FetchService() { 705 MOZ_ASSERT(XRE_IsParentProcess()); 706 MOZ_ASSERT(NS_IsMainThread()); 707 } 708 709 FetchService::~FetchService() { 710 MOZ_ALWAYS_SUCCEEDS(UnregisterNetworkObserver()); 711 } 712 713 nsresult FetchService::RegisterNetworkObserver() { 714 AssertIsOnMainThread(); 715 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); 716 if (!observerService) { 717 return NS_ERROR_UNEXPECTED; 718 } 719 720 nsCOMPtr<nsIIOService> ioService = services::GetIOService(); 721 if (!ioService) { 722 return NS_ERROR_UNEXPECTED; 723 } 724 725 nsresult rv = observerService->AddObserver( 726 this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, false); 727 NS_ENSURE_SUCCESS(rv, rv); 728 729 rv = observerService->AddObserver(this, "xpcom-shutdown", false); 730 NS_ENSURE_SUCCESS(rv, rv); 731 732 rv = ioService->GetOffline(&mOffline); 733 NS_ENSURE_SUCCESS(rv, rv); 734 mObservingNetwork = true; 735 736 return NS_OK; 737 } 738 739 nsresult FetchService::UnregisterNetworkObserver() { 740 AssertIsOnMainThread(); 741 nsresult rv; 742 if (mObservingNetwork) { 743 nsCOMPtr<nsIObserverService> observerService = 744 mozilla::services::GetObserverService(); 745 if (observerService) { 746 rv = observerService->RemoveObserver(this, 747 NS_IOSERVICE_OFFLINE_STATUS_TOPIC); 748 NS_ENSURE_SUCCESS(rv, rv); 749 rv = observerService->RemoveObserver(this, "xpcom-shutdown"); 750 NS_ENSURE_SUCCESS(rv, rv); 751 } 752 mObservingNetwork = false; 753 } 754 return NS_OK; 755 } 756 757 void FetchService::IncrementKeepAliveRequestCount(const nsACString& aOrigin) { 758 MOZ_ASSERT(XRE_IsParentProcess()); 759 MOZ_ASSERT(NS_IsMainThread()); 760 FETCH_LOG(("FetchService::IncrementKeepAliveRequestCount [origin=%s]\n", 761 PromiseFlatCString(aOrigin).get())); 762 ++mTotalKeepAliveRequests; 763 uint32_t count = mPendingKeepAliveRequestsPerOrigin.Get(aOrigin) + 1; 764 mPendingKeepAliveRequestsPerOrigin.InsertOrUpdate(aOrigin, count); 765 } 766 767 void FetchService::DecrementKeepAliveRequestCount(const nsACString& aOrigin) { 768 MOZ_ASSERT(XRE_IsParentProcess()); 769 MOZ_ASSERT(NS_IsMainThread()); 770 FETCH_LOG(("FetchService::DecrementKeepAliveRequestCount [origin=%s]\n", 771 PromiseFlatCString(aOrigin).get())); 772 MOZ_ASSERT(mTotalKeepAliveRequests > 0); 773 if (mTotalKeepAliveRequests) { 774 --mTotalKeepAliveRequests; 775 } 776 777 uint32_t count = mPendingKeepAliveRequestsPerOrigin.Get(aOrigin); 778 MOZ_ASSERT(count > 0); 779 if (count) { 780 --count; 781 if (count == 0) { 782 mPendingKeepAliveRequestsPerOrigin.Remove(aOrigin); 783 } else { 784 mPendingKeepAliveRequestsPerOrigin.InsertOrUpdate(aOrigin, count); 785 } 786 } 787 } 788 789 bool FetchService::DoesExceedsKeepaliveResourceLimits( 790 const nsACString& origin) { 791 if (mTotalKeepAliveRequests >= 792 StaticPrefs::dom_fetchKeepalive_total_request_limit()) { 793 return true; 794 } 795 796 if (mPendingKeepAliveRequestsPerOrigin.Get(origin) >= 797 StaticPrefs::dom_fetchKeepalive_request_limit_per_origin()) { 798 return true; 799 } 800 801 return false; 802 } 803 804 NS_IMETHODIMP FetchService::Observe(nsISupports* aSubject, const char* aTopic, 805 const char16_t* aData) { 806 FETCH_LOG(("FetchService::Observe topic: %s", aTopic)); 807 AssertIsOnMainThread(); 808 MOZ_ASSERT(!strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC) || 809 !strcmp(aTopic, "xpcom-shutdown")); 810 811 if (!strcmp(aTopic, "xpcom-shutdown")) { 812 // Going to shutdown, unregister the network status observer to avoid 813 // receiving 814 nsresult rv = UnregisterNetworkObserver(); 815 NS_ENSURE_SUCCESS(rv, rv); 816 return NS_OK; 817 } 818 819 if (nsDependentString(aData).EqualsLiteral(NS_IOSERVICE_ONLINE)) { 820 mOffline = false; 821 } else { 822 mOffline = true; 823 // Network is offline, cancel the running fetch that is not to local server. 824 mFetchInstanceTable.RemoveIf([](auto& entry) { 825 bool res = entry.Data()->IsLocalHostFetch(); 826 if (res) { 827 return false; 828 } 829 entry.Data()->Cancel(true); 830 return true; 831 }); 832 } 833 return NS_OK; 834 } 835 836 RefPtr<FetchServicePromises> FetchService::Fetch(FetchArgs&& aArgs) { 837 MOZ_ASSERT(XRE_IsParentProcess()); 838 MOZ_ASSERT(NS_IsMainThread()); 839 840 FETCH_LOG(("FetchService::Fetch (%s)", aArgs.is<NavigationPreloadArgs>() 841 ? "NavigationPreload" 842 : "WorkerFetch")); 843 // Create FetchInstance 844 RefPtr<FetchInstance> fetch = MakeRefPtr<FetchInstance>(); 845 846 // Call FetchInstance::Initialize() to get needed information for 847 // FetchDriver 848 nsresult rv = fetch->Initialize(std::move(aArgs)); 849 if (NS_WARN_IF(NS_FAILED(rv))) { 850 return NetworkErrorResponse(rv, fetch->Args()); 851 } 852 853 if (mOffline && !fetch->IsLocalHostFetch()) { 854 FETCH_LOG(("FetchService::Fetch network offline")); 855 return NetworkErrorResponse(NS_ERROR_OFFLINE, fetch->Args()); 856 } 857 858 // Call FetchInstance::Fetch() to start an asynchronous fetching. 859 RefPtr<FetchServicePromises> promises = fetch->Fetch(); 860 MOZ_ASSERT(promises); 861 862 if (!promises->IsResponseAvailablePromiseResolved()) { 863 // Insert the created FetchInstance into FetchInstanceTable. 864 if (!mFetchInstanceTable.WithEntryHandle(promises, [&](auto&& entry) { 865 if (entry.HasEntry()) { 866 return false; 867 } 868 entry.Insert(fetch); 869 return true; 870 })) { 871 FETCH_LOG( 872 ("FetchService::Fetch entry[%p] already exists", promises.get())); 873 return NetworkErrorResponse(NS_ERROR_UNEXPECTED, fetch->Args()); 874 } 875 FETCH_LOG(("FetchService::Fetch entry[%p] of FetchInstance[%p] added", 876 promises.get(), fetch.get())); 877 } 878 return promises; 879 } 880 881 void FetchService::CancelFetch(const RefPtr<FetchServicePromises>&& aPromises, 882 bool aForceAbort) { 883 MOZ_ASSERT(XRE_IsParentProcess()); 884 MOZ_ASSERT(NS_IsMainThread()); 885 MOZ_ASSERT(aPromises); 886 FETCH_LOG(("FetchService::CancelFetch aPromises[%p]", aPromises.get())); 887 888 auto entry = mFetchInstanceTable.Lookup(aPromises); 889 if (entry) { 890 // Notice any modifications here before entry.Remove() probably should be 891 // reflected to Observe() offline case. 892 entry.Data()->Cancel(aForceAbort); 893 entry.Remove(); 894 FETCH_LOG( 895 ("FetchService::CancelFetch entry [%p] removed", aPromises.get())); 896 } 897 } 898 899 MozPromiseRequestHolder<FetchServiceResponseEndPromise>& 900 FetchService::GetResponseEndPromiseHolder( 901 const RefPtr<FetchServicePromises>& aPromises) { 902 MOZ_ASSERT(XRE_IsParentProcess()); 903 MOZ_ASSERT(NS_IsMainThread()); 904 MOZ_ASSERT(aPromises); 905 auto entry = mFetchInstanceTable.Lookup(aPromises); 906 MOZ_ASSERT(entry); 907 return entry.Data()->GetResponseEndPromiseHolder(); 908 } 909 910 } // namespace mozilla::dom