HttpBackgroundChannelParent.cpp (16944B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set sw=2 ts=8 et tw=80 : */ 3 4 /* This Source Code Form is subject to the terms of the Mozilla Public 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 8 // HttpLog.h should generally be included first 9 #include "HttpLog.h" 10 11 #include "HttpBackgroundChannelParent.h" 12 13 #include "HttpChannelParent.h" 14 #include "mozilla/ipc/BackgroundParent.h" 15 #include "mozilla/IntegerPrintfMacros.h" 16 #include "mozilla/net/BackgroundChannelRegistrar.h" 17 #include "mozilla/net/ChannelEventQueue.h" 18 #include "nsNetCID.h" 19 #include "nsQueryObject.h" 20 #include "nsThreadUtils.h" 21 22 using mozilla::dom::ContentParent; 23 using mozilla::ipc::AssertIsInMainProcess; 24 using mozilla::ipc::AssertIsOnBackgroundThread; 25 using mozilla::ipc::BackgroundParent; 26 using mozilla::ipc::IPCResult; 27 using mozilla::ipc::IsOnBackgroundThread; 28 29 namespace mozilla { 30 namespace net { 31 32 /* 33 * Helper class for continuing the AsyncOpen procedure on main thread. 34 */ 35 class ContinueAsyncOpenRunnable final : public Runnable { 36 public: 37 ContinueAsyncOpenRunnable(HttpBackgroundChannelParent* aActor, 38 const uint64_t& aChannelId) 39 : Runnable("net::ContinueAsyncOpenRunnable"), 40 mActor(aActor), 41 mChannelId(aChannelId) { 42 AssertIsInMainProcess(); 43 AssertIsOnBackgroundThread(); 44 MOZ_ASSERT(mActor); 45 } 46 47 NS_IMETHOD Run() override { 48 LOG( 49 ("HttpBackgroundChannelParent::ContinueAsyncOpen [this=%p " 50 "channelId=%" PRIu64 "]\n", 51 mActor.get(), mChannelId)); 52 AssertIsInMainProcess(); 53 MOZ_ASSERT(NS_IsMainThread()); 54 55 nsCOMPtr<nsIBackgroundChannelRegistrar> registrar = 56 BackgroundChannelRegistrar::GetOrCreate(); 57 MOZ_ASSERT(registrar); 58 59 registrar->LinkBackgroundChannel(mChannelId, mActor); 60 return NS_OK; 61 } 62 63 private: 64 RefPtr<HttpBackgroundChannelParent> mActor; 65 const uint64_t mChannelId; 66 }; 67 68 HttpBackgroundChannelParent::HttpBackgroundChannelParent() 69 : mIPCOpened(true), 70 mBgThreadMutex("HttpBackgroundChannelParent::BgThreadMutex") { 71 AssertIsInMainProcess(); 72 AssertIsOnBackgroundThread(); 73 74 { 75 MutexAutoLock lock(mBgThreadMutex); 76 mBackgroundThread = NS_GetCurrentThread(); 77 } 78 } 79 80 HttpBackgroundChannelParent::~HttpBackgroundChannelParent() { 81 MOZ_ASSERT(NS_IsMainThread() || IsOnBackgroundThread()); 82 MOZ_ASSERT(!mIPCOpened); 83 } 84 85 nsresult HttpBackgroundChannelParent::Init(const uint64_t& aChannelId) { 86 LOG(("HttpBackgroundChannelParent::Init [this=%p channelId=%" PRIu64 "]\n", 87 this, aChannelId)); 88 AssertIsInMainProcess(); 89 AssertIsOnBackgroundThread(); 90 91 RefPtr<ContinueAsyncOpenRunnable> runnable = 92 new ContinueAsyncOpenRunnable(this, aChannelId); 93 94 return NS_DispatchToMainThread(runnable); 95 } 96 97 void HttpBackgroundChannelParent::LinkToChannel( 98 HttpChannelParent* aChannelParent) { 99 LOG(("HttpBackgroundChannelParent::LinkToChannel [this=%p channel=%p]\n", 100 this, aChannelParent)); 101 AssertIsInMainProcess(); 102 MOZ_ASSERT(NS_IsMainThread()); 103 104 if (!mIPCOpened) { 105 return; 106 } 107 108 mChannelParent = aChannelParent; 109 } 110 111 void HttpBackgroundChannelParent::OnChannelClosed() { 112 LOG(("HttpBackgroundChannelParent::OnChannelClosed [this=%p]\n", this)); 113 AssertIsInMainProcess(); 114 MOZ_ASSERT(NS_IsMainThread()); 115 116 if (!mIPCOpened) { 117 return; 118 } 119 120 nsresult rv; 121 122 { 123 MutexAutoLock lock(mBgThreadMutex); 124 RefPtr<HttpBackgroundChannelParent> self = this; 125 rv = mBackgroundThread->Dispatch( 126 NS_NewRunnableFunction( 127 "net::HttpBackgroundChannelParent::OnChannelClosed", 128 [self]() { 129 LOG(("HttpBackgroundChannelParent::DeleteRunnable [this=%p]\n", 130 self.get())); 131 AssertIsOnBackgroundThread(); 132 133 if (!self->mIPCOpened.compareExchange(true, false)) { 134 return; 135 } 136 137 (void)self->Send__delete__(self); 138 }), 139 NS_DISPATCH_NORMAL); 140 } 141 142 (void)NS_WARN_IF(NS_FAILED(rv)); 143 } 144 145 bool HttpBackgroundChannelParent::OnStartRequest( 146 nsHttpResponseHead&& aResponseHead, const bool& aUseResponseHead, 147 const nsHttpHeaderArray& aRequestHeaders, 148 const HttpChannelOnStartRequestArgs& aArgs, 149 const nsCOMPtr<nsICacheEntry>& aAltDataSource, 150 TimeStamp aOnStartRequestStart) { 151 LOG(("HttpBackgroundChannelParent::OnStartRequest [this=%p]\n", this)); 152 AssertIsInMainProcess(); 153 154 if (NS_WARN_IF(!mIPCOpened)) { 155 return false; 156 } 157 158 if (!IsOnBackgroundThread()) { 159 MutexAutoLock lock(mBgThreadMutex); 160 nsresult rv = mBackgroundThread->Dispatch( 161 NewRunnableMethod<nsHttpResponseHead&&, const bool, 162 const nsHttpHeaderArray, 163 const HttpChannelOnStartRequestArgs, 164 const nsCOMPtr<nsICacheEntry>, TimeStamp>( 165 "net::HttpBackgroundChannelParent::OnStartRequest", this, 166 &HttpBackgroundChannelParent::OnStartRequest, 167 std::move(aResponseHead), aUseResponseHead, aRequestHeaders, aArgs, 168 aAltDataSource, aOnStartRequestStart), 169 NS_DISPATCH_NORMAL); 170 171 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 172 173 return NS_SUCCEEDED(rv); 174 } 175 176 HttpChannelAltDataStream altData; 177 if (aAltDataSource) { 178 nsAutoCString altDataType; 179 (void)aAltDataSource->GetAltDataType(altDataType); 180 181 if (!altDataType.IsEmpty()) { 182 nsCOMPtr<nsIInputStream> inputStream; 183 nsresult rv = aAltDataSource->OpenAlternativeInputStream( 184 altDataType, getter_AddRefs(inputStream)); 185 if (NS_SUCCEEDED(rv)) { 186 (void)mozilla::ipc::SerializeIPCStream(inputStream.forget(), 187 altData.altDataInputStream(), 188 /* aAllowLazy */ true); 189 } 190 } 191 } 192 193 return SendOnStartRequest(std::move(aResponseHead), aUseResponseHead, 194 aRequestHeaders, aArgs, altData, 195 aOnStartRequestStart); 196 } 197 198 bool HttpBackgroundChannelParent::OnTransportAndData( 199 const nsresult& aChannelStatus, const nsresult& aTransportStatus, 200 const uint64_t& aOffset, const uint32_t& aCount, const nsCString& aData, 201 TimeStamp aOnDataAvailableStart) { 202 LOG(("HttpBackgroundChannelParent::OnTransportAndData [this=%p]\n", this)); 203 AssertIsInMainProcess(); 204 205 if (NS_WARN_IF(!mIPCOpened)) { 206 return false; 207 } 208 209 if (!IsOnBackgroundThread()) { 210 MutexAutoLock lock(mBgThreadMutex); 211 nsresult rv = mBackgroundThread->Dispatch( 212 NewRunnableMethod<const nsresult, const nsresult, const uint64_t, 213 const uint32_t, const nsCString, TimeStamp>( 214 "net::HttpBackgroundChannelParent::OnTransportAndData", this, 215 &HttpBackgroundChannelParent::OnTransportAndData, aChannelStatus, 216 aTransportStatus, aOffset, aCount, aData, aOnDataAvailableStart), 217 NS_DISPATCH_NORMAL); 218 219 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 220 221 return NS_SUCCEEDED(rv); 222 } 223 224 nsHttp::SendFunc<nsDependentCSubstring> sendFunc = 225 [self = UnsafePtr<HttpBackgroundChannelParent>(this), aChannelStatus, 226 aTransportStatus, 227 aOnDataAvailableStart](const nsDependentCSubstring& aData, 228 uint64_t aOffset, uint32_t aCount) { 229 return self->SendOnTransportAndData(aChannelStatus, aTransportStatus, 230 aOffset, aCount, aData, false, 231 aOnDataAvailableStart); 232 }; 233 234 return nsHttp::SendDataInChunks(aData, aOffset, aCount, sendFunc); 235 } 236 237 bool HttpBackgroundChannelParent::OnStopRequest( 238 const nsresult& aChannelStatus, const ResourceTimingStructArgs& aTiming, 239 const nsHttpHeaderArray& aResponseTrailers, 240 const nsTArray<ConsoleReportCollected>& aConsoleReports, 241 TimeStamp aOnStopRequestStart) { 242 LOG( 243 ("HttpBackgroundChannelParent::OnStopRequest [this=%p " 244 "status=%" PRIx32 "]\n", 245 this, static_cast<uint32_t>(aChannelStatus))); 246 AssertIsInMainProcess(); 247 248 if (NS_WARN_IF(!mIPCOpened)) { 249 return false; 250 } 251 252 if (!IsOnBackgroundThread()) { 253 MutexAutoLock lock(mBgThreadMutex); 254 nsresult rv = mBackgroundThread->Dispatch( 255 NewRunnableMethod<const nsresult, const ResourceTimingStructArgs, 256 const nsHttpHeaderArray, 257 const CopyableTArray<ConsoleReportCollected>, 258 TimeStamp>( 259 "net::HttpBackgroundChannelParent::OnStopRequest", this, 260 &HttpBackgroundChannelParent::OnStopRequest, aChannelStatus, 261 aTiming, aResponseTrailers, aConsoleReports, aOnStopRequestStart), 262 NS_DISPATCH_NORMAL); 263 264 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 265 266 return NS_SUCCEEDED(rv); 267 } 268 269 // See the child code for why we do this. 270 TimeStamp lastActTabOpt = nsHttp::GetLastActiveTabLoadOptimizationHit(); 271 272 return SendOnStopRequest(aChannelStatus, aTiming, lastActTabOpt, 273 aResponseTrailers, aConsoleReports, false, 274 aOnStopRequestStart); 275 } 276 277 bool HttpBackgroundChannelParent::OnConsoleReport( 278 const nsTArray<ConsoleReportCollected>& aConsoleReports) { 279 LOG(("HttpBackgroundChannelParent::OnConsoleReport [this=%p]", this)); 280 AssertIsInMainProcess(); 281 282 if (NS_WARN_IF(!mIPCOpened)) { 283 return false; 284 } 285 286 if (!IsOnBackgroundThread()) { 287 MutexAutoLock lock(mBgThreadMutex); 288 nsresult rv = mBackgroundThread->Dispatch( 289 NewRunnableMethod<const CopyableTArray<ConsoleReportCollected>>( 290 "net::HttpBackgroundChannelParent::OnConsoleReport", this, 291 &HttpBackgroundChannelParent::OnConsoleReport, aConsoleReports), 292 NS_DISPATCH_NORMAL); 293 294 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 295 296 return NS_SUCCEEDED(rv); 297 } 298 299 return SendOnConsoleReport(aConsoleReports); 300 } 301 302 bool HttpBackgroundChannelParent::OnAfterLastPart(const nsresult aStatus) { 303 LOG(("HttpBackgroundChannelParent::OnAfterLastPart [this=%p]\n", this)); 304 AssertIsInMainProcess(); 305 306 if (NS_WARN_IF(!mIPCOpened)) { 307 return false; 308 } 309 310 if (!IsOnBackgroundThread()) { 311 MutexAutoLock lock(mBgThreadMutex); 312 nsresult rv = mBackgroundThread->Dispatch( 313 NewRunnableMethod<const nsresult>( 314 "net::HttpBackgroundChannelParent::OnAfterLastPart", this, 315 &HttpBackgroundChannelParent::OnAfterLastPart, aStatus), 316 NS_DISPATCH_NORMAL); 317 318 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 319 320 return NS_SUCCEEDED(rv); 321 } 322 323 return SendOnAfterLastPart(aStatus); 324 } 325 326 bool HttpBackgroundChannelParent::OnProgress(const int64_t aProgress, 327 const int64_t aProgressMax) { 328 LOG(("HttpBackgroundChannelParent::OnProgress [this=%p]\n", this)); 329 AssertIsInMainProcess(); 330 331 if (NS_WARN_IF(!mIPCOpened)) { 332 return false; 333 } 334 335 if (!IsOnBackgroundThread()) { 336 MutexAutoLock lock(mBgThreadMutex); 337 nsresult rv = mBackgroundThread->Dispatch( 338 NewRunnableMethod<const int64_t, const int64_t>( 339 "net::HttpBackgroundChannelParent::OnProgress", this, 340 &HttpBackgroundChannelParent::OnProgress, aProgress, aProgressMax), 341 NS_DISPATCH_NORMAL); 342 343 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 344 345 return NS_SUCCEEDED(rv); 346 } 347 348 return SendOnProgress(aProgress, aProgressMax); 349 } 350 351 bool HttpBackgroundChannelParent::OnStatus(const nsresult aStatus) { 352 LOG(("HttpBackgroundChannelParent::OnStatus [this=%p]\n", this)); 353 AssertIsInMainProcess(); 354 355 if (NS_WARN_IF(!mIPCOpened)) { 356 return false; 357 } 358 359 if (!IsOnBackgroundThread()) { 360 MutexAutoLock lock(mBgThreadMutex); 361 nsresult rv = mBackgroundThread->Dispatch( 362 NewRunnableMethod<const nsresult>( 363 "net::HttpBackgroundChannelParent::OnStatus", this, 364 &HttpBackgroundChannelParent::OnStatus, aStatus), 365 NS_DISPATCH_NORMAL); 366 367 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 368 369 return NS_SUCCEEDED(rv); 370 } 371 372 return SendOnStatus(aStatus); 373 } 374 375 bool HttpBackgroundChannelParent::OnNotifyClassificationFlags( 376 uint32_t aClassificationFlags, bool aIsThirdParty) { 377 LOG( 378 ("HttpBackgroundChannelParent::OnNotifyClassificationFlags " 379 "classificationFlags=%" PRIu32 ", thirdparty=%d [this=%p]\n", 380 aClassificationFlags, static_cast<int>(aIsThirdParty), this)); 381 AssertIsInMainProcess(); 382 383 if (NS_WARN_IF(!mIPCOpened)) { 384 return false; 385 } 386 387 if (!IsOnBackgroundThread()) { 388 MutexAutoLock lock(mBgThreadMutex); 389 nsresult rv = mBackgroundThread->Dispatch( 390 NewRunnableMethod<uint32_t, bool>( 391 "net::HttpBackgroundChannelParent::OnNotifyClassificationFlags", 392 this, &HttpBackgroundChannelParent::OnNotifyClassificationFlags, 393 aClassificationFlags, aIsThirdParty), 394 NS_DISPATCH_NORMAL); 395 396 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 397 398 return NS_SUCCEEDED(rv); 399 } 400 401 return SendNotifyClassificationFlags(aClassificationFlags, aIsThirdParty); 402 } 403 404 bool HttpBackgroundChannelParent::OnSetClassifierMatchedInfo( 405 const nsACString& aList, const nsACString& aProvider, 406 const nsACString& aFullHash) { 407 LOG(("HttpBackgroundChannelParent::OnSetClassifierMatchedInfo [this=%p]\n", 408 this)); 409 AssertIsInMainProcess(); 410 411 if (NS_WARN_IF(!mIPCOpened)) { 412 return false; 413 } 414 415 if (!IsOnBackgroundThread()) { 416 MutexAutoLock lock(mBgThreadMutex); 417 nsresult rv = mBackgroundThread->Dispatch( 418 NewRunnableMethod<const nsCString, const nsCString, const nsCString>( 419 "net::HttpBackgroundChannelParent::OnSetClassifierMatchedInfo", 420 this, &HttpBackgroundChannelParent::OnSetClassifierMatchedInfo, 421 aList, aProvider, aFullHash), 422 NS_DISPATCH_NORMAL); 423 424 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 425 426 return NS_SUCCEEDED(rv); 427 } 428 429 ClassifierInfo info; 430 info.list() = aList; 431 info.fullhash() = aFullHash; 432 info.provider() = aProvider; 433 434 return SendSetClassifierMatchedInfo(info); 435 } 436 437 bool HttpBackgroundChannelParent::OnSetClassifierMatchedTrackingInfo( 438 const nsACString& aLists, const nsACString& aFullHashes) { 439 LOG( 440 ("HttpBackgroundChannelParent::OnSetClassifierMatchedTrackingInfo " 441 "[this=%p]\n", 442 this)); 443 AssertIsInMainProcess(); 444 445 if (NS_WARN_IF(!mIPCOpened)) { 446 return false; 447 } 448 449 if (!IsOnBackgroundThread()) { 450 MutexAutoLock lock(mBgThreadMutex); 451 nsresult rv = mBackgroundThread->Dispatch( 452 NewRunnableMethod<const nsCString, const nsCString>( 453 "net::HttpBackgroundChannelParent::" 454 "OnSetClassifierMatchedTrackingInfo", 455 this, 456 &HttpBackgroundChannelParent::OnSetClassifierMatchedTrackingInfo, 457 aLists, aFullHashes), 458 NS_DISPATCH_NORMAL); 459 460 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 461 462 return NS_SUCCEEDED(rv); 463 } 464 465 ClassifierInfo info; 466 info.list() = aLists; 467 info.fullhash() = aFullHashes; 468 469 return SendSetClassifierMatchedTrackingInfo(info); 470 } 471 472 nsISerialEventTarget* HttpBackgroundChannelParent::GetBackgroundTarget() { 473 MOZ_ASSERT(mBackgroundThread); 474 return mBackgroundThread.get(); 475 } 476 477 auto HttpBackgroundChannelParent::AttachStreamFilter( 478 Endpoint<extensions::PStreamFilterParent>&& aParentEndpoint, 479 Endpoint<extensions::PStreamFilterChild>&& aChildEndpoint) 480 -> RefPtr<ChildEndpointPromise> { 481 LOG(("HttpBackgroundChannelParent::AttachStreamFilter [this=%p]\n", this)); 482 MOZ_ASSERT(IsOnBackgroundThread()); 483 484 if (NS_WARN_IF(!mIPCOpened) || 485 !SendAttachStreamFilter(std::move(aParentEndpoint))) { 486 return ChildEndpointPromise::CreateAndReject(false, __func__); 487 } 488 489 return ChildEndpointPromise::CreateAndResolve(std::move(aChildEndpoint), 490 __func__); 491 } 492 493 auto HttpBackgroundChannelParent::DetachStreamFilters() 494 -> RefPtr<GenericPromise> { 495 LOG(("HttpBackgroundChannelParent::DetachStreamFilters [this=%p]\n", this)); 496 if (NS_WARN_IF(!mIPCOpened) || !SendDetachStreamFilters()) { 497 return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); 498 } 499 500 return GenericPromise::CreateAndResolve(true, __func__); 501 } 502 503 void HttpBackgroundChannelParent::ActorDestroy(ActorDestroyReason aWhy) { 504 LOG(("HttpBackgroundChannelParent::ActorDestroy [this=%p]\n", this)); 505 AssertIsInMainProcess(); 506 AssertIsOnBackgroundThread(); 507 508 mIPCOpened = false; 509 510 RefPtr<HttpBackgroundChannelParent> self = this; 511 DebugOnly<nsresult> rv = NS_DispatchToMainThread(NS_NewRunnableFunction( 512 "net::HttpBackgroundChannelParent::ActorDestroy", [self]() { 513 MOZ_ASSERT(NS_IsMainThread()); 514 515 RefPtr<HttpChannelParent> channelParent = 516 std::move(self->mChannelParent); 517 518 if (channelParent) { 519 channelParent->OnBackgroundParentDestroyed(); 520 } 521 })); 522 MOZ_ASSERT(NS_SUCCEEDED(rv)); 523 } 524 525 } // namespace net 526 } // namespace mozilla