content/base/src/nsDOMFile.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; 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/. */
     7 #include "nsDOMFile.h"
     9 #include "nsCExternalHandlerService.h"
    10 #include "nsContentCID.h"
    11 #include "nsContentUtils.h"
    12 #include "nsDOMClassInfoID.h"
    13 #include "nsError.h"
    14 #include "nsICharsetDetector.h"
    15 #include "nsIClassInfo.h"
    16 #include "nsIConverterInputStream.h"
    17 #include "nsIDocument.h"
    18 #include "nsIFileStreams.h"
    19 #include "nsIInputStream.h"
    20 #include "nsIIPCSerializableInputStream.h"
    21 #include "nsIMemoryReporter.h"
    22 #include "nsIMIMEService.h"
    23 #include "nsISeekableStream.h"
    24 #include "nsIUnicharInputStream.h"
    25 #include "nsIUnicodeDecoder.h"
    26 #include "nsNetCID.h"
    27 #include "nsNetUtil.h"
    28 #include "nsIUUIDGenerator.h"
    29 #include "nsHostObjectProtocolHandler.h"
    30 #include "nsStringStream.h"
    31 #include "nsJSUtils.h"
    32 #include "nsPrintfCString.h"
    33 #include "mozilla/SHA1.h"
    34 #include "mozilla/CheckedInt.h"
    35 #include "mozilla/Preferences.h"
    36 #include "mozilla/Attributes.h"
    37 #include "nsThreadUtils.h"
    39 #include "mozilla/dom/FileListBinding.h"
    40 using namespace mozilla;
    41 using namespace mozilla::dom;
    43 // XXXkhuey the input stream that we pass out of a DOMFile
    44 // can outlive the actual DOMFile object.  Thus, we must
    45 // ensure that the buffer underlying the stream we get
    46 // from NS_NewByteInputStream is held alive as long as the
    47 // stream is.  We do that by passing back this class instead.
    48 class DataOwnerAdapter MOZ_FINAL : public nsIInputStream,
    49                                    public nsISeekableStream,
    50                                    public nsIIPCSerializableInputStream
    51 {
    52   typedef nsDOMMemoryFile::DataOwner DataOwner;
    53 public:
    54   static nsresult Create(DataOwner* aDataOwner,
    55                          uint32_t aStart,
    56                          uint32_t aLength,
    57                          nsIInputStream** _retval);
    59   NS_DECL_THREADSAFE_ISUPPORTS
    61   // These are mandatory.
    62   NS_FORWARD_NSIINPUTSTREAM(mStream->)
    63   NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->)
    65   // This is optional. We use a conditional QI to keep it from being called
    66   // if the underlying stream doesn't support it.
    67   NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(mSerializableInputStream->)
    69 private:
    70   DataOwnerAdapter(DataOwner* aDataOwner,
    71                    nsIInputStream* aStream)
    72     : mDataOwner(aDataOwner), mStream(aStream),
    73       mSeekableStream(do_QueryInterface(aStream)),
    74       mSerializableInputStream(do_QueryInterface(aStream))
    75   {
    76     NS_ASSERTION(mSeekableStream, "Somebody gave us the wrong stream!");
    77   }
    79   nsRefPtr<DataOwner> mDataOwner;
    80   nsCOMPtr<nsIInputStream> mStream;
    81   nsCOMPtr<nsISeekableStream> mSeekableStream;
    82   nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream;
    83 };
    85 NS_IMPL_ADDREF(DataOwnerAdapter)
    86 NS_IMPL_RELEASE(DataOwnerAdapter)
    88 NS_INTERFACE_MAP_BEGIN(DataOwnerAdapter)
    89   NS_INTERFACE_MAP_ENTRY(nsIInputStream)
    90   NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
    91   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
    92                                      mSerializableInputStream)
    93   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
    94 NS_INTERFACE_MAP_END
    96 nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
    97                                   uint32_t aStart,
    98                                   uint32_t aLength,
    99                                   nsIInputStream** _retval)
   100 {
   101   nsresult rv;
   102   NS_ASSERTION(aDataOwner, "Uh ...");
   104   nsCOMPtr<nsIInputStream> stream;
   106   rv = NS_NewByteInputStream(getter_AddRefs(stream),
   107                              static_cast<const char*>(aDataOwner->mData) +
   108                              aStart,
   109                              (int32_t)aLength,
   110                              NS_ASSIGNMENT_DEPEND);
   111   NS_ENSURE_SUCCESS(rv, rv);
   113   NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
   115   return NS_OK;
   116 }
   118 ////////////////////////////////////////////////////////////////////////////
   119 // nsDOMFileBase implementation
   121 NS_IMETHODIMP
   122 nsDOMFileBase::GetName(nsAString &aFileName)
   123 {
   124   NS_ASSERTION(mIsFile, "Should only be called on files");
   125   aFileName = mName;
   126   return NS_OK;
   127 }
   129 NS_IMETHODIMP
   130 nsDOMFileBase::GetPath(nsAString &aPath)
   131 {
   132   NS_ASSERTION(mIsFile, "Should only be called on files");
   133   aPath = mPath;
   134   return NS_OK;
   135 }
   137 NS_IMETHODIMP
   138 nsDOMFileBase::GetLastModifiedDate(JSContext* cx, JS::MutableHandle<JS::Value> aLastModifiedDate)
   139 {
   140   JS::Rooted<JSObject*> date(cx, JS_NewDateObjectMsec(cx, JS_Now() / PR_USEC_PER_MSEC));
   141   if (!date) {
   142     return NS_ERROR_OUT_OF_MEMORY;
   143   }
   144   aLastModifiedDate.setObject(*date);
   145   return NS_OK;
   146 }
   148 NS_IMETHODIMP
   149 nsDOMFileBase::GetMozFullPath(nsAString &aFileName)
   150 {
   151   NS_ASSERTION(mIsFile, "Should only be called on files");
   153   // It is unsafe to call IsCallerChrome on a non-main thread. If
   154   // you hit the following assertion you need to figure out some other way to
   155   // determine privileges and call GetMozFullPathInternal.
   156   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   158   if (nsContentUtils::IsCallerChrome()) {
   159     return GetMozFullPathInternal(aFileName);
   160   }
   161   aFileName.Truncate();
   162   return NS_OK;
   163 }
   165 NS_IMETHODIMP
   166 nsDOMFileBase::GetMozFullPathInternal(nsAString &aFileName)
   167 {
   168   if (!mIsFile) {
   169     return NS_ERROR_FAILURE;
   170   }
   172   aFileName.Truncate();
   173   return NS_OK;
   174 }
   176 NS_IMETHODIMP
   177 nsDOMFileBase::GetSize(uint64_t *aSize)
   178 {
   179   *aSize = mLength;
   180   return NS_OK;
   181 }
   183 NS_IMETHODIMP
   184 nsDOMFileBase::GetType(nsAString &aType)
   185 {
   186   aType = mContentType;
   187   return NS_OK;
   188 }
   190 NS_IMETHODIMP
   191 nsDOMFileBase::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
   192 {
   193   NS_ASSERTION(mIsFile, "Should only be called on files");
   194   if (IsDateUnknown()) {
   195     mLastModificationDate = PR_Now();
   196   }
   197   *aLastModifiedDate = mLastModificationDate;
   198   return NS_OK;
   199 }
   201 // Makes sure that aStart and aEnd is less then or equal to aSize and greater
   202 // than 0
   203 static void
   204 ParseSize(int64_t aSize, int64_t& aStart, int64_t& aEnd)
   205 {
   206   CheckedInt64 newStartOffset = aStart;
   207   if (aStart < -aSize) {
   208     newStartOffset = 0;
   209   }
   210   else if (aStart < 0) {
   211     newStartOffset += aSize;
   212   }
   213   else if (aStart > aSize) {
   214     newStartOffset = aSize;
   215   }
   217   CheckedInt64 newEndOffset = aEnd;
   218   if (aEnd < -aSize) {
   219     newEndOffset = 0;
   220   }
   221   else if (aEnd < 0) {
   222     newEndOffset += aSize;
   223   }
   224   else if (aEnd > aSize) {
   225     newEndOffset = aSize;
   226   }
   228   if (!newStartOffset.isValid() || !newEndOffset.isValid() ||
   229       newStartOffset.value() >= newEndOffset.value()) {
   230     aStart = aEnd = 0;
   231   }
   232   else {
   233     aStart = newStartOffset.value();
   234     aEnd = newEndOffset.value();
   235   }
   236 }
   238 NS_IMETHODIMP
   239 nsDOMFileBase::Slice(int64_t aStart, int64_t aEnd,
   240                      const nsAString& aContentType, uint8_t optional_argc,
   241                      nsIDOMBlob **aBlob)
   242 {
   243   *aBlob = nullptr;
   245   // Truncate aStart and aEnd so that we stay within this file.
   246   uint64_t thisLength;
   247   nsresult rv = GetSize(&thisLength);
   248   NS_ENSURE_SUCCESS(rv, rv);
   250   if (optional_argc < 2) {
   251     aEnd = (int64_t)thisLength;
   252   }
   254   ParseSize((int64_t)thisLength, aStart, aEnd);
   256   // Create the new file
   257   *aBlob = CreateSlice((uint64_t)aStart, (uint64_t)(aEnd - aStart),
   258                        aContentType).take();
   260   return *aBlob ? NS_OK : NS_ERROR_UNEXPECTED;
   261 }
   263 NS_IMETHODIMP
   264 nsDOMFileBase::GetInternalStream(nsIInputStream **aStream)
   265 {
   266   // Must be overridden
   267   NS_NOTREACHED("Must override GetInternalStream");
   269   return NS_ERROR_NOT_IMPLEMENTED;
   270 }
   272 NS_IMETHODIMP
   273 nsDOMFileBase::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
   274 {
   275   NS_ENSURE_STATE(aPrincipal);
   277   nsCString url;
   278   nsresult rv = nsBlobProtocolHandler::AddDataEntry(
   279     NS_LITERAL_CSTRING(BLOBURI_SCHEME),
   280     static_cast<nsIDOMBlob*>(this), aPrincipal, url);
   281   if (NS_FAILED(rv)) {
   282     return rv;
   283   }
   285   CopyASCIItoUTF16(url, aURL);
   286   return NS_OK;
   287 }
   289 NS_IMETHODIMP_(int64_t)
   290 nsDOMFileBase::GetFileId()
   291 {
   292   int64_t id = -1;
   294   if (IsStoredFile() && IsWholeFile() && !IsSnapshot()) {
   295     if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
   296       indexedDB::IndexedDatabaseManager::FileMutex().Lock();
   297     }
   299     NS_ASSERTION(!mFileInfos.IsEmpty(),
   300                  "A stored file must have at least one file info!");
   302     nsRefPtr<indexedDB::FileInfo>& fileInfo = mFileInfos.ElementAt(0);
   303     if (fileInfo) {
   304       id =  fileInfo->Id();
   305     }
   307     if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
   308       indexedDB::IndexedDatabaseManager::FileMutex().Unlock();
   309     }
   310   }
   312   return id;
   313 }
   315 NS_IMETHODIMP_(void)
   316 nsDOMFileBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
   317 {
   318   if (indexedDB::IndexedDatabaseManager::IsClosed()) {
   319     NS_ERROR("Shouldn't be called after shutdown!");
   320     return;
   321   }
   323   nsRefPtr<indexedDB::FileInfo> fileInfo = aFileInfo;
   325   MutexAutoLock lock(indexedDB::IndexedDatabaseManager::FileMutex());
   327   NS_ASSERTION(!mFileInfos.Contains(aFileInfo),
   328                "Adding the same file info agan?!");
   330   nsRefPtr<indexedDB::FileInfo>* element = mFileInfos.AppendElement();
   331   element->swap(fileInfo);
   332 }
   334 NS_IMETHODIMP_(indexedDB::FileInfo*)
   335 nsDOMFileBase::GetFileInfo(indexedDB::FileManager* aFileManager)
   336 {
   337   if (indexedDB::IndexedDatabaseManager::IsClosed()) {
   338     NS_ERROR("Shouldn't be called after shutdown!");
   339     return nullptr;
   340   }
   342   // A slice created from a stored file must keep the file info alive.
   343   // However, we don't support sharing of slices yet, so the slice must be
   344   // copied again. That's why we have to ignore the first file info.
   345   // Snapshots are handled in a similar way (they have to be copied).
   346   uint32_t startIndex;
   347   if (IsStoredFile() && (!IsWholeFile() || IsSnapshot())) {
   348     startIndex = 1;
   349   }
   350   else {
   351     startIndex = 0;
   352   }
   354   MutexAutoLock lock(indexedDB::IndexedDatabaseManager::FileMutex());
   356   for (uint32_t i = startIndex; i < mFileInfos.Length(); i++) {
   357     nsRefPtr<indexedDB::FileInfo>& fileInfo = mFileInfos.ElementAt(i);
   358     if (fileInfo->Manager() == aFileManager) {
   359       return fileInfo;
   360     }
   361   }
   363   return nullptr;
   364 }
   366 NS_IMETHODIMP
   367 nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
   368                            uint64_t* aContentLength,
   369                            nsACString& aContentType,
   370                            nsACString& aCharset)
   371 {
   372   nsresult rv;
   374   nsCOMPtr<nsIInputStream> stream;
   375   rv = this->GetInternalStream(getter_AddRefs(stream));
   376   NS_ENSURE_SUCCESS(rv, rv);
   378   rv = this->GetSize(aContentLength);
   379   NS_ENSURE_SUCCESS(rv, rv);
   381   nsString contentType;
   382   rv = this->GetType(contentType);
   383   NS_ENSURE_SUCCESS(rv, rv);
   385   CopyUTF16toUTF8(contentType, aContentType);
   387   aCharset.Truncate();
   389   stream.forget(aBody);
   390   return NS_OK;
   391 }
   393 NS_IMETHODIMP
   394 nsDOMFileBase::GetMutable(bool* aMutable)
   395 {
   396   *aMutable = !mImmutable;
   397   return NS_OK;
   398 }
   400 NS_IMETHODIMP
   401 nsDOMFileBase::SetMutable(bool aMutable)
   402 {
   403   nsresult rv = NS_OK;
   405   NS_ENSURE_ARG(!mImmutable || !aMutable);
   407   if (!mImmutable && !aMutable) {
   408     // Force the content type and size to be cached
   409     nsString dummyString;
   410     rv = this->GetType(dummyString);
   411     NS_ENSURE_SUCCESS(rv, rv);
   413     uint64_t dummyInt;
   414     rv = this->GetSize(&dummyInt);
   415     NS_ENSURE_SUCCESS(rv, rv);
   416   }
   418   mImmutable = !aMutable;
   419   return rv;
   420 }
   422 NS_IMETHODIMP_(bool)
   423 nsDOMFileBase::IsMemoryFile(void)
   424 {
   425   return false;
   426 }
   428 ////////////////////////////////////////////////////////////////////////////
   429 // nsDOMFile implementation
   431 DOMCI_DATA(File, nsDOMFile)
   432 DOMCI_DATA(Blob, nsDOMFile)
   434 NS_INTERFACE_MAP_BEGIN(nsDOMFile)
   435   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
   436   NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
   437   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
   438   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   439   NS_INTERFACE_MAP_ENTRY(nsIMutable)
   440   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
   441   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
   442 NS_INTERFACE_MAP_END
   444 // Threadsafe when GetMutable() == false
   445 NS_IMPL_ADDREF(nsDOMFile)
   446 NS_IMPL_RELEASE(nsDOMFile)
   448 ////////////////////////////////////////////////////////////////////////////
   449 // nsDOMFileCC implementation
   451 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileCC)
   453 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsDOMFileCC)
   454 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMFileCC)
   455   // We don't have anything to traverse, but some of our subclasses do.
   456 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   458 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileCC)
   459   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
   460   NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
   461   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
   462   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   463   NS_INTERFACE_MAP_ENTRY(nsIMutable)
   464   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
   465   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
   466 NS_INTERFACE_MAP_END
   468 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileCC)
   469 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileCC)
   471 ////////////////////////////////////////////////////////////////////////////
   472 // nsDOMFileFile implementation
   474 already_AddRefed<nsIDOMBlob>
   475 nsDOMFileFile::CreateSlice(uint64_t aStart, uint64_t aLength,
   476                            const nsAString& aContentType)
   477 {
   478   nsCOMPtr<nsIDOMBlob> t = new nsDOMFileFile(this, aStart, aLength, aContentType);
   479   return t.forget();
   480 }
   482 NS_IMETHODIMP
   483 nsDOMFileFile::GetMozFullPathInternal(nsAString &aFilename)
   484 {
   485   NS_ASSERTION(mIsFile, "Should only be called on files");
   486   return mFile->GetPath(aFilename);
   487 }
   489 NS_IMETHODIMP
   490 nsDOMFileFile::GetLastModifiedDate(JSContext* cx, JS::MutableHandle<JS::Value> aLastModifiedDate)
   491 {
   492   NS_ASSERTION(mIsFile, "Should only be called on files");
   494   PRTime msecs;
   495   if (IsDateUnknown()) {
   496     nsresult rv = mFile->GetLastModifiedTime(&msecs);
   497     NS_ENSURE_SUCCESS(rv, rv);
   498     mLastModificationDate = msecs;
   499   } else {
   500     msecs = mLastModificationDate;
   501   }
   503   JSObject* date = JS_NewDateObjectMsec(cx, msecs);
   504   if (date) {
   505     aLastModifiedDate.setObject(*date);
   506   }
   507   else {
   508     date = JS_NewDateObjectMsec(cx, JS_Now() / PR_USEC_PER_MSEC);
   509     aLastModifiedDate.setObject(*date);
   510   }
   512   return NS_OK;
   513 }
   515 NS_IMETHODIMP
   516 nsDOMFileFile::GetSize(uint64_t *aFileSize)
   517 {
   518   if (IsSizeUnknown()) {
   519     NS_ASSERTION(mWholeFile,
   520                  "Should only use lazy size when using the whole file");
   521     int64_t fileSize;
   522     nsresult rv = mFile->GetFileSize(&fileSize);
   523     NS_ENSURE_SUCCESS(rv, rv);
   525     if (fileSize < 0) {
   526       return NS_ERROR_FAILURE;
   527     }
   529     mLength = fileSize;
   530   }
   532   *aFileSize = mLength;
   534   return NS_OK;
   535 }
   537 NS_IMETHODIMP
   538 nsDOMFileFile::GetType(nsAString &aType)
   539 {
   540   if (mContentType.IsVoid()) {
   541     NS_ASSERTION(mWholeFile,
   542                  "Should only use lazy ContentType when using the whole file");
   543     nsresult rv;
   544     nsCOMPtr<nsIMIMEService> mimeService =
   545       do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
   546     NS_ENSURE_SUCCESS(rv, rv);
   548     nsAutoCString mimeType;
   549     rv = mimeService->GetTypeFromFile(mFile, mimeType);
   550     if (NS_FAILED(rv)) {
   551       mimeType.Truncate();
   552     }
   554     AppendUTF8toUTF16(mimeType, mContentType);
   555     mContentType.SetIsVoid(false);
   556   }
   558   aType = mContentType;
   560   return NS_OK;
   561 }
   563 NS_IMETHODIMP
   564 nsDOMFileFile::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
   565 {
   566   NS_ASSERTION(mIsFile, "Should only be called on files");
   567   if (IsDateUnknown()) {
   568     PRTime msecs;
   569     nsresult rv = mFile->GetLastModifiedTime(&msecs);
   570     NS_ENSURE_SUCCESS(rv, rv);
   571     mLastModificationDate = msecs;
   572   }
   573   *aLastModifiedDate = mLastModificationDate;
   574   return NS_OK;
   575 }
   577 const uint32_t sFileStreamFlags =
   578   nsIFileInputStream::CLOSE_ON_EOF |
   579   nsIFileInputStream::REOPEN_ON_REWIND |
   580   nsIFileInputStream::DEFER_OPEN;
   582 NS_IMETHODIMP
   583 nsDOMFileFile::GetInternalStream(nsIInputStream **aStream)
   584 {
   585   return mWholeFile ?
   586     NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags) :
   587     NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
   588                                       -1, -1, sFileStreamFlags);
   589 }
   591 void
   592 nsDOMFileFile::SetPath(const nsAString& aPath)
   593 {
   594   MOZ_ASSERT(aPath.IsEmpty() ||
   595              aPath[aPath.Length() - 1] == char16_t('/'),
   596              "Path must end with a path separator");
   597   mPath = aPath;
   598 }
   600 ////////////////////////////////////////////////////////////////////////////
   601 // nsDOMMemoryFile implementation
   603 already_AddRefed<nsIDOMBlob>
   604 nsDOMMemoryFile::CreateSlice(uint64_t aStart, uint64_t aLength,
   605                              const nsAString& aContentType)
   606 {
   607   nsCOMPtr<nsIDOMBlob> t =
   608     new nsDOMMemoryFile(this, aStart, aLength, aContentType);
   609   return t.forget();
   610 }
   612 NS_IMETHODIMP
   613 nsDOMMemoryFile::GetInternalStream(nsIInputStream **aStream)
   614 {
   615   if (mLength > INT32_MAX)
   616     return NS_ERROR_FAILURE;
   618   return DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
   619 }
   621 NS_IMETHODIMP_(bool)
   622 nsDOMMemoryFile::IsMemoryFile(void)
   623 {
   624   return true;
   625 }
   627 /* static */ StaticMutex
   628 nsDOMMemoryFile::DataOwner::sDataOwnerMutex;
   630 /* static */ StaticAutoPtr<LinkedList<nsDOMMemoryFile::DataOwner> >
   631 nsDOMMemoryFile::DataOwner::sDataOwners;
   633 /* static */ bool
   634 nsDOMMemoryFile::DataOwner::sMemoryReporterRegistered;
   636 MOZ_DEFINE_MALLOC_SIZE_OF(DOMMemoryFileDataOwnerMallocSizeOf)
   638 class nsDOMMemoryFileDataOwnerMemoryReporter MOZ_FINAL
   639   : public nsIMemoryReporter
   640 {
   641 public:
   642   NS_DECL_THREADSAFE_ISUPPORTS
   644   NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCallback,
   645                             nsISupports *aClosure)
   646   {
   647     typedef nsDOMMemoryFile::DataOwner DataOwner;
   649     StaticMutexAutoLock lock(DataOwner::sDataOwnerMutex);
   651     if (!DataOwner::sDataOwners) {
   652       return NS_OK;
   653     }
   655     const size_t LARGE_OBJECT_MIN_SIZE = 8 * 1024;
   656     size_t smallObjectsTotal = 0;
   658     for (DataOwner *owner = DataOwner::sDataOwners->getFirst();
   659          owner; owner = owner->getNext()) {
   661       size_t size = DOMMemoryFileDataOwnerMallocSizeOf(owner->mData);
   663       if (size < LARGE_OBJECT_MIN_SIZE) {
   664         smallObjectsTotal += size;
   665       }
   666       else {
   667         SHA1Sum sha1;
   668         sha1.update(owner->mData, owner->mLength);
   669         uint8_t digest[SHA1Sum::HashSize]; // SHA1 digests are 20 bytes long.
   670         sha1.finish(digest);
   672         nsAutoCString digestString;
   673         for (size_t i = 0; i < sizeof(digest); i++) {
   674           digestString.AppendPrintf("%02x", digest[i]);
   675         }
   677         nsresult rv = aCallback->Callback(
   678           /* process */ NS_LITERAL_CSTRING(""),
   679           nsPrintfCString(
   680             "explicit/dom/memory-file-data/large/file(length=%llu, sha1=%s)",
   681             owner->mLength, digestString.get()),
   682           KIND_HEAP, UNITS_BYTES, size,
   683           nsPrintfCString(
   684             "Memory used to back a memory file of length %llu bytes.  The file "
   685             "has a sha1 of %s.\n\n"
   686             "Note that the allocator may round up a memory file's length -- "
   687             "that is, an N-byte memory file may take up more than N bytes of "
   688             "memory.",
   689             owner->mLength, digestString.get()),
   690           aClosure);
   691         NS_ENSURE_SUCCESS(rv, rv);
   692       }
   693     }
   695     if (smallObjectsTotal > 0) {
   696       nsresult rv = aCallback->Callback(
   697         /* process */ NS_LITERAL_CSTRING(""),
   698         NS_LITERAL_CSTRING("explicit/dom/memory-file-data/small"),
   699         KIND_HEAP, UNITS_BYTES, smallObjectsTotal,
   700         nsPrintfCString(
   701           "Memory used to back small memory files (less than %d bytes each).\n\n"
   702           "Note that the allocator may round up a memory file's length -- "
   703           "that is, an N-byte memory file may take up more than N bytes of "
   704           "memory."),
   705         aClosure);
   706       NS_ENSURE_SUCCESS(rv, rv);
   707     }
   709     return NS_OK;
   710   }
   711 };
   713 NS_IMPL_ISUPPORTS(nsDOMMemoryFileDataOwnerMemoryReporter, nsIMemoryReporter)
   715 /* static */ void
   716 nsDOMMemoryFile::DataOwner::EnsureMemoryReporterRegistered()
   717 {
   718   sDataOwnerMutex.AssertCurrentThreadOwns();
   719   if (sMemoryReporterRegistered) {
   720     return;
   721   }
   723   RegisterStrongMemoryReporter(new nsDOMMemoryFileDataOwnerMemoryReporter());
   725   sMemoryReporterRegistered = true;
   726 }
   728 ////////////////////////////////////////////////////////////////////////////
   729 // nsDOMFileList implementation
   731 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsDOMFileList)
   733 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileList)
   734   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   735   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileList)
   736   NS_INTERFACE_MAP_ENTRY(nsIDOMFileList)
   737 NS_INTERFACE_MAP_END
   739 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileList)
   740 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileList)
   742 JSObject*
   743 nsDOMFileList::WrapObject(JSContext *cx)
   744 {
   745   return FileListBinding::Wrap(cx, this);
   746 }
   748 NS_IMETHODIMP
   749 nsDOMFileList::GetLength(uint32_t* aLength)
   750 {
   751   *aLength = Length();
   753   return NS_OK;
   754 }
   756 NS_IMETHODIMP
   757 nsDOMFileList::Item(uint32_t aIndex, nsIDOMFile **aFile)
   758 {
   759   NS_IF_ADDREF(*aFile = Item(aIndex));
   761   return NS_OK;
   762 }
   764 ////////////////////////////////////////////////////////////////////////////
   765 // nsDOMFileInternalUrlHolder implementation
   767 nsDOMFileInternalUrlHolder::nsDOMFileInternalUrlHolder(nsIDOMBlob* aFile,
   768                                                        nsIPrincipal* aPrincipal
   769                                                        MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) {
   770   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   771   aFile->GetInternalUrl(aPrincipal, mUrl);
   772 }
   774 nsDOMFileInternalUrlHolder::~nsDOMFileInternalUrlHolder() {
   775   if (!mUrl.IsEmpty()) {
   776     nsAutoCString narrowUrl;
   777     CopyUTF16toUTF8(mUrl, narrowUrl);
   778     nsBlobProtocolHandler::RemoveDataEntry(narrowUrl);
   779   }
   780 }
   782 ////////////////////////////////////////////////////////////////////////////
   783 // nsDOMTemporaryFileBlob implementation
   784 already_AddRefed<nsIDOMBlob>
   785 nsDOMTemporaryFileBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
   786                                     const nsAString& aContentType)
   787 {
   788   if (aStart + aLength > mLength)
   789     return nullptr;
   791   nsCOMPtr<nsIDOMBlob> t =
   792     new nsDOMTemporaryFileBlob(this, aStart + mStartPos, aLength, aContentType);
   793   return t.forget();
   794 }
   796 NS_IMETHODIMP
   797 nsDOMTemporaryFileBlob::GetInternalStream(nsIInputStream **aStream)
   798 {
   799   nsCOMPtr<nsIInputStream> stream =
   800     new nsTemporaryFileInputStream(mFileDescOwner, mStartPos, mStartPos + mLength);
   801   stream.forget(aStream);
   802   return NS_OK;
   803 }

mercurial