Bug 1835804 - Completely block from doing audio decoding on Content and RDD r=alwu
[gecko.git] / ipc / glue / IPCStreamUtils.cpp
blob265cb1cff8d333817490ea2023ad7ef2dbc144b7
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/. */
7 #include "IPCStreamUtils.h"
9 #include "ipc/IPCMessageUtilsSpecializations.h"
11 #include "nsIHttpHeaderVisitor.h"
12 #include "nsIIPCSerializableInputStream.h"
13 #include "mozIRemoteLazyInputStream.h"
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 "mozilla/Unused.h"
22 #include "nsIMIMEInputStream.h"
23 #include "nsNetCID.h"
25 using namespace mozilla::dom;
27 namespace mozilla::ipc {
29 namespace {
31 class MIMEStreamHeaderVisitor final : public nsIHttpHeaderVisitor {
32 public:
33 explicit MIMEStreamHeaderVisitor(
34 nsTArray<mozilla::ipc::HeaderEntry>& aHeaders)
35 : mHeaders(aHeaders) {}
37 NS_DECL_ISUPPORTS
38 NS_IMETHOD VisitHeader(const nsACString& aName,
39 const nsACString& aValue) override {
40 auto el = mHeaders.AppendElement();
41 el->name() = aName;
42 el->value() = aValue;
43 return NS_OK;
46 private:
47 ~MIMEStreamHeaderVisitor() = default;
49 nsTArray<mozilla::ipc::HeaderEntry>& mHeaders;
52 NS_IMPL_ISUPPORTS(MIMEStreamHeaderVisitor, nsIHttpHeaderVisitor)
54 static bool SerializeLazyInputStream(nsIInputStream* aStream,
55 IPCStream& aValue) {
56 MOZ_ASSERT(aStream);
57 MOZ_ASSERT(XRE_IsParentProcess());
59 // If we're serializing a MIME stream, ensure we preserve header data which
60 // would not be preserved by a RemoteLazyInputStream wrapper.
61 if (nsCOMPtr<nsIMIMEInputStream> mimeStream = do_QueryInterface(aStream)) {
62 MIMEInputStreamParams params;
63 params.startedReading() = false;
65 nsCOMPtr<nsIHttpHeaderVisitor> visitor =
66 new MIMEStreamHeaderVisitor(params.headers());
67 if (NS_WARN_IF(NS_FAILED(mimeStream->VisitHeaders(visitor)))) {
68 return false;
71 nsCOMPtr<nsIInputStream> dataStream;
72 if (NS_FAILED(mimeStream->GetData(getter_AddRefs(dataStream)))) {
73 return false;
75 if (dataStream) {
76 IPCStream data;
77 if (!SerializeLazyInputStream(dataStream, data)) {
78 return false;
80 params.optionalStream().emplace(std::move(data.stream()));
83 aValue.stream() = std::move(params);
84 return true;
87 RefPtr<RemoteLazyInputStream> lazyStream =
88 RemoteLazyInputStream::WrapStream(aStream);
89 if (NS_WARN_IF(!lazyStream)) {
90 return false;
93 aValue.stream() = RemoteLazyInputStreamParams(lazyStream);
95 return true;
98 } // anonymous namespace
100 bool SerializeIPCStream(already_AddRefed<nsIInputStream> aInputStream,
101 IPCStream& aValue, bool aAllowLazy) {
102 nsCOMPtr<nsIInputStream> stream(std::move(aInputStream));
103 if (!stream) {
104 MOZ_ASSERT_UNREACHABLE(
105 "Use the Maybe<...> overload to serialize optional nsIInputStreams");
106 return false;
109 // When requesting a delayed start stream from the parent process, serialize
110 // it as a remote lazy stream to avoid bloating payloads.
111 if (aAllowLazy && XRE_IsParentProcess()) {
112 return SerializeLazyInputStream(stream, aValue);
115 if (nsCOMPtr<nsIIPCSerializableInputStream> serializable =
116 do_QueryInterface(stream)) {
117 // If you change this size, please also update the payload size in
118 // test_reload_large_postdata.html.
119 const uint64_t kTooLargeStream = 1024 * 1024;
121 uint32_t sizeUsed = 0;
122 serializable->Serialize(aValue.stream(), kTooLargeStream, &sizeUsed);
124 MOZ_ASSERT(sizeUsed <= kTooLargeStream);
126 if (aValue.stream().type() == InputStreamParams::T__None) {
127 MOZ_CRASH("Serialize failed!");
129 return true;
132 InputStreamHelper::SerializeInputStreamAsPipe(stream, aValue.stream());
133 if (aValue.stream().type() == InputStreamParams::T__None) {
134 MOZ_ASSERT_UNREACHABLE("Serializing as a pipe failed");
135 return false;
137 return true;
140 bool SerializeIPCStream(already_AddRefed<nsIInputStream> aInputStream,
141 Maybe<IPCStream>& aValue, bool aAllowLazy) {
142 nsCOMPtr<nsIInputStream> stream(std::move(aInputStream));
143 if (!stream) {
144 aValue.reset();
145 return true;
148 IPCStream value;
149 if (SerializeIPCStream(stream.forget(), value, aAllowLazy)) {
150 aValue = Some(value);
151 return true;
153 return false;
156 already_AddRefed<nsIInputStream> DeserializeIPCStream(const IPCStream& aValue) {
157 return InputStreamHelper::DeserializeInputStream(aValue.stream());
160 already_AddRefed<nsIInputStream> DeserializeIPCStream(
161 const Maybe<IPCStream>& aValue) {
162 if (aValue.isNothing()) {
163 return nullptr;
166 return DeserializeIPCStream(aValue.ref());
169 } // namespace mozilla::ipc
171 void IPC::ParamTraits<nsIInputStream*>::Write(IPC::MessageWriter* aWriter,
172 nsIInputStream* aParam) {
173 mozilla::Maybe<mozilla::ipc::IPCStream> stream;
174 if (!mozilla::ipc::SerializeIPCStream(do_AddRef(aParam), stream,
175 /* aAllowLazy */ true)) {
176 MOZ_CRASH("Failed to serialize nsIInputStream");
179 WriteParam(aWriter, stream);
182 bool IPC::ParamTraits<nsIInputStream*>::Read(IPC::MessageReader* aReader,
183 RefPtr<nsIInputStream>* aResult) {
184 mozilla::Maybe<mozilla::ipc::IPCStream> ipcStream;
185 if (!ReadParam(aReader, &ipcStream)) {
186 return false;
189 *aResult = mozilla::ipc::DeserializeIPCStream(ipcStream);
190 return true;