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 "BodyExtractor.h"
8 #include "mozilla/dom/File.h"
9 #include "mozilla/dom/FormData.h"
10 #include "mozilla/dom/ShadowRoot.h"
11 #include "mozilla/dom/TypedArray.h"
12 #include "mozilla/dom/URLSearchParams.h"
13 #include "mozilla/dom/XMLHttpRequest.h"
14 #include "mozilla/UniquePtr.h"
15 #include "nsContentUtils.h"
16 #include "nsDOMSerializer.h"
17 #include "nsIGlobalObject.h"
18 #include "nsIInputStream.h"
19 #include "nsIOutputStream.h"
20 #include "nsIStorageStream.h"
21 #include "nsStringStream.h"
23 namespace mozilla::dom
{
25 static nsresult
GetBufferDataAsStream(Vector
<uint8_t>&& aData
,
26 nsIInputStream
** aResult
,
27 uint64_t* aContentLength
,
28 nsACString
& aContentType
,
29 nsACString
& aCharset
) {
30 aContentType
.SetIsVoid(true);
33 *aContentLength
= aData
.length();
35 nsCOMPtr
<nsIInputStream
> stream
;
36 nsresult rv
= NS_NewByteInputStream(
37 getter_AddRefs(stream
),
38 AsChars(Span(aData
.extractOrCopyRawBuffer(), *aContentLength
)),
40 NS_ENSURE_SUCCESS(rv
, rv
);
42 stream
.forget(aResult
);
48 nsresult BodyExtractor
<const ArrayBuffer
>::GetAsStream(
49 nsIInputStream
** aResult
, uint64_t* aContentLength
,
50 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
51 Maybe
<Vector
<uint8_t>> body
= mBody
->CreateFromData
<Vector
<uint8_t>>();
52 if (body
.isNothing()) {
53 return NS_ERROR_OUT_OF_MEMORY
;
55 return GetBufferDataAsStream(body
.extract(), aResult
, aContentLength
,
56 aContentTypeWithCharset
, aCharset
);
60 nsresult BodyExtractor
<const ArrayBufferView
>::GetAsStream(
61 nsIInputStream
** aResult
, uint64_t* aContentLength
,
62 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
63 Maybe
<Vector
<uint8_t>> body
= mBody
->CreateFromData
<Vector
<uint8_t>>();
64 if (body
.isNothing()) {
65 return NS_ERROR_OUT_OF_MEMORY
;
67 return GetBufferDataAsStream(body
.extract(), aResult
, aContentLength
,
68 aContentTypeWithCharset
, aCharset
);
72 nsresult BodyExtractor
<Document
>::GetAsStream(
73 nsIInputStream
** aResult
, uint64_t* aContentLength
,
74 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
75 NS_ENSURE_STATE(mBody
);
76 aCharset
.AssignLiteral("UTF-8");
79 nsCOMPtr
<nsIStorageStream
> storStream
;
80 rv
= NS_NewStorageStream(4096, UINT32_MAX
, getter_AddRefs(storStream
));
81 NS_ENSURE_SUCCESS(rv
, rv
);
83 nsCOMPtr
<nsIOutputStream
> output
;
84 rv
= storStream
->GetOutputStream(0, getter_AddRefs(output
));
85 NS_ENSURE_SUCCESS(rv
, rv
);
87 if (mBody
->IsHTMLDocument()) {
88 aContentTypeWithCharset
.AssignLiteral("text/html;charset=UTF-8");
91 if (!nsContentUtils::SerializeNodeToMarkup(mBody
, true, serialized
, false,
93 return NS_ERROR_OUT_OF_MEMORY
;
96 nsAutoCString utf8Serialized
;
97 if (!AppendUTF16toUTF8(serialized
, utf8Serialized
, fallible
)) {
98 return NS_ERROR_OUT_OF_MEMORY
;
102 rv
= output
->Write(utf8Serialized
.get(), utf8Serialized
.Length(), &written
);
103 NS_ENSURE_SUCCESS(rv
, rv
);
105 MOZ_ASSERT(written
== utf8Serialized
.Length());
107 aContentTypeWithCharset
.AssignLiteral("application/xml;charset=UTF-8");
109 auto serializer
= MakeUnique
<nsDOMSerializer
>();
111 // Make sure to use the encoding we'll send
113 serializer
->SerializeToStream(*mBody
, output
, u
"UTF-8"_ns
, res
);
114 if (NS_WARN_IF(res
.Failed())) {
115 return res
.StealNSResult();
122 rv
= storStream
->GetLength(&length
);
123 NS_ENSURE_SUCCESS(rv
, rv
);
124 *aContentLength
= length
;
126 rv
= storStream
->NewInputStream(0, aResult
);
127 NS_ENSURE_SUCCESS(rv
, rv
);
132 nsresult BodyExtractor
<const nsAString
>::GetAsStream(
133 nsIInputStream
** aResult
, uint64_t* aContentLength
,
134 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
136 if (!CopyUTF16toUTF8(*mBody
, encoded
, fallible
)) {
137 return NS_ERROR_OUT_OF_MEMORY
;
140 uint32_t encodedLength
= encoded
.Length();
141 nsresult rv
= NS_NewCStringInputStream(aResult
, std::move(encoded
));
142 if (NS_WARN_IF(NS_FAILED(rv
))) {
146 *aContentLength
= encodedLength
;
147 aContentTypeWithCharset
.AssignLiteral("text/plain;charset=UTF-8");
148 aCharset
.AssignLiteral("UTF-8");
153 nsresult BodyExtractor
<nsIInputStream
>::GetAsStream(
154 nsIInputStream
** aResult
, uint64_t* aContentLength
,
155 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
156 aContentTypeWithCharset
.AssignLiteral("text/plain");
159 nsresult rv
= mBody
->Available(aContentLength
);
160 NS_ENSURE_SUCCESS(rv
, rv
);
162 nsCOMPtr
<nsIInputStream
> stream(mBody
);
163 stream
.forget(aResult
);
168 nsresult BodyExtractor
<const Blob
>::GetAsStream(
169 nsIInputStream
** aResult
, uint64_t* aContentLength
,
170 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
171 return mBody
->GetSendInfo(aResult
, aContentLength
, aContentTypeWithCharset
,
176 nsresult BodyExtractor
<const FormData
>::GetAsStream(
177 nsIInputStream
** aResult
, uint64_t* aContentLength
,
178 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
179 return mBody
->GetSendInfo(aResult
, aContentLength
, aContentTypeWithCharset
,
184 nsresult BodyExtractor
<const URLSearchParams
>::GetAsStream(
185 nsIInputStream
** aResult
, uint64_t* aContentLength
,
186 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
187 return mBody
->GetSendInfo(aResult
, aContentLength
, aContentTypeWithCharset
,
191 } // namespace mozilla::dom