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