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/TypedArray.h"
11 #include "mozilla/dom/URLSearchParams.h"
12 #include "mozilla/dom/XMLHttpRequest.h"
13 #include "mozilla/UniquePtr.h"
14 #include "nsContentUtils.h"
15 #include "nsDOMSerializer.h"
16 #include "nsIGlobalObject.h"
17 #include "nsIInputStream.h"
18 #include "nsIOutputStream.h"
19 #include "nsIStorageStream.h"
20 #include "nsStringStream.h"
22 namespace mozilla::dom
{
24 static nsresult
GetBufferDataAsStream(Vector
<uint8_t>&& aData
,
25 nsIInputStream
** aResult
,
26 uint64_t* aContentLength
,
27 nsACString
& aContentType
,
28 nsACString
& aCharset
) {
29 aContentType
.SetIsVoid(true);
32 *aContentLength
= aData
.length();
34 nsCOMPtr
<nsIInputStream
> stream
;
35 nsresult rv
= NS_NewByteInputStream(
36 getter_AddRefs(stream
),
37 AsChars(Span(aData
.extractOrCopyRawBuffer(), *aContentLength
)),
39 NS_ENSURE_SUCCESS(rv
, rv
);
41 stream
.forget(aResult
);
47 nsresult BodyExtractor
<const ArrayBuffer
>::GetAsStream(
48 nsIInputStream
** aResult
, uint64_t* aContentLength
,
49 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
50 Maybe
<Vector
<uint8_t>> body
= mBody
->CreateFromData
<Vector
<uint8_t>>();
51 if (body
.isNothing()) {
52 return NS_ERROR_OUT_OF_MEMORY
;
54 return GetBufferDataAsStream(body
.extract(), aResult
, aContentLength
,
55 aContentTypeWithCharset
, aCharset
);
59 nsresult BodyExtractor
<const ArrayBufferView
>::GetAsStream(
60 nsIInputStream
** aResult
, uint64_t* aContentLength
,
61 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
62 Maybe
<Vector
<uint8_t>> body
= mBody
->CreateFromData
<Vector
<uint8_t>>();
63 if (body
.isNothing()) {
64 return NS_ERROR_OUT_OF_MEMORY
;
66 return GetBufferDataAsStream(body
.extract(), aResult
, aContentLength
,
67 aContentTypeWithCharset
, aCharset
);
71 nsresult BodyExtractor
<Document
>::GetAsStream(
72 nsIInputStream
** aResult
, uint64_t* aContentLength
,
73 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
74 NS_ENSURE_STATE(mBody
);
75 aCharset
.AssignLiteral("UTF-8");
78 nsCOMPtr
<nsIStorageStream
> storStream
;
79 rv
= NS_NewStorageStream(4096, UINT32_MAX
, getter_AddRefs(storStream
));
80 NS_ENSURE_SUCCESS(rv
, rv
);
82 nsCOMPtr
<nsIOutputStream
> output
;
83 rv
= storStream
->GetOutputStream(0, getter_AddRefs(output
));
84 NS_ENSURE_SUCCESS(rv
, rv
);
86 if (mBody
->IsHTMLDocument()) {
87 aContentTypeWithCharset
.AssignLiteral("text/html;charset=UTF-8");
90 if (!nsContentUtils::SerializeNodeToMarkup(mBody
, true, serialized
)) {
91 return NS_ERROR_OUT_OF_MEMORY
;
94 nsAutoCString utf8Serialized
;
95 if (!AppendUTF16toUTF8(serialized
, utf8Serialized
, fallible
)) {
96 return NS_ERROR_OUT_OF_MEMORY
;
100 rv
= output
->Write(utf8Serialized
.get(), utf8Serialized
.Length(), &written
);
101 NS_ENSURE_SUCCESS(rv
, rv
);
103 MOZ_ASSERT(written
== utf8Serialized
.Length());
105 aContentTypeWithCharset
.AssignLiteral("application/xml;charset=UTF-8");
107 auto serializer
= MakeUnique
<nsDOMSerializer
>();
109 // Make sure to use the encoding we'll send
111 serializer
->SerializeToStream(*mBody
, output
, u
"UTF-8"_ns
, res
);
112 if (NS_WARN_IF(res
.Failed())) {
113 return res
.StealNSResult();
120 rv
= storStream
->GetLength(&length
);
121 NS_ENSURE_SUCCESS(rv
, rv
);
122 *aContentLength
= length
;
124 rv
= storStream
->NewInputStream(0, aResult
);
125 NS_ENSURE_SUCCESS(rv
, rv
);
130 nsresult BodyExtractor
<const nsAString
>::GetAsStream(
131 nsIInputStream
** aResult
, uint64_t* aContentLength
,
132 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
134 if (!CopyUTF16toUTF8(*mBody
, encoded
, fallible
)) {
135 return NS_ERROR_OUT_OF_MEMORY
;
138 uint32_t encodedLength
= encoded
.Length();
139 nsresult rv
= NS_NewCStringInputStream(aResult
, std::move(encoded
));
140 if (NS_WARN_IF(NS_FAILED(rv
))) {
144 *aContentLength
= encodedLength
;
145 aContentTypeWithCharset
.AssignLiteral("text/plain;charset=UTF-8");
146 aCharset
.AssignLiteral("UTF-8");
151 nsresult BodyExtractor
<nsIInputStream
>::GetAsStream(
152 nsIInputStream
** aResult
, uint64_t* aContentLength
,
153 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
154 aContentTypeWithCharset
.AssignLiteral("text/plain");
157 nsresult rv
= mBody
->Available(aContentLength
);
158 NS_ENSURE_SUCCESS(rv
, rv
);
160 nsCOMPtr
<nsIInputStream
> stream(mBody
);
161 stream
.forget(aResult
);
166 nsresult BodyExtractor
<const Blob
>::GetAsStream(
167 nsIInputStream
** aResult
, uint64_t* aContentLength
,
168 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
169 return mBody
->GetSendInfo(aResult
, aContentLength
, aContentTypeWithCharset
,
174 nsresult BodyExtractor
<const FormData
>::GetAsStream(
175 nsIInputStream
** aResult
, uint64_t* aContentLength
,
176 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
177 return mBody
->GetSendInfo(aResult
, aContentLength
, aContentTypeWithCharset
,
182 nsresult BodyExtractor
<const URLSearchParams
>::GetAsStream(
183 nsIInputStream
** aResult
, uint64_t* aContentLength
,
184 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
185 return mBody
->GetSendInfo(aResult
, aContentLength
, aContentTypeWithCharset
,
189 } // namespace mozilla::dom