tor-browser

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

CloneableWithRangeMediaResource.cpp (6065B)


      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 "CloneableWithRangeMediaResource.h"
      7 
      8 #include "mozilla/AbstractThread.h"
      9 #include "mozilla/Monitor.h"
     10 #include "nsContentUtils.h"
     11 #include "nsIAsyncInputStream.h"
     12 #include "nsITimedChannel.h"
     13 #include "nsNetCID.h"
     14 #include "nsServiceManagerUtils.h"
     15 
     16 namespace mozilla {
     17 
     18 namespace {
     19 
     20 class InputStreamReader final : public nsIInputStreamCallback {
     21 public:
     22  NS_DECL_THREADSAFE_ISUPPORTS
     23 
     24  static already_AddRefed<InputStreamReader> Create(
     25      nsICloneableInputStreamWithRange* aStream, int64_t aStart,
     26      uint32_t aLength) {
     27    MOZ_ASSERT(aStream);
     28 
     29    nsCOMPtr<nsIInputStream> stream;
     30    nsresult rv =
     31        aStream->CloneWithRange(aStart, aLength, getter_AddRefs(stream));
     32    if (NS_WARN_IF(NS_FAILED(rv))) {
     33      return nullptr;
     34    }
     35 
     36    RefPtr<InputStreamReader> reader = new InputStreamReader(stream);
     37    return reader.forget();
     38  }
     39 
     40  nsresult Read(char* aBuffer, uint32_t aSize, uint32_t* aRead) {
     41    uint32_t done = 0;
     42    do {
     43      uint32_t read;
     44      nsresult rv = SyncRead(aBuffer + done, aSize - done, &read);
     45      if (NS_SUCCEEDED(rv) && read == 0) {
     46        break;
     47      }
     48      if (NS_WARN_IF(NS_FAILED(rv))) {
     49        return rv;
     50      }
     51      done += read;
     52    } while (done != aSize);
     53 
     54    *aRead = done;
     55    return NS_OK;
     56  }
     57 
     58  NS_IMETHOD
     59  OnInputStreamReady(nsIAsyncInputStream* aStream) override {
     60    // Let's continue with SyncRead().
     61    MonitorAutoLock lock(mMonitor);
     62    lock.Notify();
     63    return NS_OK;
     64  }
     65 
     66 private:
     67  explicit InputStreamReader(nsIInputStream* aStream)
     68      : mStream(aStream), mMonitor("InputStreamReader::mMonitor") {
     69    MOZ_ASSERT(aStream);
     70  }
     71 
     72  ~InputStreamReader() = default;
     73 
     74  nsresult SyncRead(char* aBuffer, uint32_t aSize, uint32_t* aRead) {
     75    while (1) {
     76      nsresult rv = mStream->Read(aBuffer, aSize, aRead);
     77      // All good.
     78      if (rv == NS_BASE_STREAM_CLOSED || NS_SUCCEEDED(rv)) {
     79        return NS_OK;
     80      }
     81 
     82      // An error.
     83      if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
     84        return rv;
     85      }
     86 
     87      // We need to proceed async.
     88      if (!mAsyncStream) {
     89        mAsyncStream = do_QueryInterface(mStream);
     90      }
     91 
     92      if (!mAsyncStream) {
     93        return NS_ERROR_FAILURE;
     94      }
     95 
     96      nsCOMPtr<nsIEventTarget> target =
     97          do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
     98      MOZ_ASSERT(target);
     99 
    100      {
    101        // We wait for ::OnInputStreamReady() to be called.
    102        MonitorAutoLock lock(mMonitor);
    103 
    104        rv = mAsyncStream->AsyncWait(this, 0, aSize, target);
    105        if (NS_WARN_IF(NS_FAILED(rv))) {
    106          return rv;
    107        }
    108 
    109        lock.Wait();
    110      }
    111    }
    112  }
    113 
    114  nsCOMPtr<nsIInputStream> mStream;
    115  nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
    116  Monitor mMonitor MOZ_UNANNOTATED;
    117 };
    118 
    119 NS_IMPL_ADDREF(InputStreamReader);
    120 NS_IMPL_RELEASE(InputStreamReader);
    121 
    122 NS_INTERFACE_MAP_BEGIN(InputStreamReader)
    123  NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
    124  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStreamCallback)
    125 NS_INTERFACE_MAP_END
    126 
    127 }  // namespace
    128 
    129 void CloneableWithRangeMediaResource::MaybeInitialize() {
    130  if (!mInitialized) {
    131    mInitialized = true;
    132    mCallback->AbstractMainThread()->Dispatch(NewRunnableMethod<nsresult>(
    133        "MediaResourceCallback::NotifyDataEnded", mCallback.get(),
    134        &MediaResourceCallback::NotifyDataEnded, NS_OK));
    135  }
    136 }
    137 
    138 nsresult CloneableWithRangeMediaResource::GetCachedRanges(
    139    MediaByteRangeSet& aRanges) {
    140  MaybeInitialize();
    141  aRanges += MediaByteRange(0, (int64_t)mSize);
    142  return NS_OK;
    143 }
    144 
    145 nsresult CloneableWithRangeMediaResource::Open(
    146    nsIStreamListener** aStreamListener) {
    147  MOZ_ASSERT(NS_IsMainThread());
    148  MOZ_ASSERT(aStreamListener);
    149 
    150  *aStreamListener = nullptr;
    151  return NS_OK;
    152 }
    153 
    154 RefPtr<GenericPromise> CloneableWithRangeMediaResource::Close() {
    155  return GenericPromise::CreateAndResolve(true, __func__);
    156 }
    157 
    158 already_AddRefed<nsIPrincipal>
    159 CloneableWithRangeMediaResource::GetCurrentPrincipal() {
    160  MOZ_ASSERT(NS_IsMainThread());
    161 
    162  nsCOMPtr<nsIPrincipal> principal;
    163  nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
    164  if (!secMan || !mChannel) {
    165    return nullptr;
    166  }
    167 
    168  secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
    169  return principal.forget();
    170 }
    171 
    172 bool CloneableWithRangeMediaResource::HadCrossOriginRedirects() {
    173  MOZ_ASSERT(NS_IsMainThread());
    174 
    175  nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(mChannel);
    176  if (!timedChannel) {
    177    return false;
    178  }
    179 
    180  bool allRedirectsSameOrigin = false;
    181  return NS_SUCCEEDED(timedChannel->GetAllRedirectsSameOrigin(
    182             &allRedirectsSameOrigin)) &&
    183         !allRedirectsSameOrigin;
    184 }
    185 
    186 nsresult CloneableWithRangeMediaResource::ReadFromCache(char* aBuffer,
    187                                                        int64_t aOffset,
    188                                                        uint32_t aCount) {
    189  MaybeInitialize();
    190  if (!aCount) {
    191    return NS_OK;
    192  }
    193 
    194  RefPtr<InputStreamReader> reader =
    195      InputStreamReader::Create(mStream, aOffset, aCount);
    196  if (!reader) {
    197    return NS_ERROR_FAILURE;
    198  }
    199 
    200  uint32_t bytes = 0;
    201  nsresult rv = reader->Read(aBuffer, aCount, &bytes);
    202  if (NS_WARN_IF(NS_FAILED(rv))) {
    203    return rv;
    204  }
    205 
    206  return bytes == aCount ? NS_OK : NS_ERROR_FAILURE;
    207 }
    208 
    209 nsresult CloneableWithRangeMediaResource::ReadAt(int64_t aOffset, char* aBuffer,
    210                                                 uint32_t aCount,
    211                                                 uint32_t* aBytes) {
    212  MOZ_ASSERT(!NS_IsMainThread());
    213 
    214  RefPtr<InputStreamReader> reader =
    215      InputStreamReader::Create(mStream, aOffset, aCount);
    216  if (!reader) {
    217    return NS_ERROR_FAILURE;
    218  }
    219 
    220  nsresult rv = reader->Read(aBuffer, aCount, aBytes);
    221  if (NS_WARN_IF(NS_FAILED(rv))) {
    222    return rv;
    223  }
    224 
    225  return NS_OK;
    226 }
    227 
    228 }  // namespace mozilla