tor-browser

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

InputStreamUtils.cpp (7174B)


      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 "InputStreamUtils.h"
      8 
      9 #include "nsIIPCSerializableInputStream.h"
     10 
     11 #include "mozilla/Assertions.h"
     12 #include "mozilla/dom/File.h"
     13 #include "mozilla/dom/quota/DecryptingInputStream_impl.h"
     14 #include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
     15 #include "mozilla/ipc/DataPipe.h"
     16 #include "mozilla/InputStreamLengthHelper.h"
     17 #include "mozilla/RemoteLazyInputStream.h"
     18 #include "mozilla/RemoteLazyInputStreamChild.h"
     19 #include "mozilla/RemoteLazyInputStreamStorage.h"
     20 #include "mozilla/SlicedInputStream.h"
     21 #include "mozilla/InputStreamLengthWrapper.h"
     22 #include "nsBufferedStreams.h"
     23 #include "nsComponentManagerUtils.h"
     24 #include "nsDebug.h"
     25 #include "nsFileStreams.h"
     26 #include "nsIAsyncInputStream.h"
     27 #include "nsIAsyncOutputStream.h"
     28 #include "nsID.h"
     29 #include "nsIMIMEInputStream.h"
     30 #include "nsIMultiplexInputStream.h"
     31 #include "nsIPipe.h"
     32 #include "nsMIMEInputStream.h"
     33 #include "nsMultiplexInputStream.h"
     34 #include "nsNetCID.h"
     35 #include "nsStreamUtils.h"
     36 #include "nsStringStream.h"
     37 #include "nsXULAppAPI.h"
     38 
     39 using namespace mozilla;
     40 using namespace mozilla::dom;
     41 
     42 namespace mozilla {
     43 namespace ipc {
     44 
     45 void InputStreamHelper::SerializedComplexity(nsIInputStream* aInputStream,
     46                                             uint32_t aMaxSize,
     47                                             uint32_t* aSizeUsed,
     48                                             uint32_t* aPipes,
     49                                             uint32_t* aTransferables) {
     50  MOZ_ASSERT(aInputStream);
     51 
     52  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
     53      do_QueryInterface(aInputStream);
     54  if (!serializable) {
     55    MOZ_CRASH("Input stream is not serializable!");
     56  }
     57 
     58  serializable->SerializedComplexity(aMaxSize, aSizeUsed, aPipes,
     59                                     aTransferables);
     60 }
     61 
     62 void InputStreamHelper::SerializeInputStream(nsIInputStream* aInputStream,
     63                                             InputStreamParams& aParams,
     64                                             uint32_t aMaxSize,
     65                                             uint32_t* aSizeUsed) {
     66  MOZ_ASSERT(aInputStream);
     67 
     68  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
     69      do_QueryInterface(aInputStream);
     70  if (!serializable) {
     71    MOZ_CRASH("Input stream is not serializable!");
     72  }
     73 
     74  serializable->Serialize(aParams, aMaxSize, aSizeUsed);
     75 
     76  if (aParams.type() == InputStreamParams::T__None) {
     77    MOZ_CRASH("Serialize failed!");
     78  }
     79 }
     80 
     81 void InputStreamHelper::SerializeInputStreamAsPipe(nsIInputStream* aInputStream,
     82                                                   InputStreamParams& aParams) {
     83  MOZ_ASSERT(aInputStream);
     84 
     85  // Let's try to take the length using InputStreamLengthHelper. If the length
     86  // cannot be taken synchronously, and its length is needed, the stream needs
     87  // to be fully copied in memory on the deserialization side.
     88  int64_t length;
     89  if (!InputStreamLengthHelper::GetSyncLength(aInputStream, &length)) {
     90    length = -1;
     91  }
     92 
     93  RefPtr<DataPipeSender> sender;
     94  RefPtr<DataPipeReceiver> receiver;
     95  nsresult rv = NewDataPipe(kDefaultDataPipeCapacity, getter_AddRefs(sender),
     96                            getter_AddRefs(receiver));
     97  if (NS_WARN_IF(NS_FAILED(rv))) {
     98    return;
     99  }
    100 
    101  nsCOMPtr<nsIEventTarget> target =
    102      do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
    103 
    104  rv =
    105      NS_AsyncCopy(aInputStream, sender, target, NS_ASYNCCOPY_VIA_WRITESEGMENTS,
    106                   kDefaultDataPipeCapacity, nullptr, nullptr);
    107  if (NS_WARN_IF(NS_FAILED(rv))) {
    108    return;
    109  }
    110 
    111  aParams = DataPipeReceiverStreamParams(WrapNotNull(receiver));
    112  if (length != -1) {
    113    aParams = InputStreamLengthWrapperParams(aParams, length, false);
    114  }
    115 }
    116 
    117 already_AddRefed<nsIInputStream> InputStreamHelper::DeserializeInputStream(
    118    const InputStreamParams& aParams) {
    119  if (aParams.type() == InputStreamParams::TRemoteLazyInputStreamParams) {
    120    const RemoteLazyInputStreamParams& params =
    121        aParams.get_RemoteLazyInputStreamParams();
    122 
    123    // If the RemoteLazyInputStream already has an internal stream, unwrap it.
    124    // This is required as some code unfortunately depends on the precise
    125    // topology of received streams, and cannot handle being passed a
    126    // `RemoteLazyInputStream` in the parent process.
    127    nsCOMPtr<nsIInputStream> innerStream;
    128    if (XRE_IsParentProcess() &&
    129        NS_SUCCEEDED(
    130            params.stream()->TakeInternalStream(getter_AddRefs(innerStream)))) {
    131      return innerStream.forget();
    132    }
    133    return do_AddRef(params.stream().get());
    134  }
    135 
    136  if (aParams.type() == InputStreamParams::TDataPipeReceiverStreamParams) {
    137    const DataPipeReceiverStreamParams& pipeParams =
    138        aParams.get_DataPipeReceiverStreamParams();
    139    return do_AddRef(pipeParams.pipe().get());
    140  }
    141 
    142  nsCOMPtr<nsIIPCSerializableInputStream> serializable;
    143 
    144  switch (aParams.type()) {
    145    case InputStreamParams::TStringInputStreamParams: {
    146      nsCOMPtr<nsIInputStream> stream;
    147      NS_NewCStringInputStream(getter_AddRefs(stream), ""_ns);
    148      serializable = do_QueryInterface(stream);
    149    } break;
    150 
    151    case InputStreamParams::TFileInputStreamParams: {
    152      nsCOMPtr<nsIFileInputStream> stream;
    153      nsFileInputStream::Create(NS_GET_IID(nsIFileInputStream),
    154                                getter_AddRefs(stream));
    155      serializable = do_QueryInterface(stream);
    156    } break;
    157 
    158    case InputStreamParams::TBufferedInputStreamParams: {
    159      nsCOMPtr<nsIBufferedInputStream> stream;
    160      nsBufferedInputStream::Create(NS_GET_IID(nsIBufferedInputStream),
    161                                    getter_AddRefs(stream));
    162      serializable = do_QueryInterface(stream);
    163    } break;
    164 
    165    case InputStreamParams::TMIMEInputStreamParams: {
    166      nsCOMPtr<nsIMIMEInputStream> stream;
    167      nsMIMEInputStreamConstructor(NS_GET_IID(nsIMIMEInputStream),
    168                                   getter_AddRefs(stream));
    169      serializable = do_QueryInterface(stream);
    170    } break;
    171 
    172    case InputStreamParams::TMultiplexInputStreamParams: {
    173      serializable = new nsMultiplexInputStream();
    174    } break;
    175 
    176    case InputStreamParams::TSlicedInputStreamParams:
    177      serializable = new SlicedInputStream();
    178      break;
    179 
    180    case InputStreamParams::TInputStreamLengthWrapperParams:
    181      serializable = new InputStreamLengthWrapper();
    182      break;
    183 
    184    case InputStreamParams::TEncryptedFileInputStreamParams:
    185      serializable = new dom::quota::DecryptingInputStream<
    186          dom::quota::IPCStreamCipherStrategy>();
    187      break;
    188 
    189    default:
    190      MOZ_ASSERT(false, "Unknown params!");
    191      return nullptr;
    192  }
    193 
    194  MOZ_ASSERT(serializable);
    195 
    196  if (!serializable->Deserialize(aParams)) {
    197    MOZ_ASSERT(false, "Deserialize failed!");
    198    return nullptr;
    199  }
    200 
    201  nsCOMPtr<nsIInputStream> stream = do_QueryInterface(serializable);
    202  MOZ_ASSERT(stream);
    203 
    204  return stream.forget();
    205 }
    206 
    207 }  // namespace ipc
    208 }  // namespace mozilla