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(
25 const uint8_t* aData
, uint32_t aDataLength
, nsIInputStream
** aResult
,
26 uint64_t* aContentLength
, nsACString
& aContentType
, nsACString
& aCharset
) {
27 aContentType
.SetIsVoid(true);
30 *aContentLength
= aDataLength
;
31 const char* data
= reinterpret_cast<const char*>(aData
);
33 nsCOMPtr
<nsIInputStream
> stream
;
34 nsresult rv
= NS_NewByteInputStream(
35 getter_AddRefs(stream
), Span(data
, aDataLength
), NS_ASSIGNMENT_COPY
);
36 NS_ENSURE_SUCCESS(rv
, rv
);
38 stream
.forget(aResult
);
44 nsresult BodyExtractor
<const ArrayBuffer
>::GetAsStream(
45 nsIInputStream
** aResult
, uint64_t* aContentLength
,
46 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
47 mBody
->ComputeState();
48 return GetBufferDataAsStream(mBody
->Data(), mBody
->Length(), aResult
,
49 aContentLength
, aContentTypeWithCharset
,
54 nsresult BodyExtractor
<const ArrayBufferView
>::GetAsStream(
55 nsIInputStream
** aResult
, uint64_t* aContentLength
,
56 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
57 mBody
->ComputeState();
58 return GetBufferDataAsStream(mBody
->Data(), mBody
->Length(), aResult
,
59 aContentLength
, aContentTypeWithCharset
,
64 nsresult BodyExtractor
<Document
>::GetAsStream(
65 nsIInputStream
** aResult
, uint64_t* aContentLength
,
66 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
67 NS_ENSURE_STATE(mBody
);
68 aCharset
.AssignLiteral("UTF-8");
71 nsCOMPtr
<nsIStorageStream
> storStream
;
72 rv
= NS_NewStorageStream(4096, UINT32_MAX
, getter_AddRefs(storStream
));
73 NS_ENSURE_SUCCESS(rv
, rv
);
75 nsCOMPtr
<nsIOutputStream
> output
;
76 rv
= storStream
->GetOutputStream(0, getter_AddRefs(output
));
77 NS_ENSURE_SUCCESS(rv
, rv
);
79 if (mBody
->IsHTMLDocument()) {
80 aContentTypeWithCharset
.AssignLiteral("text/html;charset=UTF-8");
83 if (!nsContentUtils::SerializeNodeToMarkup(mBody
, true, serialized
)) {
84 return NS_ERROR_OUT_OF_MEMORY
;
87 nsAutoCString utf8Serialized
;
88 if (!AppendUTF16toUTF8(serialized
, utf8Serialized
, fallible
)) {
89 return NS_ERROR_OUT_OF_MEMORY
;
93 rv
= output
->Write(utf8Serialized
.get(), utf8Serialized
.Length(), &written
);
94 NS_ENSURE_SUCCESS(rv
, rv
);
96 MOZ_ASSERT(written
== utf8Serialized
.Length());
98 aContentTypeWithCharset
.AssignLiteral("application/xml;charset=UTF-8");
100 auto serializer
= MakeUnique
<nsDOMSerializer
>();
102 // Make sure to use the encoding we'll send
104 serializer
->SerializeToStream(*mBody
, output
, u
"UTF-8"_ns
, res
);
105 if (NS_WARN_IF(res
.Failed())) {
106 return res
.StealNSResult();
113 rv
= storStream
->GetLength(&length
);
114 NS_ENSURE_SUCCESS(rv
, rv
);
115 *aContentLength
= length
;
117 rv
= storStream
->NewInputStream(0, aResult
);
118 NS_ENSURE_SUCCESS(rv
, rv
);
123 nsresult BodyExtractor
<const nsAString
>::GetAsStream(
124 nsIInputStream
** aResult
, uint64_t* aContentLength
,
125 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
127 if (!CopyUTF16toUTF8(*mBody
, encoded
, fallible
)) {
128 return NS_ERROR_OUT_OF_MEMORY
;
131 uint32_t encodedLength
= encoded
.Length();
132 nsresult rv
= NS_NewCStringInputStream(aResult
, std::move(encoded
));
133 if (NS_WARN_IF(NS_FAILED(rv
))) {
137 *aContentLength
= encodedLength
;
138 aContentTypeWithCharset
.AssignLiteral("text/plain;charset=UTF-8");
139 aCharset
.AssignLiteral("UTF-8");
144 nsresult BodyExtractor
<nsIInputStream
>::GetAsStream(
145 nsIInputStream
** aResult
, uint64_t* aContentLength
,
146 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
147 aContentTypeWithCharset
.AssignLiteral("text/plain");
150 nsresult rv
= mBody
->Available(aContentLength
);
151 NS_ENSURE_SUCCESS(rv
, rv
);
153 nsCOMPtr
<nsIInputStream
> stream(mBody
);
154 stream
.forget(aResult
);
159 nsresult BodyExtractor
<const Blob
>::GetAsStream(
160 nsIInputStream
** aResult
, uint64_t* aContentLength
,
161 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
162 return mBody
->GetSendInfo(aResult
, aContentLength
, aContentTypeWithCharset
,
167 nsresult BodyExtractor
<const FormData
>::GetAsStream(
168 nsIInputStream
** aResult
, uint64_t* aContentLength
,
169 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
170 return mBody
->GetSendInfo(aResult
, aContentLength
, aContentTypeWithCharset
,
175 nsresult BodyExtractor
<const URLSearchParams
>::GetAsStream(
176 nsIInputStream
** aResult
, uint64_t* aContentLength
,
177 nsACString
& aContentTypeWithCharset
, nsACString
& aCharset
) const {
178 return mBody
->GetSendInfo(aResult
, aContentLength
, aContentTypeWithCharset
,
182 } // namespace mozilla::dom