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