LCOV - code coverage report
Current view: top level - dom/file - MultipartBlobImpl.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 189 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 14 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 "MultipartBlobImpl.h"
       8             : #include "jsfriendapi.h"
       9             : #include "mozilla/dom/BlobSet.h"
      10             : #include "mozilla/dom/FileBinding.h"
      11             : #include "mozilla/dom/UnionTypes.h"
      12             : #include "nsDOMClassInfoID.h"
      13             : #include "nsIMultiplexInputStream.h"
      14             : #include "nsRFPService.h"
      15             : #include "nsStringStream.h"
      16             : #include "nsTArray.h"
      17             : #include "nsJSUtils.h"
      18             : #include "nsContentUtils.h"
      19             : #include "nsIScriptError.h"
      20             : #include "nsIXPConnect.h"
      21             : #include <algorithm>
      22             : 
      23             : using namespace mozilla;
      24             : using namespace mozilla::dom;
      25             : 
      26           0 : NS_IMPL_ISUPPORTS_INHERITED0(MultipartBlobImpl, BlobImpl)
      27             : 
      28             : /* static */ already_AddRefed<MultipartBlobImpl>
      29           0 : MultipartBlobImpl::Create(nsTArray<RefPtr<BlobImpl>>&& aBlobImpls,
      30             :                           const nsAString& aName,
      31             :                           const nsAString& aContentType,
      32             :                           ErrorResult& aRv)
      33             : {
      34             :   RefPtr<MultipartBlobImpl> blobImpl =
      35           0 :     new MultipartBlobImpl(Move(aBlobImpls), aName, aContentType);
      36           0 :   blobImpl->SetLengthAndModifiedDate(aRv);
      37           0 :   if (NS_WARN_IF(aRv.Failed())) {
      38           0 :     return nullptr;
      39             :   }
      40             : 
      41           0 :   return blobImpl.forget();
      42             : }
      43             : 
      44             : /* static */ already_AddRefed<MultipartBlobImpl>
      45           0 : MultipartBlobImpl::Create(nsTArray<RefPtr<BlobImpl>>&& aBlobImpls,
      46             :                           const nsAString& aContentType,
      47             :                           ErrorResult& aRv)
      48             : {
      49             :   RefPtr<MultipartBlobImpl> blobImpl =
      50           0 :     new MultipartBlobImpl(Move(aBlobImpls), aContentType);
      51           0 :   blobImpl->SetLengthAndModifiedDate(aRv);
      52           0 :   if (NS_WARN_IF(aRv.Failed())) {
      53           0 :     return nullptr;
      54             :   }
      55             : 
      56           0 :   return blobImpl.forget();
      57             : }
      58             : 
      59             : void
      60           0 : MultipartBlobImpl::GetInternalStream(nsIInputStream** aStream,
      61             :                                      ErrorResult& aRv)
      62             : {
      63           0 :   *aStream = nullptr;
      64             : 
      65             :   nsCOMPtr<nsIMultiplexInputStream> stream =
      66           0 :     do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
      67           0 :   if (NS_WARN_IF(!stream)) {
      68           0 :     aRv.Throw(NS_ERROR_FAILURE);
      69           0 :     return;
      70             :   }
      71             : 
      72             :   uint32_t i;
      73           0 :   for (i = 0; i < mBlobImpls.Length(); i++) {
      74           0 :     nsCOMPtr<nsIInputStream> scratchStream;
      75           0 :     BlobImpl* blobImpl = mBlobImpls.ElementAt(i).get();
      76             : 
      77           0 :     blobImpl->GetInternalStream(getter_AddRefs(scratchStream), aRv);
      78           0 :     if (NS_WARN_IF(aRv.Failed())) {
      79           0 :       return;
      80             :     }
      81             : 
      82           0 :     aRv = stream->AppendStream(scratchStream);
      83           0 :     if (NS_WARN_IF(aRv.Failed())) {
      84           0 :       return;
      85             :     }
      86             :   }
      87             : 
      88           0 :   stream.forget(aStream);
      89             : }
      90             : 
      91             : already_AddRefed<BlobImpl>
      92           0 : MultipartBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
      93             :                                const nsAString& aContentType,
      94             :                                ErrorResult& aRv)
      95             : {
      96             :   // If we clamped to nothing we create an empty blob
      97           0 :   nsTArray<RefPtr<BlobImpl>> blobImpls;
      98             : 
      99           0 :   uint64_t length = aLength;
     100           0 :   uint64_t skipStart = aStart;
     101             : 
     102             :   // Prune the list of blobs if we can
     103             :   uint32_t i;
     104           0 :   for (i = 0; length && skipStart && i < mBlobImpls.Length(); i++) {
     105           0 :     BlobImpl* blobImpl = mBlobImpls[i].get();
     106             : 
     107           0 :     uint64_t l = blobImpl->GetSize(aRv);
     108           0 :     if (NS_WARN_IF(aRv.Failed())) {
     109           0 :       return nullptr;
     110             :     }
     111             : 
     112           0 :     if (skipStart < l) {
     113           0 :       uint64_t upperBound = std::min<uint64_t>(l - skipStart, length);
     114             : 
     115             :       RefPtr<BlobImpl> firstBlobImpl =
     116           0 :         blobImpl->CreateSlice(skipStart, upperBound,
     117           0 :                               aContentType, aRv);
     118           0 :       if (NS_WARN_IF(aRv.Failed())) {
     119           0 :         return nullptr;
     120             :       }
     121             : 
     122             :       // Avoid wrapping a single blob inside an MultipartBlobImpl
     123           0 :       if (length == upperBound) {
     124           0 :         return firstBlobImpl.forget();
     125             :       }
     126             : 
     127           0 :       blobImpls.AppendElement(firstBlobImpl);
     128           0 :       length -= upperBound;
     129           0 :       i++;
     130           0 :       break;
     131             :     }
     132           0 :     skipStart -= l;
     133             :   }
     134             : 
     135             :   // Now append enough blobs until we're done
     136           0 :   for (; length && i < mBlobImpls.Length(); i++) {
     137           0 :     BlobImpl* blobImpl = mBlobImpls[i].get();
     138             : 
     139           0 :     uint64_t l = blobImpl->GetSize(aRv);
     140           0 :     if (NS_WARN_IF(aRv.Failed())) {
     141           0 :       return nullptr;
     142             :     }
     143             : 
     144           0 :     if (length < l) {
     145             :       RefPtr<BlobImpl> lastBlobImpl =
     146           0 :         blobImpl->CreateSlice(0, length, aContentType, aRv);
     147           0 :       if (NS_WARN_IF(aRv.Failed())) {
     148           0 :         return nullptr;
     149             :       }
     150             : 
     151           0 :       blobImpls.AppendElement(lastBlobImpl);
     152             :     } else {
     153           0 :       blobImpls.AppendElement(blobImpl);
     154             :     }
     155           0 :     length -= std::min<uint64_t>(l, length);
     156             :   }
     157             : 
     158             :   // we can create our blob now
     159           0 :   RefPtr<BlobImpl> impl = Create(Move(blobImpls), aContentType, aRv);
     160           0 :   if (NS_WARN_IF(aRv.Failed())) {
     161           0 :     return nullptr;
     162             :   }
     163             : 
     164           0 :   return impl.forget();
     165             : }
     166             : 
     167             : void
     168           0 : MultipartBlobImpl::InitializeBlob(ErrorResult& aRv)
     169             : {
     170           0 :   SetLengthAndModifiedDate(aRv);
     171           0 :   NS_WARNING_ASSERTION(!aRv.Failed(), "SetLengthAndModifiedDate failed");
     172           0 : }
     173             : 
     174             : void
     175           0 : MultipartBlobImpl::InitializeBlob(const Sequence<Blob::BlobPart>& aData,
     176             :                                   const nsAString& aContentType,
     177             :                                   bool aNativeEOL,
     178             :                                   ErrorResult& aRv)
     179             : {
     180           0 :   mContentType = aContentType;
     181           0 :   BlobSet blobSet;
     182             : 
     183           0 :   for (uint32_t i = 0, len = aData.Length(); i < len; ++i) {
     184           0 :     const Blob::BlobPart& data = aData[i];
     185             : 
     186           0 :     if (data.IsBlob()) {
     187           0 :       RefPtr<Blob> blob = data.GetAsBlob().get();
     188           0 :       blobSet.AppendBlobImpl(blob->Impl());
     189             :     }
     190             : 
     191           0 :     else if (data.IsUSVString()) {
     192           0 :       aRv = blobSet.AppendString(data.GetAsUSVString(), aNativeEOL);
     193           0 :       if (aRv.Failed()) {
     194           0 :         return;
     195             :       }
     196             :     }
     197             : 
     198           0 :     else if (data.IsArrayBuffer()) {
     199           0 :       const ArrayBuffer& buffer = data.GetAsArrayBuffer();
     200           0 :       buffer.ComputeLengthAndData();
     201           0 :       aRv = blobSet.AppendVoidPtr(buffer.Data(), buffer.Length());
     202           0 :       if (aRv.Failed()) {
     203           0 :         return;
     204             :       }
     205             :     }
     206             : 
     207           0 :     else if (data.IsArrayBufferView()) {
     208           0 :       const ArrayBufferView& buffer = data.GetAsArrayBufferView();
     209           0 :       buffer.ComputeLengthAndData();
     210           0 :       aRv = blobSet.AppendVoidPtr(buffer.Data(), buffer.Length());
     211           0 :       if (aRv.Failed()) {
     212           0 :         return;
     213             :       }
     214             :     }
     215             : 
     216             :     else {
     217           0 :       MOZ_CRASH("Impossible blob data type.");
     218             :     }
     219             :   }
     220             : 
     221             : 
     222           0 :   mBlobImpls = blobSet.GetBlobImpls();
     223           0 :   SetLengthAndModifiedDate(aRv);
     224           0 :   NS_WARNING_ASSERTION(!aRv.Failed(), "SetLengthAndModifiedDate failed");
     225             : }
     226             : 
     227             : void
     228           0 : MultipartBlobImpl::SetLengthAndModifiedDate(ErrorResult& aRv)
     229             : {
     230           0 :   MOZ_ASSERT(mLength == UINT64_MAX);
     231           0 :   MOZ_ASSERT(mLastModificationDate == INT64_MAX);
     232             : 
     233           0 :   uint64_t totalLength = 0;
     234           0 :   int64_t lastModified = 0;
     235           0 :   bool lastModifiedSet = false;
     236             : 
     237           0 :   for (uint32_t index = 0, count = mBlobImpls.Length(); index < count; index++) {
     238           0 :     RefPtr<BlobImpl>& blob = mBlobImpls[index];
     239             : 
     240             : #ifdef DEBUG
     241           0 :     MOZ_ASSERT(!blob->IsSizeUnknown());
     242           0 :     MOZ_ASSERT(!blob->IsDateUnknown());
     243             : #endif
     244             : 
     245           0 :     uint64_t subBlobLength = blob->GetSize(aRv);
     246           0 :     if (NS_WARN_IF(aRv.Failed())) {
     247           0 :       return;
     248             :     }
     249             : 
     250           0 :     MOZ_ASSERT(UINT64_MAX - subBlobLength >= totalLength);
     251           0 :     totalLength += subBlobLength;
     252             : 
     253           0 :     if (blob->IsFile()) {
     254           0 :       int64_t partLastModified = blob->GetLastModified(aRv);
     255           0 :       if (NS_WARN_IF(aRv.Failed())) {
     256           0 :         return;
     257             :       }
     258             : 
     259           0 :       if (lastModified < partLastModified) {
     260           0 :         lastModified = partLastModified;
     261           0 :         lastModifiedSet = true;
     262             :       }
     263             :     }
     264             :   }
     265             : 
     266           0 :   mLength = totalLength;
     267             : 
     268           0 :   if (mIsFile) {
     269             :     // We cannot use PR_Now() because bug 493756 and, for this reason:
     270             :     //   var x = new Date(); var f = new File(...);
     271             :     //   x.getTime() < f.dateModified.getTime()
     272             :     // could fail.
     273           0 :     mLastModificationDate = nsRFPService::ReduceTimePrecisionAsUSecs(
     274           0 :       lastModifiedSet ? lastModified * PR_USEC_PER_MSEC : JS_Now());
     275             :   }
     276             : }
     277             : 
     278             : void
     279           0 : MultipartBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
     280             :                                           ErrorResult& aRv) const
     281             : {
     282           0 :   if (!mIsFromNsIFile || mBlobImpls.Length() == 0) {
     283           0 :     BaseBlobImpl::GetMozFullPathInternal(aFilename, aRv);
     284           0 :     return;
     285             :   }
     286             : 
     287           0 :   BlobImpl* blobImpl = mBlobImpls.ElementAt(0).get();
     288           0 :   if (!blobImpl) {
     289           0 :     BaseBlobImpl::GetMozFullPathInternal(aFilename, aRv);
     290           0 :     return;
     291             :   }
     292             : 
     293           0 :   blobImpl->GetMozFullPathInternal(aFilename, aRv);
     294             : }
     295             : 
     296             : nsresult
     297           0 : MultipartBlobImpl::SetMutable(bool aMutable)
     298             : {
     299             :   nsresult rv;
     300             : 
     301             :   // This looks a little sketchy since BlobImpl objects are supposed to be
     302             :   // threadsafe. However, we try to enforce that all BlobImpl objects must be
     303             :   // set to immutable *before* being passed to another thread, so this should
     304             :   // be safe.
     305           0 :   if (!aMutable && !mImmutable && !mBlobImpls.IsEmpty()) {
     306           0 :     for (uint32_t index = 0, count = mBlobImpls.Length();
     307           0 :          index < count;
     308             :          index++) {
     309           0 :       rv = mBlobImpls[index]->SetMutable(aMutable);
     310           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     311           0 :         return rv;
     312             :       }
     313             :     }
     314             :   }
     315             : 
     316           0 :   rv = BaseBlobImpl::SetMutable(aMutable);
     317           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     318           0 :     return rv;
     319             :   }
     320             : 
     321           0 :   MOZ_ASSERT_IF(!aMutable, mImmutable);
     322             : 
     323           0 :   return NS_OK;
     324             : }
     325             : 
     326             : nsresult
     327           0 : MultipartBlobImpl::InitializeChromeFile(nsIFile* aFile,
     328             :                                         const nsAString& aType,
     329             :                                         const nsAString& aName,
     330             :                                         bool aLastModifiedPassed,
     331             :                                         int64_t aLastModified,
     332             :                                         bool aIsFromNsIFile)
     333             : {
     334           0 :   MOZ_ASSERT(!mImmutable, "Something went wrong ...");
     335           0 :   if (mImmutable) {
     336           0 :     return NS_ERROR_UNEXPECTED;
     337             :   }
     338             : 
     339           0 :   mName = aName;
     340           0 :   mContentType = aType;
     341           0 :   mIsFromNsIFile = aIsFromNsIFile;
     342             : 
     343             :   bool exists;
     344           0 :   nsresult rv= aFile->Exists(&exists);
     345           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     346           0 :     return rv;
     347             :   }
     348             : 
     349           0 :   if (!exists) {
     350           0 :     return NS_ERROR_FILE_NOT_FOUND;
     351             :   }
     352             : 
     353             :   bool isDir;
     354           0 :   rv = aFile->IsDirectory(&isDir);
     355           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     356           0 :     return rv;
     357             :   }
     358             : 
     359           0 :   if (isDir) {
     360           0 :     return NS_ERROR_FILE_IS_DIRECTORY;
     361             :   }
     362             : 
     363           0 :   if (mName.IsEmpty()) {
     364           0 :     aFile->GetLeafName(mName);
     365             :   }
     366             : 
     367           0 :   RefPtr<File> blob = File::CreateFromFile(nullptr, aFile);
     368             : 
     369             :   // Pre-cache size.
     370           0 :   ErrorResult error;
     371           0 :   blob->GetSize(error);
     372           0 :   if (NS_WARN_IF(error.Failed())) {
     373           0 :     return error.StealNSResult();
     374             :   }
     375             : 
     376             :   // Pre-cache modified date.
     377           0 :   blob->GetLastModified(error);
     378           0 :   if (NS_WARN_IF(error.Failed())) {
     379           0 :     return error.StealNSResult();
     380             :   }
     381             : 
     382             :   // XXXkhuey this is terrible
     383           0 :   if (mContentType.IsEmpty()) {
     384           0 :     blob->GetType(mContentType);
     385             :   }
     386             : 
     387           0 :   BlobSet blobSet;
     388           0 :   blobSet.AppendBlobImpl(static_cast<File*>(blob.get())->Impl());
     389           0 :   mBlobImpls = blobSet.GetBlobImpls();
     390             : 
     391           0 :   SetLengthAndModifiedDate(error);
     392           0 :   if (NS_WARN_IF(error.Failed())) {
     393           0 :     return error.StealNSResult();
     394             :   }
     395             : 
     396           0 :   if (aLastModifiedPassed) {
     397           0 :     SetLastModified(aLastModified);
     398             :   }
     399             : 
     400           0 :   return NS_OK;
     401             : }
     402             : 
     403             : bool
     404           0 : MultipartBlobImpl::MayBeClonedToOtherThreads() const
     405             : {
     406           0 :   for (uint32_t i = 0; i < mBlobImpls.Length(); ++i) {
     407           0 :     if (!mBlobImpls[i]->MayBeClonedToOtherThreads()) {
     408           0 :       return false;
     409             :     }
     410             :   }
     411             : 
     412           0 :   return true;
     413             : }

Generated by: LCOV version 1.13