LCOV - code coverage report
Current view: top level - dom/file - MutableBlobStorage.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 311 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 49 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "MutableBlobStorage.h"
       8             : #include "MemoryBlobImpl.h"
       9             : #include "mozilla/CheckedInt.h"
      10             : #include "mozilla/Preferences.h"
      11             : #include "mozilla/TaskQueue.h"
      12             : #include "File.h"
      13             : #include "nsAnonymousTemporaryFile.h"
      14             : #include "nsNetCID.h"
      15             : #include "nsProxyRelease.h"
      16             : #include "WorkerPrivate.h"
      17             : 
      18             : #define BLOB_MEMORY_TEMPORARY_FILE 1048576
      19             : 
      20             : namespace mozilla {
      21             : namespace dom {
      22             : 
      23             : namespace {
      24             : 
      25             : // This class uses the callback to inform when the Blob is created or when the
      26             : // error must be propagated.
      27             : class BlobCreationDoneRunnable final : public Runnable
      28             : {
      29             : public:
      30           0 :   BlobCreationDoneRunnable(MutableBlobStorage* aBlobStorage,
      31             :                            MutableBlobStorageCallback* aCallback,
      32             :                            Blob* aBlob,
      33             :                            nsresult aRv)
      34           0 :     : Runnable("dom::BlobCreationDoneRunnable")
      35             :     , mBlobStorage(aBlobStorage)
      36             :     , mCallback(aCallback)
      37             :     , mBlob(aBlob)
      38           0 :     , mRv(aRv)
      39             :   {
      40           0 :     MOZ_ASSERT(aBlobStorage);
      41           0 :     MOZ_ASSERT(aCallback);
      42           0 :     MOZ_ASSERT((NS_FAILED(aRv) && !aBlob) ||
      43             :                (NS_SUCCEEDED(aRv) && aBlob));
      44           0 :   }
      45             : 
      46             :   NS_IMETHOD
      47           0 :   Run() override
      48             :   {
      49           0 :     MOZ_ASSERT(NS_IsMainThread());
      50           0 :     MOZ_ASSERT(mBlobStorage);
      51           0 :     mCallback->BlobStoreCompleted(mBlobStorage, mBlob, mRv);
      52           0 :     mCallback = nullptr;
      53           0 :     mBlob = nullptr;
      54           0 :     return NS_OK;
      55             :   }
      56             : 
      57             : private:
      58           0 :   ~BlobCreationDoneRunnable()
      59           0 :   {
      60           0 :     MOZ_ASSERT(mBlobStorage);
      61             :     // If something when wrong, we still have to release these objects in the
      62             :     // correct thread.
      63           0 :     NS_ProxyRelease(
      64             :       "BlobCreationDoneRunnable::mCallback",
      65           0 :       mBlobStorage->EventTarget(), mCallback.forget());
      66           0 :     NS_ProxyRelease(
      67             :       "BlobCreationDoneRunnable::mBlob",
      68           0 :       mBlobStorage->EventTarget(), mBlob.forget());
      69           0 :   }
      70             : 
      71             :   RefPtr<MutableBlobStorage> mBlobStorage;
      72             :   RefPtr<MutableBlobStorageCallback> mCallback;
      73             :   RefPtr<Blob> mBlob;
      74             :   nsresult mRv;
      75             : };
      76             : 
      77             : // This runnable goes back to the main-thread and informs the BlobStorage about
      78             : // the temporary file.
      79             : class FileCreatedRunnable final : public Runnable
      80             : {
      81             : public:
      82           0 :   FileCreatedRunnable(MutableBlobStorage* aBlobStorage, PRFileDesc* aFD)
      83           0 :     : Runnable("dom::FileCreatedRunnable")
      84             :     , mBlobStorage(aBlobStorage)
      85           0 :     , mFD(aFD)
      86             :   {
      87           0 :     MOZ_ASSERT(aBlobStorage);
      88           0 :     MOZ_ASSERT(aFD);
      89           0 :   }
      90             : 
      91             :   NS_IMETHOD
      92           0 :   Run() override
      93             :   {
      94           0 :     MOZ_ASSERT(NS_IsMainThread());
      95           0 :     mBlobStorage->TemporaryFileCreated(mFD);
      96           0 :     mFD = nullptr;
      97           0 :     return NS_OK;
      98             :   }
      99             : 
     100             : private:
     101           0 :   ~FileCreatedRunnable()
     102           0 :   {
     103             :     // If something when wrong, we still have to close the FileDescriptor.
     104           0 :     if (mFD) {
     105           0 :       PR_Close(mFD);
     106             :     }
     107           0 :   }
     108             : 
     109             :   RefPtr<MutableBlobStorage> mBlobStorage;
     110             :   PRFileDesc* mFD;
     111             : };
     112             : 
     113             : // This runnable creates the temporary file. When done, FileCreatedRunnable is
     114             : // dispatched back to the main-thread.
     115           0 : class CreateTemporaryFileRunnable final : public Runnable
     116             : {
     117             : public:
     118           0 :   explicit CreateTemporaryFileRunnable(MutableBlobStorage* aBlobStorage)
     119           0 :     : Runnable("dom::CreateTemporaryFileRunnable")
     120           0 :     , mBlobStorage(aBlobStorage)
     121             :   {
     122           0 :     MOZ_ASSERT(NS_IsMainThread());
     123           0 :     MOZ_ASSERT(XRE_IsParentProcess());
     124           0 :     MOZ_ASSERT(aBlobStorage);
     125           0 :   }
     126             : 
     127             :   NS_IMETHOD
     128           0 :   Run() override
     129             :   {
     130           0 :     MOZ_ASSERT(!NS_IsMainThread());
     131           0 :     MOZ_ASSERT(XRE_IsParentProcess());
     132           0 :     MOZ_ASSERT(mBlobStorage);
     133             : 
     134           0 :     PRFileDesc* tempFD = nullptr;
     135           0 :     nsresult rv = NS_OpenAnonymousTemporaryFile(&tempFD);
     136           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     137           0 :       return NS_OK;
     138             :     }
     139             : 
     140             :     // The ownership of the tempFD is moved to the FileCreatedRunnable.
     141           0 :     return mBlobStorage->EventTarget()->Dispatch(
     142           0 :       new FileCreatedRunnable(mBlobStorage, tempFD), NS_DISPATCH_NORMAL);
     143             :   }
     144             : 
     145             : private:
     146             :   RefPtr<MutableBlobStorage> mBlobStorage;
     147             : };
     148             : 
     149             : // Simple runnable to propagate the error to the BlobStorage.
     150           0 : class ErrorPropagationRunnable final : public Runnable
     151             : {
     152             : public:
     153           0 :   ErrorPropagationRunnable(MutableBlobStorage* aBlobStorage, nsresult aRv)
     154           0 :     : Runnable("dom::ErrorPropagationRunnable")
     155             :     , mBlobStorage(aBlobStorage)
     156           0 :     , mRv(aRv)
     157           0 :   {}
     158             : 
     159             :   NS_IMETHOD
     160           0 :   Run() override
     161             :   {
     162           0 :     mBlobStorage->ErrorPropagated(mRv);
     163           0 :     return NS_OK;
     164             :   }
     165             : 
     166             : private:
     167             :   RefPtr<MutableBlobStorage> mBlobStorage;
     168             :   nsresult mRv;
     169             : };
     170             : 
     171             : // This runnable moves a buffer to the IO thread and there, it writes it into
     172             : // the temporary file.
     173             : class WriteRunnable final : public Runnable
     174             : {
     175             : public:
     176             :   static WriteRunnable*
     177           0 :   CopyBuffer(MutableBlobStorage* aBlobStorage, PRFileDesc* aFD,
     178             :              const void* aData, uint32_t aLength)
     179             :   {
     180           0 :     MOZ_ASSERT(NS_IsMainThread());
     181           0 :     MOZ_ASSERT(aBlobStorage);
     182           0 :     MOZ_ASSERT(aFD);
     183           0 :     MOZ_ASSERT(aData);
     184             : 
     185             :     // We have to take a copy of this buffer.
     186           0 :     void* data = malloc(aLength);
     187           0 :     if (!data) {
     188           0 :       return nullptr;
     189             :     }
     190             : 
     191           0 :     memcpy((char*)data, aData, aLength);
     192           0 :     return new WriteRunnable(aBlobStorage, aFD, data, aLength);
     193             :   }
     194             : 
     195             :   static WriteRunnable*
     196           0 :   AdoptBuffer(MutableBlobStorage* aBlobStorage, PRFileDesc* aFD,
     197             :               void* aData, uint32_t aLength)
     198             :   {
     199           0 :     MOZ_ASSERT(NS_IsMainThread());
     200           0 :     MOZ_ASSERT(aBlobStorage);
     201           0 :     MOZ_ASSERT(aFD);
     202           0 :     MOZ_ASSERT(aData);
     203             : 
     204           0 :     return new WriteRunnable(aBlobStorage, aFD, aData, aLength);
     205             :   }
     206             : 
     207             :   NS_IMETHOD
     208           0 :   Run() override
     209             :   {
     210           0 :     MOZ_ASSERT(!NS_IsMainThread());
     211           0 :     MOZ_ASSERT(mBlobStorage);
     212             : 
     213           0 :     int32_t written = PR_Write(mFD, mData, mLength);
     214           0 :     if (NS_WARN_IF(written < 0 || uint32_t(written) != mLength)) {
     215           0 :       return mBlobStorage->EventTarget()->Dispatch(
     216           0 :         new ErrorPropagationRunnable(mBlobStorage, NS_ERROR_FAILURE),
     217           0 :         NS_DISPATCH_NORMAL);
     218             :     }
     219             : 
     220           0 :     return NS_OK;
     221             :   }
     222             : 
     223             : private:
     224           0 :   WriteRunnable(MutableBlobStorage* aBlobStorage,
     225             :                 PRFileDesc* aFD,
     226             :                 void* aData,
     227             :                 uint32_t aLength)
     228           0 :     : Runnable("dom::WriteRunnable")
     229             :     , mBlobStorage(aBlobStorage)
     230             :     , mFD(aFD)
     231             :     , mData(aData)
     232           0 :     , mLength(aLength)
     233             :   {
     234           0 :     MOZ_ASSERT(NS_IsMainThread());
     235           0 :     MOZ_ASSERT(mBlobStorage);
     236           0 :     MOZ_ASSERT(aFD);
     237           0 :     MOZ_ASSERT(aData);
     238           0 :   }
     239             : 
     240           0 :   ~WriteRunnable()
     241           0 :   {
     242           0 :     free(mData);
     243           0 :   }
     244             : 
     245             :   RefPtr<MutableBlobStorage> mBlobStorage;
     246             :   PRFileDesc* mFD;
     247             :   void* mData;
     248             :   uint32_t mLength;
     249             : };
     250             : 
     251             : // This runnable closes the FD in case something goes wrong or the temporary
     252             : // file is not needed anymore.
     253             : class CloseFileRunnable final : public Runnable
     254             : {
     255             : public:
     256           0 :   explicit CloseFileRunnable(PRFileDesc* aFD)
     257           0 :     : Runnable("dom::CloseFileRunnable")
     258           0 :     , mFD(aFD)
     259           0 :   {}
     260             : 
     261             :   NS_IMETHOD
     262           0 :   Run() override
     263             :   {
     264           0 :     MOZ_ASSERT(!NS_IsMainThread());
     265           0 :     PR_Close(mFD);
     266           0 :     mFD = nullptr;
     267           0 :     return NS_OK;
     268             :   }
     269             : 
     270             : private:
     271           0 :   ~CloseFileRunnable()
     272           0 :   {
     273           0 :     if (mFD) {
     274           0 :       PR_Close(mFD);
     275             :     }
     276           0 :   }
     277             : 
     278             :   PRFileDesc* mFD;
     279             : };
     280             : 
     281             : // This runnable is dispatched to the main-thread from the IO thread and its
     282             : // task is to create the blob and inform the callback.
     283             : class CreateBlobRunnable final : public Runnable
     284             : {
     285             : public:
     286           0 :   CreateBlobRunnable(MutableBlobStorage* aBlobStorage,
     287             :                      already_AddRefed<nsISupports> aParent,
     288             :                      const nsACString& aContentType,
     289             :                      already_AddRefed<MutableBlobStorageCallback> aCallback)
     290           0 :     : Runnable("dom::CreateBlobRunnable")
     291             :     , mBlobStorage(aBlobStorage)
     292             :     , mParent(aParent)
     293             :     , mContentType(aContentType)
     294           0 :     , mCallback(aCallback)
     295             :   {
     296           0 :     MOZ_ASSERT(!NS_IsMainThread());
     297           0 :     MOZ_ASSERT(aBlobStorage);
     298           0 :   }
     299             : 
     300             :   NS_IMETHOD
     301           0 :   Run() override
     302             :   {
     303           0 :     MOZ_ASSERT(NS_IsMainThread());
     304           0 :     MOZ_ASSERT(mBlobStorage);
     305           0 :     mBlobStorage->CreateBlobAndRespond(mParent.forget(), mContentType,
     306           0 :                                        mCallback.forget());
     307           0 :     return NS_OK;
     308             :   }
     309             : 
     310             : private:
     311           0 :   ~CreateBlobRunnable()
     312           0 :   {
     313           0 :     MOZ_ASSERT(mBlobStorage);
     314             :     // If something when wrong, we still have to release data in the correct
     315             :     // thread.
     316           0 :     NS_ProxyRelease(
     317             :       "CreateBlobRunnable::mParent",
     318           0 :       mBlobStorage->EventTarget(), mParent.forget());
     319           0 :     NS_ProxyRelease(
     320             :       "CreateBlobRunnable::mCallback",
     321           0 :       mBlobStorage->EventTarget(), mCallback.forget());
     322           0 :   }
     323             : 
     324             :   RefPtr<MutableBlobStorage> mBlobStorage;
     325             :   nsCOMPtr<nsISupports> mParent;
     326             :   nsCString mContentType;
     327             :   RefPtr<MutableBlobStorageCallback> mCallback;
     328             : };
     329             : 
     330             : // This task is used to know when the writing is completed. From the IO thread
     331             : // it dispatches a CreateBlobRunnable to the main-thread.
     332             : class LastRunnable final : public Runnable
     333             : {
     334             : public:
     335           0 :   LastRunnable(MutableBlobStorage* aBlobStorage,
     336             :                nsISupports* aParent,
     337             :                const nsACString& aContentType,
     338             :                MutableBlobStorageCallback* aCallback)
     339           0 :     : Runnable("dom::LastRunnable")
     340             :     , mBlobStorage(aBlobStorage)
     341             :     , mParent(aParent)
     342             :     , mContentType(aContentType)
     343           0 :     , mCallback(aCallback)
     344             :   {
     345           0 :     MOZ_ASSERT(NS_IsMainThread());
     346           0 :     MOZ_ASSERT(mBlobStorage);
     347           0 :     MOZ_ASSERT(aCallback);
     348           0 :   }
     349             : 
     350             :   NS_IMETHOD
     351           0 :   Run() override
     352             :   {
     353           0 :     MOZ_ASSERT(!NS_IsMainThread());
     354           0 :     MOZ_ASSERT(mBlobStorage);
     355             :     RefPtr<Runnable> runnable =
     356           0 :       new CreateBlobRunnable(mBlobStorage, mParent.forget(),
     357           0 :                              mContentType, mCallback.forget());
     358           0 :     return mBlobStorage->EventTarget()->Dispatch(runnable, NS_DISPATCH_NORMAL);
     359             :   }
     360             : 
     361             : private:
     362           0 :   ~LastRunnable()
     363           0 :   {
     364           0 :     MOZ_ASSERT(mBlobStorage);
     365             :     // If something when wrong, we still have to release data in the correct
     366             :     // thread.
     367           0 :     NS_ProxyRelease(
     368             :       "LastRunnable::mParent",
     369           0 :       mBlobStorage->EventTarget(), mParent.forget());
     370           0 :     NS_ProxyRelease(
     371             :       "LastRunnable::mCallback",
     372           0 :       mBlobStorage->EventTarget(), mCallback.forget());
     373           0 :   }
     374             : 
     375             :   RefPtr<MutableBlobStorage> mBlobStorage;
     376             :   nsCOMPtr<nsISupports> mParent;
     377             :   nsCString mContentType;
     378             :   RefPtr<MutableBlobStorageCallback> mCallback;
     379             : };
     380             : 
     381             : } // anonymous namespace
     382             : 
     383           0 : MutableBlobStorage::MutableBlobStorage(MutableBlobStorageType aType,
     384           0 :                                        nsIEventTarget* aEventTarget)
     385             :   : mData(nullptr)
     386             :   , mDataLen(0)
     387             :   , mDataBufferLen(0)
     388           0 :   , mStorageState(aType == eOnlyInMemory ? eKeepInMemory : eInMemory)
     389             :   , mFD(nullptr)
     390             :   , mErrorResult(NS_OK)
     391           0 :   , mEventTarget(aEventTarget)
     392             : {
     393           0 :   MOZ_ASSERT(NS_IsMainThread());
     394             : 
     395           0 :   if (!mEventTarget) {
     396           0 :     mEventTarget = GetMainThreadEventTarget();
     397             :   }
     398             : 
     399           0 :   MOZ_ASSERT(mEventTarget);
     400           0 : }
     401             : 
     402           0 : MutableBlobStorage::~MutableBlobStorage()
     403             : {
     404           0 :   free(mData);
     405             : 
     406           0 :   if (mFD) {
     407           0 :     RefPtr<Runnable> runnable = new CloseFileRunnable(mFD);
     408           0 :     DispatchToIOThread(runnable.forget());
     409             :   }
     410             : 
     411           0 :   if (mTaskQueue) {
     412           0 :     mTaskQueue->BeginShutdown();
     413             :   }
     414           0 : }
     415             : 
     416             : uint64_t
     417           0 : MutableBlobStorage::GetBlobWhenReady(nsISupports* aParent,
     418             :                                      const nsACString& aContentType,
     419             :                                      MutableBlobStorageCallback* aCallback)
     420             : {
     421           0 :   MOZ_ASSERT(NS_IsMainThread());
     422           0 :   MOZ_ASSERT(aCallback);
     423             : 
     424             :   // GetBlob can be called just once.
     425           0 :   MOZ_ASSERT(mStorageState != eClosed);
     426           0 :   StorageState previousState = mStorageState;
     427           0 :   mStorageState = eClosed;
     428             : 
     429           0 :   if (previousState == eInTemporaryFile) {
     430           0 :     MOZ_ASSERT(mFD);
     431             : 
     432           0 :     if (NS_FAILED(mErrorResult)) {
     433             :       RefPtr<Runnable> runnable =
     434           0 :         new BlobCreationDoneRunnable(this, aCallback, nullptr, mErrorResult);
     435           0 :       EventTarget()->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
     436           0 :       return 0;
     437             :     }
     438             : 
     439             :     // We want to wait until all the WriteRunnable are completed. The way we do
     440             :     // this is to go to the I/O thread and then we come back: the runnables are
     441             :     // executed in order and this LastRunnable will be... the last one.
     442             :     RefPtr<Runnable> runnable =
     443           0 :       new LastRunnable(this, aParent, aContentType, aCallback);
     444           0 :     DispatchToIOThread(runnable.forget());
     445           0 :     return mDataLen;
     446             :   }
     447             : 
     448             :   // If we are waiting for the temporary file, it's better to wait...
     449           0 :   if (previousState == eWaitingForTemporaryFile) {
     450           0 :     mPendingParent = aParent;
     451           0 :     mPendingContentType = aContentType;
     452           0 :     mPendingCallback = aCallback;
     453           0 :     return mDataLen;
     454             :   }
     455             : 
     456           0 :   RefPtr<BlobImpl> blobImpl;
     457             : 
     458           0 :   if (mData) {
     459             :     blobImpl = new MemoryBlobImpl(mData, mDataLen,
     460           0 :                                   NS_ConvertUTF8toUTF16(aContentType));
     461             : 
     462           0 :     mData = nullptr; // The MemoryBlobImpl takes ownership of the buffer
     463           0 :     mDataLen = 0;
     464           0 :     mDataBufferLen = 0;
     465             :   } else {
     466           0 :     blobImpl = new EmptyBlobImpl(NS_ConvertUTF8toUTF16(aContentType));
     467             :   }
     468             : 
     469           0 :   RefPtr<Blob> blob = Blob::Create(aParent, blobImpl);
     470             :   RefPtr<BlobCreationDoneRunnable> runnable =
     471           0 :     new BlobCreationDoneRunnable(this, aCallback, blob, NS_OK);
     472             : 
     473           0 :   nsresult error = EventTarget()->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
     474           0 :   if (NS_WARN_IF(NS_FAILED(error))) {
     475           0 :     return 0;
     476             :   }
     477             : 
     478           0 :   return mDataLen;
     479             : }
     480             : 
     481             : nsresult
     482           0 : MutableBlobStorage::Append(const void* aData, uint32_t aLength)
     483             : {
     484           0 :   MOZ_ASSERT(NS_IsMainThread());
     485           0 :   MOZ_ASSERT(mStorageState != eClosed);
     486           0 :   NS_ENSURE_ARG_POINTER(aData);
     487             : 
     488           0 :   if (!aLength) {
     489           0 :     return NS_OK;
     490             :   }
     491             : 
     492             :   // If eInMemory is the current Storage state, we could maybe migrate to
     493             :   // a temporary file.
     494           0 :   if (mStorageState == eInMemory && ShouldBeTemporaryStorage(aLength)) {
     495           0 :     nsresult rv = MaybeCreateTemporaryFile();
     496           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     497           0 :       return rv;
     498             :     }
     499             :   }
     500             : 
     501             :   // If we are already in the temporaryFile mode, we have to dispatch a
     502             :   // runnable.
     503           0 :   if (mStorageState == eInTemporaryFile) {
     504           0 :     MOZ_ASSERT(mFD);
     505             : 
     506             :     RefPtr<WriteRunnable> runnable =
     507           0 :       WriteRunnable::CopyBuffer(this, mFD, aData, aLength);
     508           0 :     if (NS_WARN_IF(!runnable)) {
     509           0 :       return NS_ERROR_OUT_OF_MEMORY;
     510             :     }
     511             : 
     512           0 :     DispatchToIOThread(runnable.forget());
     513             : 
     514           0 :     mDataLen += aLength;
     515           0 :     return NS_OK;
     516             :   }
     517             : 
     518             :   // By default, we store in memory.
     519             : 
     520           0 :   uint64_t offset = mDataLen;
     521             : 
     522           0 :   if (!ExpandBufferSize(aLength)) {
     523           0 :     return NS_ERROR_OUT_OF_MEMORY;
     524             :   }
     525             : 
     526           0 :   memcpy((char*)mData + offset, aData, aLength);
     527           0 :   return NS_OK;
     528             : }
     529             : 
     530             : bool
     531           0 : MutableBlobStorage::ExpandBufferSize(uint64_t aSize)
     532             : {
     533           0 :   MOZ_ASSERT(NS_IsMainThread());
     534           0 :   MOZ_ASSERT(mStorageState < eInTemporaryFile);
     535             : 
     536           0 :   if (mDataBufferLen >= mDataLen + aSize) {
     537           0 :     mDataLen += aSize;
     538           0 :     return true;
     539             :   }
     540             : 
     541             :   // Start at 1 or we'll loop forever.
     542             :   CheckedUint32 bufferLen =
     543           0 :     std::max<uint32_t>(static_cast<uint32_t>(mDataBufferLen), 1);
     544           0 :   while (bufferLen.isValid() && bufferLen.value() < mDataLen + aSize) {
     545           0 :     bufferLen *= 2;
     546             :   }
     547             : 
     548           0 :   if (!bufferLen.isValid()) {
     549           0 :     return false;
     550             :   }
     551             : 
     552           0 :   void* data = realloc(mData, bufferLen.value());
     553           0 :   if (!data) {
     554           0 :     return false;
     555             :   }
     556             : 
     557           0 :   mData = data;
     558           0 :   mDataBufferLen = bufferLen.value();
     559           0 :   mDataLen += aSize;
     560           0 :   return true;
     561             : }
     562             : 
     563             : bool
     564           0 : MutableBlobStorage::ShouldBeTemporaryStorage(uint64_t aSize) const
     565             : {
     566           0 :   MOZ_ASSERT(mStorageState == eInMemory);
     567             : 
     568           0 :   CheckedUint32 bufferSize = mDataLen;
     569           0 :   bufferSize += aSize;
     570             : 
     571           0 :   if (!bufferSize.isValid()) {
     572           0 :     return false;
     573             :   }
     574             : 
     575           0 :   return bufferSize.value() >= Preferences::GetUint("dom.blob.memoryToTemporaryFile",
     576           0 :                                                     BLOB_MEMORY_TEMPORARY_FILE);
     577             : }
     578             : 
     579             : nsresult
     580           0 : MutableBlobStorage::MaybeCreateTemporaryFile()
     581             : {
     582           0 :   if (XRE_IsParentProcess()) {
     583           0 :     RefPtr<Runnable> runnable = new CreateTemporaryFileRunnable(this);
     584           0 :     DispatchToIOThread(runnable.forget());
     585             :   } else {
     586           0 :     RefPtr<MutableBlobStorage> self(this);
     587             :     ContentChild::GetSingleton()->
     588           0 :       AsyncOpenAnonymousTemporaryFile([self](PRFileDesc* prfile) {
     589           0 :         if (prfile) {
     590             :           // The ownership of the prfile is moved to the FileCreatedRunnable.
     591           0 :           self->EventTarget()->Dispatch(
     592           0 :             new FileCreatedRunnable(self, prfile), NS_DISPATCH_NORMAL);
     593             :         }
     594           0 :       });
     595             :   }
     596             : 
     597           0 :   mStorageState = eWaitingForTemporaryFile;
     598           0 :   return NS_OK;
     599             : }
     600             : 
     601             : void
     602           0 : MutableBlobStorage::TemporaryFileCreated(PRFileDesc* aFD)
     603             : {
     604           0 :   MOZ_ASSERT(NS_IsMainThread());
     605           0 :   MOZ_ASSERT(mStorageState == eWaitingForTemporaryFile ||
     606             :              mStorageState == eClosed);
     607           0 :   MOZ_ASSERT_IF(mPendingCallback, mStorageState == eClosed);
     608             : 
     609             :   // If the object has been already closed and we don't need to execute a
     610             :   // callback, we need just to close the file descriptor in the correct thread.
     611           0 :   if (mStorageState == eClosed && !mPendingCallback) {
     612           0 :     RefPtr<Runnable> runnable = new CloseFileRunnable(aFD);
     613           0 :     DispatchToIOThread(runnable.forget());
     614           0 :     return;
     615             :   }
     616             : 
     617             :   // If we still receiving data, we can proceed in temporary-file mode.
     618           0 :   if (mStorageState == eWaitingForTemporaryFile) {
     619           0 :     mStorageState = eInTemporaryFile;
     620             :   }
     621             : 
     622           0 :   mFD = aFD;
     623             : 
     624             :   // This runnable takes the ownership of mData and it will write this buffer
     625             :   // into the temporary file.
     626             :   RefPtr<WriteRunnable> runnable =
     627           0 :     WriteRunnable::AdoptBuffer(this, mFD, mData, mDataLen);
     628           0 :   MOZ_ASSERT(runnable);
     629             : 
     630           0 :   mData = nullptr;
     631             : 
     632           0 :   DispatchToIOThread(runnable.forget());
     633             : 
     634             :   // If we are closed, it means that GetBlobWhenReady() has been called when we
     635             :   // were already waiting for a temporary file-descriptor. Finally we are here,
     636             :   // AdoptBuffer runnable is going to write the current buffer into this file.
     637             :   // After that, there is nothing else to write, and we dispatch LastRunnable
     638             :   // which ends up calling mPendingCallback via CreateBlobRunnable.
     639           0 :   if (mStorageState == eClosed) {
     640           0 :     MOZ_ASSERT(mPendingCallback);
     641             : 
     642             :     RefPtr<Runnable> runnable =
     643             :       new LastRunnable(this, mPendingParent, mPendingContentType,
     644           0 :                        mPendingCallback);
     645           0 :     DispatchToIOThread(runnable.forget());
     646             : 
     647           0 :     mPendingParent = nullptr;
     648           0 :     mPendingCallback = nullptr;
     649             :   }
     650             : }
     651             : 
     652             : void
     653           0 : MutableBlobStorage::CreateBlobAndRespond(already_AddRefed<nsISupports> aParent,
     654             :                                          const nsACString& aContentType,
     655             :                                          already_AddRefed<MutableBlobStorageCallback> aCallback)
     656             : {
     657           0 :   MOZ_ASSERT(NS_IsMainThread());
     658           0 :   MOZ_ASSERT(mStorageState == eClosed);
     659           0 :   MOZ_ASSERT(mFD);
     660             : 
     661           0 :   nsCOMPtr<nsISupports> parent(aParent);
     662           0 :   RefPtr<MutableBlobStorageCallback> callback(aCallback);
     663             : 
     664             :   RefPtr<Blob> blob =
     665           0 :     File::CreateTemporaryBlob(parent, mFD, 0, mDataLen,
     666           0 :                               NS_ConvertUTF8toUTF16(aContentType));
     667           0 :   callback->BlobStoreCompleted(this, blob, NS_OK);
     668             : 
     669             :   // ownership of this FD is moved to the BlobImpl.
     670           0 :   mFD = nullptr;
     671           0 : }
     672             : 
     673             : void
     674           0 : MutableBlobStorage::ErrorPropagated(nsresult aRv)
     675             : {
     676           0 :   MOZ_ASSERT(NS_IsMainThread());
     677           0 :   mErrorResult = aRv;
     678           0 : }
     679             : 
     680             : void
     681           0 : MutableBlobStorage::DispatchToIOThread(already_AddRefed<nsIRunnable> aRunnable)
     682             : {
     683           0 :   if (!mTaskQueue) {
     684             :     nsCOMPtr<nsIEventTarget> target
     685           0 :       = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
     686           0 :     MOZ_ASSERT(target);
     687             : 
     688           0 :     mTaskQueue = new TaskQueue(target.forget());
     689             :   }
     690             : 
     691           0 :   nsCOMPtr<nsIRunnable> runnable(aRunnable);
     692           0 :   mTaskQueue->Dispatch(runnable.forget());
     693           0 : }
     694             : 
     695             : } // dom namespace
     696             : } // mozilla namespace

Generated by: LCOV version 1.13