tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FileMediaResource.cpp (6887B)


      1 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "FileMediaResource.h"
      7 
      8 #include "mozilla/AbstractThread.h"
      9 #include "mozilla/dom/BlobImpl.h"
     10 #include "mozilla/dom/BlobURLProtocolHandler.h"
     11 #include "nsContentUtils.h"
     12 #include "nsIFile.h"
     13 #include "nsIFileChannel.h"
     14 #include "nsIFileStreams.h"
     15 #include "nsITimedChannel.h"
     16 #include "nsNetUtil.h"
     17 
     18 namespace mozilla {
     19 
     20 void FileMediaResource::EnsureSizeInitialized() {
     21  mLock.AssertCurrentThreadOwns();
     22  NS_ASSERTION(mInput, "Must have file input stream");
     23  if (mSizeInitialized && mNotifyDataEndedProcessed) {
     24    return;
     25  }
     26 
     27  if (!mSizeInitialized) {
     28    // Get the file size and inform the decoder.
     29    uint64_t size;
     30    nsresult res = mInput->Available(&size);
     31    if (NS_SUCCEEDED(res) && size <= INT64_MAX) {
     32      mSize = (int64_t)size;
     33    }
     34  }
     35  mSizeInitialized = true;
     36  if (!mNotifyDataEndedProcessed && mSize >= 0) {
     37    mCallback->AbstractMainThread()->Dispatch(NewRunnableMethod<nsresult>(
     38        "MediaResourceCallback::NotifyDataEnded", mCallback.get(),
     39        &MediaResourceCallback::NotifyDataEnded, NS_OK));
     40  }
     41  mNotifyDataEndedProcessed = true;
     42 }
     43 
     44 nsresult FileMediaResource::GetCachedRanges(MediaByteRangeSet& aRanges) {
     45  MutexAutoLock lock(mLock);
     46 
     47  EnsureSizeInitialized();
     48  if (mSize == -1) {
     49    return NS_ERROR_FAILURE;
     50  }
     51  aRanges += MediaByteRange(0, mSize);
     52  return NS_OK;
     53 }
     54 
     55 nsresult FileMediaResource::Open(nsIStreamListener** aStreamListener) {
     56  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
     57  MOZ_ASSERT(aStreamListener);
     58 
     59  *aStreamListener = nullptr;
     60  nsresult rv = NS_OK;
     61 
     62  MutexAutoLock lock(mLock);
     63  // The channel is already open. We need a synchronous stream that
     64  // implements nsISeekableStream, so we have to find the underlying
     65  // file and reopen it
     66  nsCOMPtr<nsIFileChannel> fc(do_QueryInterface(mChannel));
     67  if (fc) {
     68    nsCOMPtr<nsIFile> file;
     69    rv = fc->GetFile(getter_AddRefs(file));
     70    NS_ENSURE_SUCCESS(rv, rv);
     71 
     72    rv = NS_NewLocalFileInputStream(getter_AddRefs(mInput), file, -1, -1,
     73                                    nsIFileInputStream::SHARE_DELETE);
     74    NS_ENSURE_SUCCESS(rv, rv);
     75  } else if (dom::IsBlobURI(mURI)) {
     76    RefPtr<dom::BlobImpl> blobImpl;
     77    rv = NS_GetBlobForBlobURI(mURI, getter_AddRefs(blobImpl));
     78    NS_ENSURE_SUCCESS(rv, rv);
     79    MOZ_ASSERT(blobImpl);
     80 
     81    ErrorResult err;
     82    blobImpl->CreateInputStream(getter_AddRefs(mInput), err);
     83    if (NS_WARN_IF(err.Failed())) {
     84      return err.StealNSResult();
     85    }
     86  }
     87 
     88  mSeekable = do_QueryInterface(mInput);
     89  if (!mSeekable) {
     90    // XXX The file may just be a .url or similar
     91    // shortcut that points to a Web site. We need to fix this by
     92    // doing an async open and waiting until we locate the real resource,
     93    // then using that (if it's still a file!).
     94    return NS_ERROR_FAILURE;
     95  }
     96 
     97  return NS_OK;
     98 }
     99 
    100 RefPtr<GenericPromise> FileMediaResource::Close() {
    101  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
    102 
    103  // Since mChennel is only accessed by main thread, there is no necessary to
    104  // take the lock.
    105  if (mChannel) {
    106    mChannel->Cancel(NS_ERROR_PARSED_DATA_CACHED);
    107    mChannel = nullptr;
    108  }
    109 
    110  return GenericPromise::CreateAndResolve(true, __func__);
    111 }
    112 
    113 already_AddRefed<nsIPrincipal> FileMediaResource::GetCurrentPrincipal() {
    114  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
    115 
    116  nsCOMPtr<nsIPrincipal> principal;
    117  nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
    118  if (!secMan || !mChannel) return nullptr;
    119  secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
    120  return principal.forget();
    121 }
    122 
    123 bool FileMediaResource::HadCrossOriginRedirects() {
    124  MOZ_ASSERT(NS_IsMainThread());
    125 
    126  nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(mChannel);
    127  if (!timedChannel) {
    128    return false;
    129  }
    130 
    131  bool allRedirectsSameOrigin = false;
    132  return NS_SUCCEEDED(timedChannel->GetAllRedirectsSameOrigin(
    133             &allRedirectsSameOrigin)) &&
    134         !allRedirectsSameOrigin;
    135 }
    136 
    137 nsresult FileMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset,
    138                                          uint32_t aCount) {
    139  MutexAutoLock lock(mLock);
    140 
    141  EnsureSizeInitialized();
    142  if (!aCount) {
    143    return NS_OK;
    144  }
    145  int64_t offset = 0;
    146  nsresult res = mSeekable->Tell(&offset);
    147  NS_ENSURE_SUCCESS(res, res);
    148  res = mSeekable->Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
    149  NS_ENSURE_SUCCESS(res, res);
    150  uint32_t bytesRead = 0;
    151  do {
    152    uint32_t x = 0;
    153    uint32_t bytesToRead = aCount - bytesRead;
    154    res = mInput->Read(aBuffer, bytesToRead, &x);
    155    bytesRead += x;
    156    if (!x) {
    157      res = NS_ERROR_FAILURE;
    158    }
    159  } while (bytesRead != aCount && res == NS_OK);
    160 
    161  // Reset read head to original position so we don't disturb any other
    162  // reading thread.
    163  nsresult seekres = mSeekable->Seek(nsISeekableStream::NS_SEEK_SET, offset);
    164 
    165  // If a read failed in the loop above, we want to return its failure code.
    166  NS_ENSURE_SUCCESS(res, res);
    167 
    168  // Else we succeed if the reset-seek succeeds.
    169  return seekres;
    170 }
    171 
    172 nsresult FileMediaResource::UnsafeRead(char* aBuffer, uint32_t aCount,
    173                                       uint32_t* aBytes) {
    174  EnsureSizeInitialized();
    175  return mInput->Read(aBuffer, aCount, aBytes);
    176 }
    177 
    178 nsresult FileMediaResource::ReadAt(int64_t aOffset, char* aBuffer,
    179                                   uint32_t aCount, uint32_t* aBytes) {
    180  NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
    181 
    182  nsresult rv;
    183  {
    184    MutexAutoLock lock(mLock);
    185    rv = UnsafeSeek(nsISeekableStream::NS_SEEK_SET, aOffset);
    186    if (NS_FAILED(rv)) return rv;
    187    rv = UnsafeRead(aBuffer, aCount, aBytes);
    188  }
    189  return rv;
    190 }
    191 
    192 already_AddRefed<MediaByteBuffer> FileMediaResource::UnsafeMediaReadAt(
    193    int64_t aOffset, uint32_t aCount) {
    194  RefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
    195  bool ok = bytes->SetLength(aCount, fallible);
    196  NS_ENSURE_TRUE(ok, nullptr);
    197  nsresult rv = UnsafeSeek(nsISeekableStream::NS_SEEK_SET, aOffset);
    198  NS_ENSURE_SUCCESS(rv, nullptr);
    199  char* curr = reinterpret_cast<char*>(bytes->Elements());
    200  const char* start = curr;
    201  while (aCount > 0) {
    202    uint32_t bytesRead;
    203    rv = UnsafeRead(curr, aCount, &bytesRead);
    204    NS_ENSURE_SUCCESS(rv, nullptr);
    205    if (!bytesRead) {
    206      break;
    207    }
    208    aCount -= bytesRead;
    209    curr += bytesRead;
    210  }
    211  bytes->SetLength(curr - start);
    212  return bytes.forget();
    213 }
    214 
    215 nsresult FileMediaResource::UnsafeSeek(int32_t aWhence, int64_t aOffset) {
    216  NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
    217 
    218  if (!mSeekable) return NS_ERROR_FAILURE;
    219  EnsureSizeInitialized();
    220  return mSeekable->Seek(aWhence, aOffset);
    221 }
    222 
    223 }  // namespace mozilla