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