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"
25 using namespace mozilla::dom
;
27 namespace mozilla::ipc
{
31 class MIMEStreamHeaderVisitor final
: public nsIHttpHeaderVisitor
{
33 explicit MIMEStreamHeaderVisitor(
34 nsTArray
<mozilla::ipc::HeaderEntry
>& aHeaders
)
35 : mHeaders(aHeaders
) {}
38 NS_IMETHOD
VisitHeader(const nsACString
& aName
,
39 const nsACString
& aValue
) override
{
40 auto el
= mHeaders
.AppendElement();
47 ~MIMEStreamHeaderVisitor() = default;
49 nsTArray
<mozilla::ipc::HeaderEntry
>& mHeaders
;
52 NS_IMPL_ISUPPORTS(MIMEStreamHeaderVisitor
, nsIHttpHeaderVisitor
)
54 static bool SerializeLazyInputStream(nsIInputStream
* 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
)))) {
71 nsCOMPtr
<nsIInputStream
> dataStream
;
72 if (NS_FAILED(mimeStream
->GetData(getter_AddRefs(dataStream
)))) {
77 if (!SerializeLazyInputStream(dataStream
, data
)) {
80 params
.optionalStream().emplace(std::move(data
.stream()));
83 aValue
.stream() = std::move(params
);
87 RefPtr
<RemoteLazyInputStream
> lazyStream
=
88 RemoteLazyInputStream::WrapStream(aStream
);
89 if (NS_WARN_IF(!lazyStream
)) {
93 aValue
.stream() = RemoteLazyInputStreamParams(lazyStream
);
98 } // anonymous namespace
100 bool SerializeIPCStream(already_AddRefed
<nsIInputStream
> aInputStream
,
101 IPCStream
& aValue
, bool aAllowLazy
) {
102 nsCOMPtr
<nsIInputStream
> stream(std::move(aInputStream
));
104 MOZ_ASSERT_UNREACHABLE(
105 "Use the Maybe<...> overload to serialize optional nsIInputStreams");
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!");
132 InputStreamHelper::SerializeInputStreamAsPipe(stream
, aValue
.stream());
133 if (aValue
.stream().type() == InputStreamParams::T__None
) {
134 MOZ_ASSERT_UNREACHABLE("Serializing as a pipe failed");
140 bool SerializeIPCStream(already_AddRefed
<nsIInputStream
> aInputStream
,
141 Maybe
<IPCStream
>& aValue
, bool aAllowLazy
) {
142 nsCOMPtr
<nsIInputStream
> stream(std::move(aInputStream
));
149 if (SerializeIPCStream(stream
.forget(), value
, aAllowLazy
)) {
150 aValue
= Some(value
);
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()) {
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
)) {
189 *aResult
= mozilla::ipc::DeserializeIPCStream(ipcStream
);