diff options
Diffstat (limited to 'dom/media/CloneableWithRangeMediaResource.cpp')
-rw-r--r-- | dom/media/CloneableWithRangeMediaResource.cpp | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/dom/media/CloneableWithRangeMediaResource.cpp b/dom/media/CloneableWithRangeMediaResource.cpp new file mode 100644 index 0000000000..4faac6125f --- /dev/null +++ b/dom/media/CloneableWithRangeMediaResource.cpp @@ -0,0 +1,228 @@ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CloneableWithRangeMediaResource.h" + +#include "mozilla/AbstractThread.h" +#include "mozilla/Monitor.h" +#include "nsContentUtils.h" +#include "nsIAsyncInputStream.h" +#include "nsITimedChannel.h" +#include "nsNetCID.h" +#include "nsServiceManagerUtils.h" + +namespace mozilla { + +namespace { + +class InputStreamReader final : public nsIInputStreamCallback { + public: + NS_DECL_THREADSAFE_ISUPPORTS + + static already_AddRefed<InputStreamReader> Create( + nsICloneableInputStreamWithRange* aStream, int64_t aStart, + uint32_t aLength) { + MOZ_ASSERT(aStream); + + nsCOMPtr<nsIInputStream> stream; + nsresult rv = + aStream->CloneWithRange(aStart, aLength, getter_AddRefs(stream)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + + RefPtr<InputStreamReader> reader = new InputStreamReader(stream); + return reader.forget(); + } + + nsresult Read(char* aBuffer, uint32_t aSize, uint32_t* aRead) { + uint32_t done = 0; + do { + uint32_t read; + nsresult rv = SyncRead(aBuffer + done, aSize - done, &read); + if (NS_SUCCEEDED(rv) && read == 0) { + break; + } + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + done += read; + } while (done != aSize); + + *aRead = done; + return NS_OK; + } + + NS_IMETHOD + OnInputStreamReady(nsIAsyncInputStream* aStream) override { + // Let's continue with SyncRead(). + MonitorAutoLock lock(mMonitor); + lock.Notify(); + return NS_OK; + } + + private: + explicit InputStreamReader(nsIInputStream* aStream) + : mStream(aStream), mMonitor("InputStreamReader::mMonitor") { + MOZ_ASSERT(aStream); + } + + ~InputStreamReader() = default; + + nsresult SyncRead(char* aBuffer, uint32_t aSize, uint32_t* aRead) { + while (1) { + nsresult rv = mStream->Read(aBuffer, aSize, aRead); + // All good. + if (rv == NS_BASE_STREAM_CLOSED || NS_SUCCEEDED(rv)) { + return NS_OK; + } + + // An error. + if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) { + return rv; + } + + // We need to proceed async. + if (!mAsyncStream) { + mAsyncStream = do_QueryInterface(mStream); + } + + if (!mAsyncStream) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr<nsIEventTarget> target = + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); + MOZ_ASSERT(target); + + { + // We wait for ::OnInputStreamReady() to be called. + MonitorAutoLock lock(mMonitor); + + rv = mAsyncStream->AsyncWait(this, 0, aSize, target); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + lock.Wait(); + } + } + } + + nsCOMPtr<nsIInputStream> mStream; + nsCOMPtr<nsIAsyncInputStream> mAsyncStream; + Monitor mMonitor MOZ_UNANNOTATED; +}; + +NS_IMPL_ADDREF(InputStreamReader); +NS_IMPL_RELEASE(InputStreamReader); + +NS_INTERFACE_MAP_BEGIN(InputStreamReader) + NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStreamCallback) +NS_INTERFACE_MAP_END + +} // namespace + +void CloneableWithRangeMediaResource::MaybeInitialize() { + if (!mInitialized) { + mInitialized = true; + mCallback->AbstractMainThread()->Dispatch(NewRunnableMethod<nsresult>( + "MediaResourceCallback::NotifyDataEnded", mCallback.get(), + &MediaResourceCallback::NotifyDataEnded, NS_OK)); + } +} + +nsresult CloneableWithRangeMediaResource::GetCachedRanges( + MediaByteRangeSet& aRanges) { + MaybeInitialize(); + aRanges += MediaByteRange(0, (int64_t)mSize); + return NS_OK; +} + +nsresult CloneableWithRangeMediaResource::Open( + nsIStreamListener** aStreamListener) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aStreamListener); + + *aStreamListener = nullptr; + return NS_OK; +} + +RefPtr<GenericPromise> CloneableWithRangeMediaResource::Close() { + return GenericPromise::CreateAndResolve(true, __func__); +} + +already_AddRefed<nsIPrincipal> +CloneableWithRangeMediaResource::GetCurrentPrincipal() { + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr<nsIPrincipal> principal; + nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager(); + if (!secMan || !mChannel) { + return nullptr; + } + + secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal)); + return principal.forget(); +} + +bool CloneableWithRangeMediaResource::HadCrossOriginRedirects() { + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(mChannel); + if (!timedChannel) { + return false; + } + + bool allRedirectsSameOrigin = false; + return NS_SUCCEEDED(timedChannel->GetAllRedirectsSameOrigin( + &allRedirectsSameOrigin)) && + !allRedirectsSameOrigin; +} + +nsresult CloneableWithRangeMediaResource::ReadFromCache(char* aBuffer, + int64_t aOffset, + uint32_t aCount) { + MaybeInitialize(); + if (!aCount) { + return NS_OK; + } + + RefPtr<InputStreamReader> reader = + InputStreamReader::Create(mStream, aOffset, aCount); + if (!reader) { + return NS_ERROR_FAILURE; + } + + uint32_t bytes = 0; + nsresult rv = reader->Read(aBuffer, aCount, &bytes); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return bytes == aCount ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult CloneableWithRangeMediaResource::ReadAt(int64_t aOffset, char* aBuffer, + uint32_t aCount, + uint32_t* aBytes) { + MOZ_ASSERT(!NS_IsMainThread()); + + RefPtr<InputStreamReader> reader = + InputStreamReader::Create(mStream, aOffset, aCount); + if (!reader) { + return NS_ERROR_FAILURE; + } + + nsresult rv = reader->Read(aBuffer, aCount, aBytes); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +} // namespace mozilla |