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