BodyExtractor.cpp (6285B)
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/. */ 6 7 #include "BodyExtractor.h" 8 9 #include "mozilla/UniquePtr.h" 10 #include "mozilla/dom/File.h" 11 #include "mozilla/dom/FormData.h" 12 #include "mozilla/dom/ShadowRoot.h" 13 #include "mozilla/dom/TypedArray.h" 14 #include "mozilla/dom/URLSearchParams.h" 15 #include "mozilla/dom/XMLHttpRequest.h" 16 #include "nsContentUtils.h" 17 #include "nsDOMSerializer.h" 18 #include "nsIGlobalObject.h" 19 #include "nsIInputStream.h" 20 #include "nsIOutputStream.h" 21 #include "nsIStorageStream.h" 22 #include "nsStringStream.h" 23 24 namespace mozilla::dom { 25 26 static nsresult GetBufferDataAsStream(Vector<uint8_t>&& aData, 27 nsIInputStream** aResult, 28 uint64_t* aContentLength, 29 nsACString& aContentType, 30 nsACString& aCharset) { 31 aContentType.SetIsVoid(true); 32 aCharset.Truncate(); 33 34 *aContentLength = aData.length(); 35 36 nsCOMPtr<nsIInputStream> stream; 37 nsresult rv = NS_NewByteInputStream( 38 getter_AddRefs(stream), 39 AsChars(Span(aData.extractOrCopyRawBuffer(), *aContentLength)), 40 NS_ASSIGNMENT_ADOPT); 41 NS_ENSURE_SUCCESS(rv, rv); 42 43 stream.forget(aResult); 44 45 return NS_OK; 46 } 47 48 template <> 49 nsresult BodyExtractor<const ArrayBuffer>::GetAsStream( 50 nsIInputStream** aResult, uint64_t* aContentLength, 51 nsACString& aContentTypeWithCharset, nsACString& aCharset) const { 52 Maybe<Vector<uint8_t>> body = mBody->CreateFromData<Vector<uint8_t>>(); 53 if (body.isNothing()) { 54 return NS_ERROR_OUT_OF_MEMORY; 55 } 56 return GetBufferDataAsStream(body.extract(), aResult, aContentLength, 57 aContentTypeWithCharset, aCharset); 58 } 59 60 template <> 61 nsresult BodyExtractor<const ArrayBufferView>::GetAsStream( 62 nsIInputStream** aResult, uint64_t* aContentLength, 63 nsACString& aContentTypeWithCharset, nsACString& aCharset) const { 64 Maybe<Vector<uint8_t>> body = mBody->CreateFromData<Vector<uint8_t>>(); 65 if (body.isNothing()) { 66 return NS_ERROR_OUT_OF_MEMORY; 67 } 68 return GetBufferDataAsStream(body.extract(), aResult, aContentLength, 69 aContentTypeWithCharset, aCharset); 70 } 71 72 template <> 73 nsresult BodyExtractor<Document>::GetAsStream( 74 nsIInputStream** aResult, uint64_t* aContentLength, 75 nsACString& aContentTypeWithCharset, nsACString& aCharset) const { 76 NS_ENSURE_STATE(mBody); 77 aCharset.AssignLiteral("UTF-8"); 78 79 nsresult rv; 80 nsCOMPtr<nsIStorageStream> storStream; 81 rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream)); 82 NS_ENSURE_SUCCESS(rv, rv); 83 84 nsCOMPtr<nsIOutputStream> output; 85 rv = storStream->GetOutputStream(0, getter_AddRefs(output)); 86 NS_ENSURE_SUCCESS(rv, rv); 87 88 if (mBody->IsHTMLDocument()) { 89 aContentTypeWithCharset.AssignLiteral("text/html;charset=UTF-8"); 90 91 nsString serialized; 92 if (!nsContentUtils::SerializeNodeToMarkup(mBody, true, serialized, false, 93 {})) { 94 return NS_ERROR_OUT_OF_MEMORY; 95 } 96 97 nsAutoCString utf8Serialized; 98 if (!AppendUTF16toUTF8(serialized, utf8Serialized, fallible)) { 99 return NS_ERROR_OUT_OF_MEMORY; 100 } 101 102 uint32_t written; 103 rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written); 104 NS_ENSURE_SUCCESS(rv, rv); 105 106 MOZ_ASSERT(written == utf8Serialized.Length()); 107 } else { 108 aContentTypeWithCharset.AssignLiteral("application/xml;charset=UTF-8"); 109 110 auto serializer = MakeUnique<nsDOMSerializer>(); 111 112 // Make sure to use the encoding we'll send 113 ErrorResult res; 114 serializer->SerializeToStream(*mBody, output, u"UTF-8"_ns, res); 115 if (NS_WARN_IF(res.Failed())) { 116 return res.StealNSResult(); 117 } 118 } 119 120 output->Close(); 121 122 uint32_t length; 123 rv = storStream->GetLength(&length); 124 NS_ENSURE_SUCCESS(rv, rv); 125 *aContentLength = length; 126 127 rv = storStream->NewInputStream(0, aResult); 128 NS_ENSURE_SUCCESS(rv, rv); 129 return NS_OK; 130 } 131 132 template <> 133 nsresult BodyExtractor<const nsAString>::GetAsStream( 134 nsIInputStream** aResult, uint64_t* aContentLength, 135 nsACString& aContentTypeWithCharset, nsACString& aCharset) const { 136 nsCString encoded; 137 if (!CopyUTF16toUTF8(*mBody, encoded, fallible)) { 138 return NS_ERROR_OUT_OF_MEMORY; 139 } 140 141 uint32_t encodedLength = encoded.Length(); 142 nsresult rv = NS_NewCStringInputStream(aResult, std::move(encoded)); 143 if (NS_WARN_IF(NS_FAILED(rv))) { 144 return rv; 145 } 146 147 *aContentLength = encodedLength; 148 aContentTypeWithCharset.AssignLiteral("text/plain;charset=UTF-8"); 149 aCharset.AssignLiteral("UTF-8"); 150 return NS_OK; 151 } 152 153 template <> 154 nsresult BodyExtractor<nsIInputStream>::GetAsStream( 155 nsIInputStream** aResult, uint64_t* aContentLength, 156 nsACString& aContentTypeWithCharset, nsACString& aCharset) const { 157 aContentTypeWithCharset.AssignLiteral("text/plain"); 158 aCharset.Truncate(); 159 160 nsresult rv = mBody->Available(aContentLength); 161 NS_ENSURE_SUCCESS(rv, rv); 162 163 nsCOMPtr<nsIInputStream> stream(mBody); 164 stream.forget(aResult); 165 return NS_OK; 166 } 167 168 template <> 169 nsresult BodyExtractor<const Blob>::GetAsStream( 170 nsIInputStream** aResult, uint64_t* aContentLength, 171 nsACString& aContentTypeWithCharset, nsACString& aCharset) const { 172 return mBody->GetSendInfo(aResult, aContentLength, aContentTypeWithCharset, 173 aCharset); 174 } 175 176 template <> 177 nsresult BodyExtractor<const FormData>::GetAsStream( 178 nsIInputStream** aResult, uint64_t* aContentLength, 179 nsACString& aContentTypeWithCharset, nsACString& aCharset) const { 180 return mBody->GetSendInfo(aResult, aContentLength, aContentTypeWithCharset, 181 aCharset); 182 } 183 184 template <> 185 nsresult BodyExtractor<const URLSearchParams>::GetAsStream( 186 nsIInputStream** aResult, uint64_t* aContentLength, 187 nsACString& aContentTypeWithCharset, nsACString& aCharset) const { 188 return mBody->GetSendInfo(aResult, aContentLength, aContentTypeWithCharset, 189 aCharset); 190 } 191 192 } // namespace mozilla::dom