tor-browser

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

AltDataOutputStreamChild.cpp (5188B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/net/AltDataOutputStreamChild.h"
      8 #include "nsIInputStream.h"
      9 #include "nsStreamUtils.h"
     10 
     11 namespace mozilla {
     12 namespace net {
     13 
     14 NS_IMPL_ADDREF(AltDataOutputStreamChild)
     15 
     16 NS_IMETHODIMP_(MozExternalRefCountType) AltDataOutputStreamChild::Release() {
     17  MOZ_ASSERT(0 != mRefCnt, "dup release");
     18  MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
     19  --mRefCnt;
     20  NS_LOG_RELEASE(this, mRefCnt, "AltDataOutputStreamChild");
     21 
     22  if (mRefCnt == 1 && mIPCOpen) {
     23    // The only reference left is the IPDL one. After the parent replies back
     24    // with a DeleteSelf message, the child will call Send__delete__(this),
     25    // decrementing the ref count and triggering the destructor.
     26    SendDeleteSelf();
     27    return 1;
     28  }
     29 
     30  if (mRefCnt == 0) {
     31    mRefCnt = 1; /* stabilize */
     32    delete this;
     33    return 0;
     34  }
     35  return mRefCnt;
     36 }
     37 
     38 NS_INTERFACE_MAP_BEGIN(AltDataOutputStreamChild)
     39  NS_INTERFACE_MAP_ENTRY(nsIAsyncOutputStream)
     40  NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
     41  NS_INTERFACE_MAP_ENTRY(nsISupports)
     42 NS_INTERFACE_MAP_END
     43 
     44 AltDataOutputStreamChild::AltDataOutputStreamChild()
     45    : mIPCOpen(false), mError(NS_OK), mCallbackFlags(0) {
     46  MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
     47 }
     48 
     49 void AltDataOutputStreamChild::AddIPDLReference() {
     50  MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
     51  mIPCOpen = true;
     52  AddRef();
     53 }
     54 
     55 void AltDataOutputStreamChild::ReleaseIPDLReference() {
     56  MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
     57  mIPCOpen = false;
     58 
     59  if (mCallback) {
     60    NotifyListener();
     61  }
     62 
     63  Release();
     64 }
     65 
     66 bool AltDataOutputStreamChild::WriteDataInChunks(
     67    const nsDependentCSubstring& data) {
     68  const size_t kChunkSize = 128 * 1024;
     69  size_t next = std::min(data.Length(), kChunkSize);
     70  for (size_t i = 0; i < data.Length();
     71       i = next, next = std::min(data.Length(), next + kChunkSize)) {
     72    nsCString chunk(Substring(data, i, kChunkSize));
     73    if (mIPCOpen && !SendWriteData(chunk)) {
     74      mIPCOpen = false;
     75      return false;
     76    }
     77  }
     78  return true;
     79 }
     80 
     81 NS_IMETHODIMP
     82 AltDataOutputStreamChild::Close() { return CloseWithStatus(NS_OK); }
     83 
     84 NS_IMETHODIMP
     85 AltDataOutputStreamChild::Flush() {
     86  if (!mIPCOpen) {
     87    return NS_ERROR_NOT_AVAILABLE;
     88  }
     89  if (NS_FAILED(mError)) {
     90    return mError;
     91  }
     92 
     93  // This is a no-op
     94  return NS_OK;
     95 }
     96 
     97 NS_IMETHODIMP
     98 AltDataOutputStreamChild::StreamStatus() {
     99  if (!mIPCOpen) {
    100    return NS_ERROR_NOT_AVAILABLE;
    101  }
    102  return mError;
    103 }
    104 
    105 NS_IMETHODIMP
    106 AltDataOutputStreamChild::Write(const char* aBuf, uint32_t aCount,
    107                                uint32_t* _retval) {
    108  if (!mIPCOpen) {
    109    return NS_ERROR_NOT_AVAILABLE;
    110  }
    111  if (NS_FAILED(mError)) {
    112    return mError;
    113  }
    114  if (WriteDataInChunks(nsDependentCSubstring(aBuf, aCount))) {
    115    *_retval = aCount;
    116    return NS_OK;
    117  }
    118  return NS_ERROR_FAILURE;
    119 }
    120 
    121 NS_IMETHODIMP
    122 AltDataOutputStreamChild::WriteFrom(nsIInputStream* aFromStream,
    123                                    uint32_t aCount, uint32_t* _retval) {
    124  return NS_ERROR_NOT_IMPLEMENTED;
    125 }
    126 
    127 NS_IMETHODIMP
    128 AltDataOutputStreamChild::WriteSegments(nsReadSegmentFun aReader,
    129                                        void* aClosure, uint32_t aCount,
    130                                        uint32_t* _retval) {
    131  return NS_ERROR_NOT_IMPLEMENTED;
    132 }
    133 
    134 NS_IMETHODIMP
    135 AltDataOutputStreamChild::IsNonBlocking(bool* _retval) {
    136  *_retval = false;
    137  return NS_OK;
    138 }
    139 
    140 mozilla::ipc::IPCResult AltDataOutputStreamChild::RecvError(
    141    const nsresult& err) {
    142  mError = err;
    143  return IPC_OK();
    144 }
    145 
    146 mozilla::ipc::IPCResult AltDataOutputStreamChild::RecvDeleteSelf() {
    147  PAltDataOutputStreamChild::Send__delete__(this);
    148  return IPC_OK();
    149 }
    150 
    151 // nsIAsyncOutputStream
    152 
    153 NS_IMETHODIMP
    154 AltDataOutputStreamChild::CloseWithStatus(nsresult aStatus) {
    155  if (!mIPCOpen) {
    156    return NS_ERROR_NOT_AVAILABLE;
    157  }
    158  if (NS_FAILED(mError)) {
    159    return mError;
    160  }
    161  (void)SendClose(aStatus);
    162 
    163  return NS_OK;
    164 }
    165 
    166 NS_IMETHODIMP
    167 AltDataOutputStreamChild::AsyncWait(nsIOutputStreamCallback* aCallback,
    168                                    uint32_t aFlags, uint32_t aRequestedCount,
    169                                    nsIEventTarget* aEventTarget) {
    170  mCallback = aCallback;
    171  mCallbackFlags = aFlags;
    172  mCallbackTarget = aEventTarget;
    173 
    174  if (!mCallback) {
    175    return NS_OK;
    176  }
    177 
    178  // The stream is blocking so it is writable at any time
    179  if (!mIPCOpen || !(aFlags & WAIT_CLOSURE_ONLY)) {
    180    NotifyListener();
    181  }
    182 
    183  return NS_OK;
    184 }
    185 
    186 void AltDataOutputStreamChild::NotifyListener() {
    187  MOZ_ASSERT(mCallback);
    188 
    189  if (!mCallbackTarget) {
    190    mCallbackTarget = GetMainThreadSerialEventTarget();
    191  }
    192 
    193  nsCOMPtr<nsIOutputStreamCallback> asyncCallback =
    194      NS_NewOutputStreamReadyEvent(mCallback, mCallbackTarget);
    195 
    196  mCallback = nullptr;
    197  mCallbackTarget = nullptr;
    198 
    199  asyncCallback->OnOutputStreamReady(this);
    200 }
    201 
    202 }  // namespace net
    203 }  // namespace mozilla