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 "EmptyBlobImpl.h"
8 #include "mozilla/InputStreamLengthWrapper.h"
9 #include "mozilla/SlicedInputStream.h"
10 #include "StreamBlobImpl.h"
11 #include "nsStreamUtils.h"
12 #include "nsStringStream.h"
13 #include "nsICloneableInputStream.h"
14
15 namespace mozilla::dom {
16
NS_IMPL_ISUPPORTS_INHERITED(StreamBlobImpl,BlobImpl,nsIMemoryReporter)17 NS_IMPL_ISUPPORTS_INHERITED(StreamBlobImpl, BlobImpl, nsIMemoryReporter)
18
19 /* static */
20 already_AddRefed<StreamBlobImpl> StreamBlobImpl::Create(
21 already_AddRefed<nsIInputStream> aInputStream,
22 const nsAString& aContentType, uint64_t aLength,
23 const nsAString& aBlobImplType) {
24 nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
25
26 RefPtr<StreamBlobImpl> blobImplStream = new StreamBlobImpl(
27 inputStream.forget(), aContentType, aLength, aBlobImplType);
28 blobImplStream->MaybeRegisterMemoryReporter();
29 return blobImplStream.forget();
30 }
31
32 /* static */
Create(already_AddRefed<nsIInputStream> aInputStream,const nsAString & aName,const nsAString & aContentType,int64_t aLastModifiedDate,uint64_t aLength,const nsAString & aBlobImplType)33 already_AddRefed<StreamBlobImpl> StreamBlobImpl::Create(
34 already_AddRefed<nsIInputStream> aInputStream, const nsAString& aName,
35 const nsAString& aContentType, int64_t aLastModifiedDate, uint64_t aLength,
36 const nsAString& aBlobImplType) {
37 nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
38
39 RefPtr<StreamBlobImpl> blobImplStream =
40 new StreamBlobImpl(inputStream.forget(), aName, aContentType,
41 aLastModifiedDate, aLength, aBlobImplType);
42 blobImplStream->MaybeRegisterMemoryReporter();
43 return blobImplStream.forget();
44 }
45
StreamBlobImpl(already_AddRefed<nsIInputStream> aInputStream,const nsAString & aContentType,uint64_t aLength,const nsAString & aBlobImplType)46 StreamBlobImpl::StreamBlobImpl(already_AddRefed<nsIInputStream> aInputStream,
47 const nsAString& aContentType, uint64_t aLength,
48 const nsAString& aBlobImplType)
49 : BaseBlobImpl(aContentType, aLength),
50 mInputStream(std::move(aInputStream)),
51 mBlobImplType(aBlobImplType),
52 mIsDirectory(false),
53 mFileId(-1) {}
54
StreamBlobImpl(already_AddRefed<nsIInputStream> aInputStream,const nsAString & aName,const nsAString & aContentType,int64_t aLastModifiedDate,uint64_t aLength,const nsAString & aBlobImplType)55 StreamBlobImpl::StreamBlobImpl(already_AddRefed<nsIInputStream> aInputStream,
56 const nsAString& aName,
57 const nsAString& aContentType,
58 int64_t aLastModifiedDate, uint64_t aLength,
59 const nsAString& aBlobImplType)
60 : BaseBlobImpl(aName, aContentType, aLength, aLastModifiedDate),
61 mInputStream(std::move(aInputStream)),
62 mBlobImplType(aBlobImplType),
63 mIsDirectory(false),
64 mFileId(-1) {}
65
~StreamBlobImpl()66 StreamBlobImpl::~StreamBlobImpl() { UnregisterWeakMemoryReporter(this); }
67
CreateInputStream(nsIInputStream ** aStream,ErrorResult & aRv)68 void StreamBlobImpl::CreateInputStream(nsIInputStream** aStream,
69 ErrorResult& aRv) {
70 nsCOMPtr<nsIInputStream> clonedStream;
71 nsCOMPtr<nsIInputStream> replacementStream;
72
73 aRv = NS_CloneInputStream(mInputStream, getter_AddRefs(clonedStream),
74 getter_AddRefs(replacementStream));
75 if (NS_WARN_IF(aRv.Failed())) {
76 return;
77 }
78
79 if (replacementStream) {
80 mInputStream = std::move(replacementStream);
81 }
82
83 nsCOMPtr<nsIInputStream> wrappedStream =
84 InputStreamLengthWrapper::MaybeWrap(clonedStream.forget(), mLength);
85
86 wrappedStream.forget(aStream);
87 }
88
CreateSlice(uint64_t aStart,uint64_t aLength,const nsAString & aContentType,ErrorResult & aRv)89 already_AddRefed<BlobImpl> StreamBlobImpl::CreateSlice(
90 uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
91 ErrorResult& aRv) {
92 if (!aLength) {
93 RefPtr<BlobImpl> impl = new EmptyBlobImpl(aContentType);
94 return impl.forget();
95 }
96
97 nsCOMPtr<nsIInputStream> clonedStream;
98
99 nsCOMPtr<nsICloneableInputStreamWithRange> stream =
100 do_QueryInterface(mInputStream);
101 if (stream) {
102 aRv = stream->CloneWithRange(aStart, aLength, getter_AddRefs(clonedStream));
103 if (NS_WARN_IF(aRv.Failed())) {
104 return nullptr;
105 }
106 } else {
107 CreateInputStream(getter_AddRefs(clonedStream), aRv);
108 if (NS_WARN_IF(aRv.Failed())) {
109 return nullptr;
110 }
111
112 clonedStream =
113 new SlicedInputStream(clonedStream.forget(), aStart, aLength);
114 }
115
116 MOZ_ASSERT(clonedStream);
117
118 RefPtr<BlobImpl> impl = new StreamBlobImpl(
119 clonedStream.forget(), aContentType, aLength, mBlobImplType);
120 return impl.forget();
121 }
122
MaybeRegisterMemoryReporter()123 void StreamBlobImpl::MaybeRegisterMemoryReporter() {
124 // We report only stringInputStream.
125 nsCOMPtr<nsIStringInputStream> stringInputStream =
126 do_QueryInterface(mInputStream);
127 if (!stringInputStream) {
128 return;
129 }
130
131 RegisterWeakMemoryReporter(this);
132 }
133
134 NS_IMETHODIMP
CollectReports(nsIHandleReportCallback * aHandleReport,nsISupports * aData,bool aAnonymize)135 StreamBlobImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
136 nsISupports* aData, bool aAnonymize) {
137 nsCOMPtr<nsIStringInputStream> stringInputStream =
138 do_QueryInterface(mInputStream);
139 if (!stringInputStream) {
140 return NS_OK;
141 }
142
143 MOZ_COLLECT_REPORT(
144 "explicit/dom/memory-file-data/stream", KIND_HEAP, UNITS_BYTES,
145 stringInputStream->SizeOfIncludingThisIfUnshared(MallocSizeOf),
146 "Memory used to back a File/Blob based on an input stream.");
147
148 return NS_OK;
149 }
150
GetAllocationSize() const151 size_t StreamBlobImpl::GetAllocationSize() const {
152 nsCOMPtr<nsIStringInputStream> stringInputStream =
153 do_QueryInterface(mInputStream);
154 if (!stringInputStream) {
155 return 0;
156 }
157
158 return stringInputStream->SizeOfIncludingThisEvenIfShared(MallocSizeOf);
159 }
160
GetBlobImplType(nsAString & aBlobImplType) const161 void StreamBlobImpl::GetBlobImplType(nsAString& aBlobImplType) const {
162 aBlobImplType.AssignLiteral("StreamBlobImpl[");
163 aBlobImplType.Append(mBlobImplType);
164 aBlobImplType.AppendLiteral("]");
165 }
166
167 } // namespace mozilla::dom
168