tor-browser

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

WebSocketConnectionParent.cpp (6093B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set sw=2 ts=8 et ft=cpp : */
      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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "WebSocketLog.h"
      8 #include "WebSocketConnectionParent.h"
      9 
     10 #include "nsIHttpChannelInternal.h"
     11 #include "nsITransportSecurityInfo.h"
     12 #include "nsSerializationHelper.h"
     13 #include "nsThreadUtils.h"
     14 #include "WebSocketConnectionListener.h"
     15 
     16 namespace mozilla {
     17 namespace net {
     18 
     19 NS_IMPL_ISUPPORTS0(WebSocketConnectionParent)
     20 
     21 WebSocketConnectionParent::WebSocketConnectionParent(
     22    nsIHttpUpgradeListener* aListener)
     23    : mUpgradeListener(aListener),
     24      mBackgroundThread(GetCurrentSerialEventTarget()) {
     25  LOG(("WebSocketConnectionParent ctor %p\n", this));
     26  MOZ_ASSERT(mUpgradeListener);
     27 }
     28 
     29 WebSocketConnectionParent::~WebSocketConnectionParent() {
     30  LOG(("WebSocketConnectionParent dtor %p\n", this));
     31 }
     32 
     33 mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnTransportAvailable(
     34    nsITransportSecurityInfo* aSecurityInfo) {
     35  LOG(("WebSocketConnectionParent::RecvOnTransportAvailable %p\n", this));
     36  MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread());
     37 
     38  if (aSecurityInfo) {
     39    MutexAutoLock lock(mMutex);
     40    mSecurityInfo = aSecurityInfo;
     41  }
     42 
     43  if (mUpgradeListener) {
     44    (void)mUpgradeListener->OnWebSocketConnectionAvailable(this);
     45    mUpgradeListener = nullptr;
     46  }
     47  return IPC_OK();
     48 }
     49 
     50 mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnError(
     51    const nsresult& aStatus) {
     52  LOG(("WebSocketConnectionParent::RecvOnError %p\n", this));
     53  MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread());
     54 
     55  MOZ_ASSERT(mListener);
     56  mListener->OnError(aStatus);
     57  return IPC_OK();
     58 }
     59 
     60 mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnUpgradeFailed(
     61    const nsresult& aReason) {
     62  MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread());
     63 
     64  if (mUpgradeListener) {
     65    (void)mUpgradeListener->OnUpgradeFailed(aReason);
     66    mUpgradeListener = nullptr;
     67  }
     68  return IPC_OK();
     69 }
     70 
     71 mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnTCPClosed() {
     72  LOG(("WebSocketConnectionParent::RecvOnTCPClosed %p\n", this));
     73  MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread());
     74 
     75  MOZ_ASSERT(mListener);
     76  mListener->OnTCPClosed();
     77  return IPC_OK();
     78 }
     79 
     80 mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnDataReceived(
     81    nsTArray<uint8_t>&& aData) {
     82  LOG(("WebSocketConnectionParent::RecvOnDataReceived %p\n", this));
     83  MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread());
     84 
     85  MOZ_ASSERT(mListener);
     86  uint8_t* buffer = const_cast<uint8_t*>(aData.Elements());
     87  nsresult rv = mListener->OnDataReceived(buffer, aData.Length());
     88  if (NS_FAILED(rv)) {
     89    mListener->OnError(rv);
     90  }
     91 
     92  return IPC_OK();
     93 }
     94 
     95 void WebSocketConnectionParent::ActorDestroy(ActorDestroyReason aWhy) {
     96  LOG(("WebSocketConnectionParent::ActorDestroy %p aWhy=%d\n", this, aWhy));
     97  if (!mClosed) {
     98    // Treat this as an error when IPC is closed before
     99    // WebSocketConnectionParent::Close() is called.
    100    RefPtr<WebSocketConnectionListener> listener;
    101    listener.swap(mListener);
    102    if (listener) {
    103      listener->OnError(NS_ERROR_FAILURE);
    104    }
    105  }
    106  mBackgroundThread->Dispatch(NS_NewRunnableFunction(
    107      "WebSocketConnectionParent::DefereredDestroy", [self = RefPtr{this}]() {
    108        LOG(("WebSocketConnectionParent::DefereredDestroy"));
    109      }));
    110 };
    111 
    112 nsresult WebSocketConnectionParent::Init(
    113    WebSocketConnectionListener* aListener) {
    114  NS_ENSURE_ARG_POINTER(aListener);
    115 
    116  mListener = aListener;
    117  return NS_OK;
    118 }
    119 
    120 void WebSocketConnectionParent::GetIoTarget(nsIEventTarget** aTarget) {
    121  nsCOMPtr<nsIEventTarget> target = mBackgroundThread;
    122  return target.forget(aTarget);
    123 }
    124 
    125 void WebSocketConnectionParent::Close() {
    126  LOG(("WebSocketConnectionParent::Close %p\n", this));
    127 
    128  mClosed = true;
    129 
    130  auto task = [self = RefPtr{this}]() {
    131    self->PWebSocketConnectionParent::Close();
    132  };
    133 
    134  if (mBackgroundThread->IsOnCurrentThread()) {
    135    task();
    136  } else {
    137    mBackgroundThread->Dispatch(NS_NewRunnableFunction(
    138        "WebSocketConnectionParent::Close", std::move(task)));
    139  }
    140 }
    141 
    142 nsresult WebSocketConnectionParent::WriteOutputData(
    143    const uint8_t* aHdrBuf, uint32_t aHdrBufLength, const uint8_t* aPayloadBuf,
    144    uint32_t aPayloadBufLength) {
    145  LOG(("WebSocketConnectionParent::WriteOutputData %p", this));
    146  MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread());
    147 
    148  if (!CanSend()) {
    149    return NS_ERROR_NOT_AVAILABLE;
    150  }
    151 
    152  nsTArray<uint8_t> data;
    153  data.AppendElements(aHdrBuf, aHdrBufLength);
    154  data.AppendElements(aPayloadBuf, aPayloadBufLength);
    155  return SendWriteOutputData(data) ? NS_OK : NS_ERROR_FAILURE;
    156 }
    157 
    158 nsresult WebSocketConnectionParent::StartReading() {
    159  LOG(("WebSocketConnectionParent::StartReading %p\n", this));
    160 
    161  RefPtr<WebSocketConnectionParent> self = this;
    162  auto task = [self{std::move(self)}]() {
    163    if (!self->CanSend()) {
    164      if (self->mListener) {
    165        self->mListener->OnError(NS_ERROR_NOT_AVAILABLE);
    166      }
    167      return;
    168    }
    169 
    170    (void)self->SendStartReading();
    171  };
    172 
    173  if (mBackgroundThread->IsOnCurrentThread()) {
    174    task();
    175  } else {
    176    mBackgroundThread->Dispatch(NS_NewRunnableFunction(
    177        "WebSocketConnectionParent::SendStartReading", std::move(task)));
    178  }
    179 
    180  return NS_OK;
    181 }
    182 
    183 void WebSocketConnectionParent::DrainSocketData() {
    184  LOG(("WebSocketConnectionParent::DrainSocketData %p\n", this));
    185  MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread());
    186 
    187  if (!CanSend()) {
    188    MOZ_ASSERT(mListener);
    189    mListener->OnError(NS_ERROR_NOT_AVAILABLE);
    190 
    191    return;
    192  }
    193 
    194  (void)SendDrainSocketData();
    195 }
    196 
    197 nsresult WebSocketConnectionParent::GetSecurityInfo(
    198    nsITransportSecurityInfo** aSecurityInfo) {
    199  LOG(("WebSocketConnectionParent::GetSecurityInfo() %p\n", this));
    200  MOZ_ASSERT(NS_IsMainThread());
    201 
    202  NS_ENSURE_ARG_POINTER(aSecurityInfo);
    203 
    204  MutexAutoLock lock(mMutex);
    205  NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
    206  return NS_OK;
    207 }
    208 
    209 }  // namespace net
    210 }  // namespace mozilla