HttpBackgroundChannelChild.cpp (16599B)
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 "HttpBackgroundChannelChild.h" 12 13 #include "HttpChannelChild.h" 14 #include "mozilla/ipc/BackgroundChild.h" 15 #include "mozilla/ipc/Endpoint.h" 16 #include "mozilla/ipc/PBackgroundChild.h" 17 #include "mozilla/IntegerPrintfMacros.h" 18 #include "mozilla/net/BackgroundDataBridgeChild.h" 19 #include "nsSocketTransportService2.h" 20 21 using mozilla::ipc::BackgroundChild; 22 using mozilla::ipc::IPCResult; 23 24 namespace mozilla { 25 namespace net { 26 27 // HttpBackgroundChannelChild 28 HttpBackgroundChannelChild::HttpBackgroundChannelChild() = default; 29 30 HttpBackgroundChannelChild::~HttpBackgroundChannelChild() = default; 31 32 nsresult HttpBackgroundChannelChild::Init(HttpChannelChild* aChannelChild) { 33 LOG( 34 ("HttpBackgroundChannelChild::Init [this=%p httpChannel=%p " 35 "channelId=%" PRIu64 "]\n", 36 this, aChannelChild, aChannelChild->ChannelId())); 37 MOZ_ASSERT(OnSocketThread()); 38 NS_ENSURE_ARG(aChannelChild); 39 40 mChannelChild = aChannelChild; 41 42 if (NS_WARN_IF(!CreateBackgroundChannel())) { 43 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 44 // mChannelChild may be nulled already. Use aChannelChild 45 aChannelChild->mCreateBackgroundChannelFailed = true; 46 #endif 47 mChannelChild = nullptr; 48 return NS_ERROR_FAILURE; 49 } 50 51 mFirstODASource = ODA_PENDING; 52 mOnStopRequestCalled = false; 53 return NS_OK; 54 } 55 56 void HttpBackgroundChannelChild::CreateDataBridge( 57 Endpoint<PBackgroundDataBridgeChild>&& aEndpoint) { 58 MOZ_ASSERT(OnSocketThread()); 59 60 if (!mChannelChild) { 61 return; 62 } 63 64 RefPtr<BackgroundDataBridgeChild> dataBridgeChild = 65 new BackgroundDataBridgeChild(this); 66 aEndpoint.Bind(dataBridgeChild); 67 } 68 69 void HttpBackgroundChannelChild::OnChannelClosed() { 70 LOG(("HttpBackgroundChannelChild::OnChannelClosed [this=%p]\n", this)); 71 MOZ_ASSERT(OnSocketThread()); 72 73 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 74 if (mChannelChild) { 75 mChannelChild->mBackgroundChildQueueFinalState = 76 mQueuedRunnables.IsEmpty() ? HttpChannelChild::BCKCHILD_EMPTY 77 : HttpChannelChild::BCKCHILD_NON_EMPTY; 78 } 79 #endif 80 81 // HttpChannelChild is not going to handle any incoming message. 82 mChannelChild = nullptr; 83 84 // Remove pending IPC messages as well. 85 mQueuedRunnables.Clear(); 86 mConsoleReportTask = nullptr; 87 } 88 89 bool HttpBackgroundChannelChild::ChannelClosed() { 90 MOZ_ASSERT(OnSocketThread()); 91 92 return !mChannelChild; 93 } 94 95 void HttpBackgroundChannelChild::OnStartRequestReceived( 96 Maybe<uint32_t> aMultiPartID) { 97 LOG(("HttpBackgroundChannelChild::OnStartRequestReceived [this=%p]\n", this)); 98 MOZ_ASSERT(OnSocketThread()); 99 MOZ_ASSERT(mChannelChild); 100 MOZ_ASSERT(!mStartReceived || *aMultiPartID > 0); 101 102 mStartReceived = true; 103 104 nsTArray<nsCOMPtr<nsIRunnable>> runnables = std::move(mQueuedRunnables); 105 106 for (const auto& event : runnables) { 107 // Note: these runnables call Recv* methods on HttpBackgroundChannelChild 108 // but not the Process* methods on HttpChannelChild. 109 event->Run(); 110 } 111 112 // Ensure no new message is enqueued. 113 MOZ_ASSERT(mQueuedRunnables.IsEmpty()); 114 } 115 116 bool HttpBackgroundChannelChild::CreateBackgroundChannel() { 117 LOG(("HttpBackgroundChannelChild::CreateBackgroundChannel [this=%p]\n", 118 this)); 119 MOZ_ASSERT(OnSocketThread()); 120 MOZ_ASSERT(mChannelChild); 121 122 PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread(); 123 if (NS_WARN_IF(!actorChild)) { 124 return false; 125 } 126 127 const uint64_t channelId = mChannelChild->ChannelId(); 128 if (!actorChild->SendPHttpBackgroundChannelConstructor(this, channelId)) { 129 return false; 130 } 131 132 mChannelChild->OnBackgroundChildReady(this); 133 return true; 134 } 135 136 IPCResult HttpBackgroundChannelChild::RecvOnAfterLastPart( 137 const nsresult& aStatus) { 138 LOG(("HttpBackgroundChannelChild::RecvOnAfterLastPart [this=%p]\n", this)); 139 MOZ_ASSERT(OnSocketThread()); 140 141 if (NS_WARN_IF(!mChannelChild)) { 142 return IPC_OK(); 143 } 144 145 mChannelChild->ProcessOnAfterLastPart(aStatus); 146 return IPC_OK(); 147 } 148 149 IPCResult HttpBackgroundChannelChild::RecvOnProgress( 150 const int64_t& aProgress, const int64_t& aProgressMax) { 151 LOG(("HttpBackgroundChannelChild::RecvOnProgress [this=%p]\n", this)); 152 MOZ_ASSERT(OnSocketThread()); 153 154 if (NS_WARN_IF(!mChannelChild)) { 155 return IPC_OK(); 156 } 157 158 mChannelChild->ProcessOnProgress(aProgress, aProgressMax); 159 return IPC_OK(); 160 } 161 162 IPCResult HttpBackgroundChannelChild::RecvOnStatus(const nsresult& aStatus) { 163 LOG(("HttpBackgroundChannelChild::RecvOnStatus [this=%p]\n", this)); 164 MOZ_ASSERT(OnSocketThread()); 165 166 if (NS_WARN_IF(!mChannelChild)) { 167 return IPC_OK(); 168 } 169 170 mChannelChild->ProcessOnStatus(aStatus); 171 return IPC_OK(); 172 } 173 174 bool HttpBackgroundChannelChild::IsWaitingOnStartRequest() { 175 MOZ_ASSERT(OnSocketThread()); 176 177 // Need to wait for OnStartRequest if it is sent by 178 // parent process but not received by content process. 179 return !mStartReceived; 180 } 181 182 // PHttpBackgroundChannelChild 183 IPCResult HttpBackgroundChannelChild::RecvOnStartRequest( 184 const nsHttpResponseHead& aResponseHead, const bool& aUseResponseHead, 185 const nsHttpHeaderArray& aRequestHeaders, 186 const HttpChannelOnStartRequestArgs& aArgs, 187 const HttpChannelAltDataStream& aAltData, 188 const TimeStamp& aOnStartRequestStart) { 189 LOG(( 190 "HttpBackgroundChannelChild::RecvOnStartRequest [this=%p, status=%" PRIx32 191 "]\n", 192 this, static_cast<uint32_t>(aArgs.channelStatus()))); 193 MOZ_ASSERT(OnSocketThread()); 194 195 if (NS_WARN_IF(!mChannelChild)) { 196 return IPC_OK(); 197 } 198 199 mFirstODASource = 200 aArgs.dataFromSocketProcess() ? ODA_FROM_SOCKET : ODA_FROM_PARENT; 201 202 mChannelChild->ProcessOnStartRequest(aResponseHead, aUseResponseHead, 203 aRequestHeaders, aArgs, aAltData, 204 aOnStartRequestStart); 205 // Allow to queue other runnable since OnStartRequest Event already hits the 206 // child's mEventQ. 207 OnStartRequestReceived(aArgs.multiPartID()); 208 209 return IPC_OK(); 210 } 211 212 IPCResult HttpBackgroundChannelChild::RecvOnTransportAndData( 213 const nsresult& aChannelStatus, const nsresult& aTransportStatus, 214 const uint64_t& aOffset, const uint32_t& aCount, const nsACString& aData, 215 const bool& aDataFromSocketProcess, 216 const TimeStamp& aOnDataAvailableStart) { 217 RefPtr<HttpBackgroundChannelChild> self = this; 218 std::function<void()> callProcessOnTransportAndData = 219 [self, aChannelStatus, aTransportStatus, aOffset, aCount, 220 data = nsCString(aData), aDataFromSocketProcess, 221 aOnDataAvailableStart]() { 222 LOG( 223 ("HttpBackgroundChannelChild::RecvOnTransportAndData [this=%p, " 224 "aDataFromSocketProcess=%d, mFirstODASource=%d]\n", 225 self.get(), aDataFromSocketProcess, self->mFirstODASource)); 226 MOZ_ASSERT(OnSocketThread()); 227 228 if (NS_WARN_IF(!self->mChannelChild)) { 229 return; 230 } 231 232 if (((self->mFirstODASource == ODA_FROM_SOCKET) && 233 !aDataFromSocketProcess) || 234 ((self->mFirstODASource == ODA_FROM_PARENT) && 235 aDataFromSocketProcess)) { 236 return; 237 } 238 239 // The HttpTransactionChild in socket process may not know that this 240 // request is cancelled or failed due to the IPC delay. In this case, we 241 // should not forward ODA to HttpChannelChild. 242 nsresult channelStatus; 243 self->mChannelChild->GetStatus(&channelStatus); 244 if (NS_FAILED(channelStatus)) { 245 return; 246 } 247 248 self->mChannelChild->ProcessOnTransportAndData( 249 aChannelStatus, aTransportStatus, aOffset, aCount, data, 250 aOnDataAvailableStart); 251 }; 252 253 // Bug 1641336: Race only happens if the data is from socket process. 254 if (IsWaitingOnStartRequest()) { 255 LOG((" > pending until OnStartRequest [offset=%" PRIu64 " count=%" PRIu32 256 "]\n", 257 aOffset, aCount)); 258 259 mQueuedRunnables.AppendElement(NS_NewRunnableFunction( 260 "HttpBackgroundChannelChild::RecvOnTransportAndData", 261 std::move(callProcessOnTransportAndData))); 262 return IPC_OK(); 263 } 264 265 callProcessOnTransportAndData(); 266 return IPC_OK(); 267 } 268 269 IPCResult HttpBackgroundChannelChild::RecvOnStopRequest( 270 const nsresult& aChannelStatus, const ResourceTimingStructArgs& aTiming, 271 const TimeStamp& aLastActiveTabOptHit, 272 const nsHttpHeaderArray& aResponseTrailers, 273 nsTArray<ConsoleReportCollected>&& aConsoleReports, 274 const bool& aFromSocketProcess, const TimeStamp& aOnStopRequestStart) { 275 LOG( 276 ("HttpBackgroundChannelChild::RecvOnStopRequest [this=%p, " 277 "aFromSocketProcess=%d, mFirstODASource=%d]\n", 278 this, aFromSocketProcess, mFirstODASource)); 279 MOZ_ASSERT(gSocketTransportService); 280 MOZ_ASSERT(gSocketTransportService->IsOnCurrentThreadInfallible()); 281 282 // It's enough to set this from (just before) OnStopRequest notification, 283 // since we don't need this value sooner than a channel was done loading - 284 // everything this timestamp affects takes place only after a channel's 285 // OnStopRequest. 286 nsHttp::SetLastActiveTabLoadOptimizationHit(aLastActiveTabOptHit); 287 288 if (NS_WARN_IF(!mChannelChild)) { 289 return IPC_OK(); 290 } 291 292 if (IsWaitingOnStartRequest()) { 293 LOG((" > pending until OnStartRequest [status=%" PRIx32 "]\n", 294 static_cast<uint32_t>(aChannelStatus))); 295 296 RefPtr<HttpBackgroundChannelChild> self = this; 297 298 nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction( 299 "HttpBackgroundChannelChild::RecvOnStopRequest", 300 [self, aChannelStatus, aTiming, aLastActiveTabOptHit, aResponseTrailers, 301 consoleReports = CopyableTArray{std::move(aConsoleReports)}, 302 aFromSocketProcess, aOnStopRequestStart]() mutable { 303 self->RecvOnStopRequest(aChannelStatus, aTiming, aLastActiveTabOptHit, 304 aResponseTrailers, std::move(consoleReports), 305 aFromSocketProcess, aOnStopRequestStart); 306 }); 307 308 mQueuedRunnables.AppendElement(task.forget()); 309 return IPC_OK(); 310 } 311 312 if (mFirstODASource != ODA_FROM_SOCKET) { 313 if (!aFromSocketProcess) { 314 mOnStopRequestCalled = true; 315 mChannelChild->ProcessOnStopRequest( 316 aChannelStatus, aTiming, aResponseTrailers, 317 std::move(aConsoleReports), false, aOnStopRequestStart); 318 } 319 return IPC_OK(); 320 } 321 322 MOZ_ASSERT(mFirstODASource == ODA_FROM_SOCKET); 323 324 if (aFromSocketProcess) { 325 MOZ_ASSERT(!mOnStopRequestCalled); 326 mOnStopRequestCalled = true; 327 mChannelChild->ProcessOnStopRequest( 328 aChannelStatus, aTiming, aResponseTrailers, std::move(aConsoleReports), 329 true, aOnStopRequestStart); 330 if (mConsoleReportTask) { 331 mConsoleReportTask(); 332 mConsoleReportTask = nullptr; 333 } 334 return IPC_OK(); 335 } 336 337 return IPC_OK(); 338 } 339 340 IPCResult HttpBackgroundChannelChild::RecvOnConsoleReport( 341 nsTArray<ConsoleReportCollected>&& aConsoleReports) { 342 LOG(("HttpBackgroundChannelChild::RecvOnConsoleReport [this=%p]\n", this)); 343 MOZ_ASSERT(mFirstODASource == ODA_FROM_SOCKET); 344 MOZ_ASSERT(gSocketTransportService); 345 MOZ_ASSERT(gSocketTransportService->IsOnCurrentThreadInfallible()); 346 347 if (IsWaitingOnStartRequest()) { 348 LOG((" > pending until OnStartRequest\n")); 349 350 RefPtr<HttpBackgroundChannelChild> self = this; 351 352 nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction( 353 "HttpBackgroundChannelChild::RecvOnConsoleReport", 354 [self, consoleReports = 355 CopyableTArray{std::move(aConsoleReports)}]() mutable { 356 self->RecvOnConsoleReport(std::move(consoleReports)); 357 }); 358 359 mQueuedRunnables.AppendElement(task.forget()); 360 return IPC_OK(); 361 } 362 363 if (mOnStopRequestCalled) { 364 mChannelChild->ProcessOnConsoleReport(std::move(aConsoleReports)); 365 } else { 366 RefPtr<HttpBackgroundChannelChild> self = this; 367 mConsoleReportTask = [self, consoleReports = CopyableTArray{ 368 std::move(aConsoleReports)}]() mutable { 369 self->mChannelChild->ProcessOnConsoleReport(std::move(consoleReports)); 370 }; 371 } 372 373 return IPC_OK(); 374 } 375 376 IPCResult HttpBackgroundChannelChild::RecvNotifyClassificationFlags( 377 const uint32_t& aClassificationFlags, const bool& aIsThirdParty) { 378 LOG( 379 ("HttpBackgroundChannelChild::RecvNotifyClassificationFlags " 380 "classificationFlags=%" PRIu32 ", thirdparty=%d [this=%p]\n", 381 aClassificationFlags, static_cast<int>(aIsThirdParty), this)); 382 MOZ_ASSERT(OnSocketThread()); 383 384 if (NS_WARN_IF(!mChannelChild)) { 385 return IPC_OK(); 386 } 387 388 // NotifyClassificationFlags has no order dependency to OnStartRequest. 389 // It this be handled as soon as possible 390 mChannelChild->ProcessNotifyClassificationFlags(aClassificationFlags, 391 aIsThirdParty); 392 393 return IPC_OK(); 394 } 395 396 IPCResult HttpBackgroundChannelChild::RecvSetClassifierMatchedInfo( 397 const ClassifierInfo& info) { 398 LOG(("HttpBackgroundChannelChild::RecvSetClassifierMatchedInfo [this=%p]\n", 399 this)); 400 MOZ_ASSERT(OnSocketThread()); 401 402 if (NS_WARN_IF(!mChannelChild)) { 403 return IPC_OK(); 404 } 405 406 // SetClassifierMatchedInfo has no order dependency to OnStartRequest. 407 // It this be handled as soon as possible 408 mChannelChild->ProcessSetClassifierMatchedInfo(info.list(), info.provider(), 409 info.fullhash()); 410 411 return IPC_OK(); 412 } 413 414 IPCResult HttpBackgroundChannelChild::RecvSetClassifierMatchedTrackingInfo( 415 const ClassifierInfo& info) { 416 LOG( 417 ("HttpBackgroundChannelChild::RecvSetClassifierMatchedTrackingInfo " 418 "[this=%p]\n", 419 this)); 420 MOZ_ASSERT(OnSocketThread()); 421 422 if (NS_WARN_IF(!mChannelChild)) { 423 return IPC_OK(); 424 } 425 426 // SetClassifierMatchedTrackingInfo has no order dependency to 427 // OnStartRequest. It this be handled as soon as possible 428 mChannelChild->ProcessSetClassifierMatchedTrackingInfo(info.list(), 429 info.fullhash()); 430 431 return IPC_OK(); 432 } 433 434 IPCResult HttpBackgroundChannelChild::RecvAttachStreamFilter( 435 Endpoint<extensions::PStreamFilterParent>&& aEndpoint) { 436 LOG(("HttpBackgroundChannelChild::RecvAttachStreamFilter [this=%p]\n", this)); 437 MOZ_ASSERT(OnSocketThread()); 438 439 if (NS_WARN_IF(!mChannelChild)) { 440 return IPC_OK(); 441 } 442 443 mChannelChild->ProcessAttachStreamFilter(std::move(aEndpoint)); 444 return IPC_OK(); 445 } 446 447 IPCResult HttpBackgroundChannelChild::RecvDetachStreamFilters() { 448 LOG(("HttpBackgroundChannelChild::RecvDetachStreamFilters [this=%p]\n", 449 this)); 450 MOZ_ASSERT(OnSocketThread()); 451 452 if (NS_WARN_IF(!mChannelChild)) { 453 return IPC_OK(); 454 } 455 456 mChannelChild->ProcessDetachStreamFilters(); 457 return IPC_OK(); 458 } 459 460 void HttpBackgroundChannelChild::ActorDestroy(ActorDestroyReason aWhy) { 461 LOG(("HttpBackgroundChannelChild::ActorDestroy[this=%p]\n", this)); 462 // This function might be called during shutdown phase, so OnSocketThread() 463 // might return false even on STS thread. Use IsOnCurrentThreadInfallible() 464 // to get correct information. 465 MOZ_ASSERT(gSocketTransportService); 466 MOZ_ASSERT(gSocketTransportService->IsOnCurrentThreadInfallible()); 467 468 // Ensure all IPC messages received before ActorDestroy can be 469 // handled correctly. If there is any pending IPC message, destroyed 470 // mChannelChild until those messages are flushed. 471 // If background channel is not closed by normal IPDL actor deletion, 472 // remove the HttpChannelChild reference and notify background channel 473 // destroyed immediately. 474 if (aWhy == Deletion && !mQueuedRunnables.IsEmpty()) { 475 LOG((" > pending until queued messages are flushed\n")); 476 RefPtr<HttpBackgroundChannelChild> self = this; 477 mQueuedRunnables.AppendElement(NS_NewRunnableFunction( 478 "HttpBackgroundChannelChild::ActorDestroy", [self]() { 479 MOZ_ASSERT(OnSocketThread()); 480 RefPtr<HttpChannelChild> channelChild = 481 std::move(self->mChannelChild); 482 483 if (channelChild) { 484 channelChild->OnBackgroundChildDestroyed(self); 485 } 486 })); 487 return; 488 } 489 490 if (mChannelChild) { 491 RefPtr<HttpChannelChild> channelChild = std::move(mChannelChild); 492 493 channelChild->OnBackgroundChildDestroyed(this); 494 } 495 } 496 497 } // namespace net 498 } // namespace mozilla