tor-browser

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

BaseMediaResource.cpp (5521B)


      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 "BaseMediaResource.h"
      8 
      9 #include "ChannelMediaResource.h"
     10 #include "CloneableWithRangeMediaResource.h"
     11 #include "FileMediaResource.h"
     12 #include "MediaContainerType.h"
     13 #include "mozilla/InputStreamLengthHelper.h"
     14 #include "mozilla/dom/BlobImpl.h"
     15 #include "mozilla/dom/BlobURLProtocolHandler.h"
     16 #include "mozilla/dom/HTMLMediaElement.h"
     17 #include "nsDebug.h"
     18 #include "nsError.h"
     19 #include "nsICloneableInputStream.h"
     20 #include "nsIFile.h"
     21 #include "nsIFileChannel.h"
     22 #include "nsIInputStream.h"
     23 #include "nsNetUtil.h"
     24 
     25 namespace mozilla {
     26 
     27 already_AddRefed<BaseMediaResource> BaseMediaResource::Create(
     28    MediaResourceCallback* aCallback, nsIChannel* aChannel,
     29    bool aIsPrivateBrowsing) {
     30  NS_ASSERTION(NS_IsMainThread(),
     31               "MediaResource::Open called on non-main thread");
     32 
     33  // If the channel was redirected, we want the post-redirect URI;
     34  // but if the URI scheme was expanded, say from chrome: to jar:file:,
     35  // we want the original URI.
     36  nsCOMPtr<nsIURI> uri;
     37  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
     38  NS_ENSURE_SUCCESS(rv, nullptr);
     39 
     40  nsAutoCString contentTypeString;
     41  aChannel->GetContentType(contentTypeString);
     42  Maybe<MediaContainerType> containerType =
     43      MakeMediaContainerType(contentTypeString);
     44  if (!containerType) {
     45    return nullptr;
     46  }
     47 
     48  // Let's try to create a FileMediaResource in case the channel is a nsIFile
     49  nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aChannel);
     50  if (fc) {
     51    RefPtr<BaseMediaResource> resource =
     52        new FileMediaResource(aCallback, aChannel, uri);
     53    return resource.forget();
     54  }
     55 
     56  int64_t streamLength = -1;
     57 
     58  RefPtr<mozilla::dom::BlobImpl> blobImpl;
     59  if (dom::IsBlobURI(uri) &&
     60      NS_SUCCEEDED(NS_GetBlobForBlobURI(uri, getter_AddRefs(blobImpl))) &&
     61      blobImpl) {
     62    IgnoredErrorResult rv;
     63 
     64    nsCOMPtr<nsIInputStream> stream;
     65    blobImpl->CreateInputStream(getter_AddRefs(stream), rv);
     66    if (NS_WARN_IF(rv.Failed())) {
     67      return nullptr;
     68    }
     69 
     70    // If this stream knows its own size synchronously, we can still use
     71    // FileMediaResource. If the size is known, it means that the reading
     72    // doesn't require any async operation.  This is required because
     73    // FileMediaResource doesn't work with nsIAsyncInputStreams.
     74    int64_t length;
     75    if (InputStreamLengthHelper::GetSyncLength(stream, &length) &&
     76        length >= 0) {
     77      RefPtr<BaseMediaResource> resource =
     78          new FileMediaResource(aCallback, aChannel, uri, length);
     79      return resource.forget();
     80    }
     81 
     82    // Also if the stream doesn't know its own size synchronously, we can still
     83    // read the length from the blob.
     84    uint64_t size = blobImpl->GetSize(rv);
     85    if (NS_WARN_IF(rv.Failed())) {
     86      return nullptr;
     87    }
     88 
     89    // Maybe this blob URL can be cloned with a range.
     90    nsCOMPtr<nsICloneableInputStreamWithRange> cloneableWithRange =
     91        do_QueryInterface(stream);
     92    if (cloneableWithRange) {
     93      RefPtr<BaseMediaResource> resource = new CloneableWithRangeMediaResource(
     94          aCallback, aChannel, uri, stream, size);
     95      return resource.forget();
     96    }
     97 
     98    // We know the size of the stream for blobURLs, let's use it.
     99    streamLength = size;
    100  }
    101 
    102  RefPtr<BaseMediaResource> resource = new ChannelMediaResource(
    103      aCallback, aChannel, uri, streamLength, aIsPrivateBrowsing);
    104  return resource.forget();
    105 }
    106 
    107 void BaseMediaResource::SetLoadInBackground(bool aLoadInBackground) {
    108  if (aLoadInBackground == mLoadInBackground) {
    109    return;
    110  }
    111  mLoadInBackground = aLoadInBackground;
    112  if (!mChannel) {
    113    // No channel, resource is probably already loaded.
    114    return;
    115  }
    116 
    117  MediaDecoderOwner* owner = mCallback->GetMediaOwner();
    118  if (!owner) {
    119    NS_WARNING("Null owner in MediaResource::SetLoadInBackground()");
    120    return;
    121  }
    122  RefPtr<dom::HTMLMediaElement> element = owner->GetMediaElement();
    123  if (!element) {
    124    NS_WARNING("Null element in MediaResource::SetLoadInBackground()");
    125    return;
    126  }
    127 
    128  bool isPending = false;
    129  if (NS_SUCCEEDED(mChannel->IsPending(&isPending)) && isPending) {
    130    nsLoadFlags loadFlags;
    131    DebugOnly<nsresult> rv = mChannel->GetLoadFlags(&loadFlags);
    132    NS_ASSERTION(NS_SUCCEEDED(rv), "GetLoadFlags() failed!");
    133 
    134    if (aLoadInBackground) {
    135      loadFlags |= nsIRequest::LOAD_BACKGROUND;
    136    } else {
    137      loadFlags &= ~nsIRequest::LOAD_BACKGROUND;
    138    }
    139    (void)NS_WARN_IF(NS_FAILED(ModifyLoadFlags(loadFlags)));
    140  }
    141 }
    142 
    143 nsresult BaseMediaResource::ModifyLoadFlags(nsLoadFlags aFlags) {
    144  nsCOMPtr<nsILoadGroup> loadGroup;
    145  nsresult rv = mChannel->GetLoadGroup(getter_AddRefs(loadGroup));
    146  MOZ_ASSERT(NS_SUCCEEDED(rv), "GetLoadGroup() failed!");
    147 
    148  bool inLoadGroup = false;
    149  if (loadGroup) {
    150    nsresult status;
    151    mChannel->GetStatus(&status);
    152 
    153    rv = loadGroup->RemoveRequest(mChannel, nullptr, status);
    154    if (NS_WARN_IF(NS_FAILED(rv))) {
    155      return rv;
    156    }
    157    inLoadGroup = true;
    158  }
    159 
    160  rv = mChannel->SetLoadFlags(aFlags);
    161  MOZ_ASSERT(NS_SUCCEEDED(rv), "SetLoadFlags() failed!");
    162 
    163  if (inLoadGroup) {
    164    rv = loadGroup->AddRequest(mChannel, nullptr);
    165    MOZ_ASSERT(NS_SUCCEEDED(rv), "AddRequest() failed!");
    166  }
    167 
    168  return NS_OK;
    169 }
    170 
    171 }  // namespace mozilla