tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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