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 #ifndef mozilla_dom_MemoryBlobImpl_h 8 #define mozilla_dom_MemoryBlobImpl_h 9 10 #include "mozilla/dom/BaseBlobImpl.h" 11 #include "mozilla/LinkedList.h" 12 #include "mozilla/StaticMutex.h" 13 #include "mozilla/StaticPtr.h" 14 #include "nsCOMPtr.h" 15 #include "nsICloneableInputStream.h" 16 #include "nsIInputStream.h" 17 #include "nsIIPCSerializableInputStream.h" 18 #include "nsISeekableStream.h" 19 20 namespace mozilla { 21 namespace dom { 22 23 class MemoryBlobImpl final : public BaseBlobImpl { 24 public: 25 NS_INLINE_DECL_REFCOUNTING_INHERITED(MemoryBlobImpl, BaseBlobImpl) 26 27 // File constructor. 28 static already_AddRefed<MemoryBlobImpl> CreateWithLastModifiedNow( 29 void* aMemoryBuffer, uint64_t aLength, const nsAString& aName, 30 const nsAString& aContentType, bool aCrossOriginIsolated); 31 32 // File constructor with custom lastModified attribue value. You should 33 // probably use CreateWithLastModifiedNow() instead of this one. 34 static already_AddRefed<MemoryBlobImpl> CreateWithCustomLastModified( 35 void* aMemoryBuffer, uint64_t aLength, const nsAString& aName, 36 const nsAString& aContentType, int64_t aLastModifiedDate); 37 38 // Blob constructor. MemoryBlobImpl(void * aMemoryBuffer,uint64_t aLength,const nsAString & aContentType)39 MemoryBlobImpl(void* aMemoryBuffer, uint64_t aLength, 40 const nsAString& aContentType) 41 : BaseBlobImpl(aContentType, aLength), 42 mDataOwner(new DataOwner(aMemoryBuffer, aLength)) { 43 MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data"); 44 } 45 46 void CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv) override; 47 48 already_AddRefed<BlobImpl> CreateSlice(uint64_t aStart, uint64_t aLength, 49 const nsAString& aContentType, 50 ErrorResult& aRv) override; 51 IsMemoryFile()52 bool IsMemoryFile() const override { return true; } 53 GetAllocationSize()54 size_t GetAllocationSize() const override { return mLength; } 55 GetAllocationSize(FallibleTArray<BlobImpl * > & aVisitedBlobImpls)56 size_t GetAllocationSize( 57 FallibleTArray<BlobImpl*>& aVisitedBlobImpls) const override { 58 return GetAllocationSize(); 59 } 60 GetBlobImplType(nsAString & aBlobImplType)61 void GetBlobImplType(nsAString& aBlobImplType) const override { 62 aBlobImplType = u"MemoryBlobImpl"_ns; 63 } 64 65 class DataOwner final : public mozilla::LinkedListElement<DataOwner> { 66 public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataOwner)67 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataOwner) 68 DataOwner(void* aMemoryBuffer, uint64_t aLength) 69 : mData(aMemoryBuffer), mLength(aLength) { 70 mozilla::StaticMutexAutoLock lock(sDataOwnerMutex); 71 72 if (!sDataOwners) { 73 sDataOwners = new mozilla::LinkedList<DataOwner>(); 74 EnsureMemoryReporterRegistered(); 75 } 76 sDataOwners->insertBack(this); 77 } 78 79 private: 80 // Private destructor, to discourage deletion outside of Release(): ~DataOwner()81 ~DataOwner() { 82 mozilla::StaticMutexAutoLock lock(sDataOwnerMutex); 83 84 remove(); 85 if (sDataOwners->isEmpty()) { 86 // Free the linked list if it's empty. 87 sDataOwners = nullptr; 88 } 89 90 free(mData); 91 } 92 93 public: 94 static void EnsureMemoryReporterRegistered(); 95 96 // sDataOwners and sMemoryReporterRegistered may only be accessed while 97 // holding sDataOwnerMutex! You also must hold the mutex while touching 98 // elements of the linked list that DataOwner inherits from. 99 static mozilla::StaticMutex sDataOwnerMutex; 100 static mozilla::StaticAutoPtr<mozilla::LinkedList<DataOwner> > sDataOwners; 101 static bool sMemoryReporterRegistered; 102 103 void* mData; 104 uint64_t mLength; 105 }; 106 107 class DataOwnerAdapter final : public nsIInputStream, 108 public nsISeekableStream, 109 public nsIIPCSerializableInputStream, 110 public nsICloneableInputStream { 111 typedef MemoryBlobImpl::DataOwner DataOwner; 112 113 public: 114 static nsresult Create(DataOwner* aDataOwner, uint32_t aStart, 115 uint32_t aLength, nsIInputStream** _retval); 116 117 NS_DECL_THREADSAFE_ISUPPORTS 118 NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM 119 120 // These are mandatory. 121 NS_FORWARD_NSIINPUTSTREAM(mStream->) 122 NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->) 123 NS_FORWARD_NSITELLABLESTREAM(mSeekableStream->) 124 NS_FORWARD_NSICLONEABLEINPUTSTREAM(mCloneableInputStream->) 125 126 private: 127 ~DataOwnerAdapter() = default; 128 DataOwnerAdapter(DataOwner * aDataOwner,nsIInputStream * aStream,uint32_t aLength)129 DataOwnerAdapter(DataOwner* aDataOwner, nsIInputStream* aStream, 130 uint32_t aLength) 131 : mDataOwner(aDataOwner), 132 mStream(aStream), 133 mSeekableStream(do_QueryInterface(aStream)), 134 mSerializableInputStream(do_QueryInterface(aStream)), 135 mCloneableInputStream(do_QueryInterface(aStream)), 136 mLength(aLength) { 137 MOZ_ASSERT( 138 mSeekableStream && mSerializableInputStream && mCloneableInputStream, 139 "Somebody gave us the wrong stream!"); 140 } 141 142 template <typename M> 143 void SerializeInternal(mozilla::ipc::InputStreamParams& aParams, 144 FileDescriptorArray& aFileDescriptors, 145 bool aDelayedStart, uint32_t aMaxSize, 146 uint32_t* aSizeUsed, M* aManager); 147 148 RefPtr<DataOwner> mDataOwner; 149 nsCOMPtr<nsIInputStream> mStream; 150 nsCOMPtr<nsISeekableStream> mSeekableStream; 151 nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream; 152 nsCOMPtr<nsICloneableInputStream> mCloneableInputStream; 153 uint32_t mLength; 154 }; 155 156 private: 157 // File constructor. MemoryBlobImpl(void * aMemoryBuffer,uint64_t aLength,const nsAString & aName,const nsAString & aContentType,int64_t aLastModifiedDate)158 MemoryBlobImpl(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName, 159 const nsAString& aContentType, int64_t aLastModifiedDate) 160 : BaseBlobImpl(aName, aContentType, aLength, aLastModifiedDate), 161 mDataOwner(new DataOwner(aMemoryBuffer, aLength)) { 162 MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data"); 163 } 164 165 // Create slice MemoryBlobImpl(const MemoryBlobImpl * aOther,uint64_t aStart,uint64_t aLength,const nsAString & aContentType)166 MemoryBlobImpl(const MemoryBlobImpl* aOther, uint64_t aStart, 167 uint64_t aLength, const nsAString& aContentType) 168 : BaseBlobImpl(aContentType, aOther->mStart + aStart, aLength), 169 mDataOwner(aOther->mDataOwner) { 170 MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data"); 171 } 172 173 ~MemoryBlobImpl() = default; 174 175 // Used when backed by a memory store 176 RefPtr<DataOwner> mDataOwner; 177 }; 178 179 } // namespace dom 180 } // namespace mozilla 181 182 #endif // mozilla_dom_MemoryBlobImpl_h 183