tor-browser

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

IPCStreamUtils.cpp (5752B)


      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 "IPCStreamUtils.h"
      8 
      9 #include "ipc/IPCMessageUtilsSpecializations.h"
     10 
     11 #include "nsIHttpHeaderVisitor.h"
     12 #include "nsIIPCSerializableInputStream.h"
     13 #include "mozIRemoteLazyInputStream.h"
     14 
     15 #include "mozilla/Assertions.h"
     16 #include "mozilla/dom/File.h"
     17 #include "mozilla/ipc/IPCStream.h"
     18 #include "mozilla/ipc/InputStreamUtils.h"
     19 #include "mozilla/InputStreamLengthHelper.h"
     20 #include "mozilla/RemoteLazyInputStreamParent.h"
     21 #include "nsIMIMEInputStream.h"
     22 #include "nsNetCID.h"
     23 
     24 using namespace mozilla::dom;
     25 
     26 namespace mozilla::ipc {
     27 
     28 namespace {
     29 
     30 class MIMEStreamHeaderVisitor final : public nsIHttpHeaderVisitor {
     31 public:
     32  explicit MIMEStreamHeaderVisitor(
     33      nsTArray<mozilla::ipc::HeaderEntry>& aHeaders)
     34      : mHeaders(aHeaders) {}
     35 
     36  NS_DECL_ISUPPORTS
     37  NS_IMETHOD VisitHeader(const nsACString& aName,
     38                         const nsACString& aValue) override {
     39    auto el = mHeaders.AppendElement();
     40    el->name() = aName;
     41    el->value() = aValue;
     42    return NS_OK;
     43  }
     44 
     45 private:
     46  ~MIMEStreamHeaderVisitor() = default;
     47 
     48  nsTArray<mozilla::ipc::HeaderEntry>& mHeaders;
     49 };
     50 
     51 NS_IMPL_ISUPPORTS(MIMEStreamHeaderVisitor, nsIHttpHeaderVisitor)
     52 
     53 static bool SerializeLazyInputStream(nsIInputStream* aStream,
     54                                     IPCStream& aValue) {
     55  MOZ_ASSERT(aStream);
     56  MOZ_ASSERT(XRE_IsParentProcess());
     57 
     58  // If we're serializing a MIME stream, ensure we preserve header data which
     59  // would not be preserved by a RemoteLazyInputStream wrapper.
     60  if (nsCOMPtr<nsIMIMEInputStream> mimeStream = do_QueryInterface(aStream)) {
     61    MIMEInputStreamParams params;
     62    params.startedReading() = false;
     63 
     64    nsCOMPtr<nsIHttpHeaderVisitor> visitor =
     65        new MIMEStreamHeaderVisitor(params.headers());
     66    if (NS_WARN_IF(NS_FAILED(mimeStream->VisitHeaders(visitor)))) {
     67      return false;
     68    }
     69 
     70    nsCOMPtr<nsIInputStream> dataStream;
     71    if (NS_FAILED(mimeStream->GetData(getter_AddRefs(dataStream)))) {
     72      return false;
     73    }
     74    if (dataStream) {
     75      IPCStream data;
     76      if (!SerializeLazyInputStream(dataStream, data)) {
     77        return false;
     78      }
     79      params.optionalStream().emplace(std::move(data.stream()));
     80    }
     81 
     82    aValue.stream() = std::move(params);
     83    return true;
     84  }
     85 
     86  RefPtr<RemoteLazyInputStream> lazyStream =
     87      RemoteLazyInputStream::WrapStream(aStream);
     88  if (NS_WARN_IF(!lazyStream)) {
     89    return false;
     90  }
     91 
     92  aValue.stream() = RemoteLazyInputStreamParams(WrapNotNull(lazyStream));
     93 
     94  return true;
     95 }
     96 
     97 }  // anonymous namespace
     98 
     99 bool SerializeIPCStream(already_AddRefed<nsIInputStream> aInputStream,
    100                        IPCStream& aValue, bool aAllowLazy) {
    101  nsCOMPtr<nsIInputStream> stream(std::move(aInputStream));
    102  if (!stream) {
    103    MOZ_ASSERT_UNREACHABLE(
    104        "Use the Maybe<...> overload to serialize optional nsIInputStreams");
    105    return false;
    106  }
    107 
    108  // When requesting a delayed start stream from the parent process, serialize
    109  // it as a remote lazy stream to avoid bloating payloads.
    110  if (aAllowLazy && XRE_IsParentProcess()) {
    111    return SerializeLazyInputStream(stream, aValue);
    112  }
    113 
    114  if (nsCOMPtr<nsIIPCSerializableInputStream> serializable =
    115          do_QueryInterface(stream)) {
    116    // If you change this size, please also update the payload size in
    117    // test_reload_large_postdata.html.
    118    const uint64_t kTooLargeStream = 1024 * 1024;
    119 
    120    uint32_t sizeUsed = 0;
    121    serializable->Serialize(aValue.stream(), kTooLargeStream, &sizeUsed);
    122 
    123    MOZ_ASSERT(sizeUsed <= kTooLargeStream);
    124 
    125    if (aValue.stream().type() == InputStreamParams::T__None) {
    126      MOZ_CRASH("Serialize failed!");
    127    }
    128    return true;
    129  }
    130 
    131  InputStreamHelper::SerializeInputStreamAsPipe(stream, aValue.stream());
    132  if (aValue.stream().type() == InputStreamParams::T__None) {
    133    // This can fail from OOM, etc.  We will likely MOZ_CRASH now
    134    return false;
    135  }
    136  return true;
    137 }
    138 
    139 bool SerializeIPCStream(already_AddRefed<nsIInputStream> aInputStream,
    140                        Maybe<IPCStream>& aValue, bool aAllowLazy) {
    141  nsCOMPtr<nsIInputStream> stream(std::move(aInputStream));
    142  if (!stream) {
    143    aValue.reset();
    144    return true;
    145  }
    146 
    147  IPCStream value;
    148  if (SerializeIPCStream(stream.forget(), value, aAllowLazy)) {
    149    aValue = Some(value);
    150    return true;
    151  }
    152  return false;
    153 }
    154 
    155 already_AddRefed<nsIInputStream> DeserializeIPCStream(const IPCStream& aValue) {
    156  return InputStreamHelper::DeserializeInputStream(aValue.stream());
    157 }
    158 
    159 already_AddRefed<nsIInputStream> DeserializeIPCStream(
    160    const Maybe<IPCStream>& aValue) {
    161  if (aValue.isNothing()) {
    162    return nullptr;
    163  }
    164 
    165  return DeserializeIPCStream(aValue.ref());
    166 }
    167 
    168 }  // namespace mozilla::ipc
    169 
    170 void IPC::ParamTraits<nsIInputStream*>::Write(IPC::MessageWriter* aWriter,
    171                                              nsIInputStream* aParam) {
    172  mozilla::Maybe<mozilla::ipc::IPCStream> stream;
    173  if (!mozilla::ipc::SerializeIPCStream(do_AddRef(aParam), stream,
    174                                        /* aAllowLazy */ true)) {
    175    MOZ_CRASH("Failed to serialize nsIInputStream");
    176  }
    177 
    178  WriteParam(aWriter, stream);
    179 }
    180 
    181 bool IPC::ParamTraits<nsIInputStream*>::Read(IPC::MessageReader* aReader,
    182                                             RefPtr<nsIInputStream>* aResult) {
    183  mozilla::Maybe<mozilla::ipc::IPCStream> ipcStream;
    184  if (!ReadParam(aReader, &ipcStream)) {
    185    return false;
    186  }
    187 
    188  *aResult = mozilla::ipc::DeserializeIPCStream(ipcStream);
    189  return true;
    190 }