Bug 1772053 - Enable dynamic code disable mitigations only on Windows 10 1703+ r...
[gecko.git] / dom / media / ChannelMediaResource.h
blob695e490c6f7c037a2e8d6d19d3f55312d9ced348
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/. */
6 #ifndef mozilla_dom_media_ChannelMediaResource_h
7 #define mozilla_dom_media_ChannelMediaResource_h
9 #include "BaseMediaResource.h"
10 #include "MediaCache.h"
11 #include "mozilla/Mutex.h"
12 #include "nsIChannelEventSink.h"
13 #include "nsIInterfaceRequestor.h"
14 #include "nsIThreadRetargetableStreamListener.h"
16 class nsIHttpChannel;
18 namespace mozilla {
20 /**
21 * This class is responsible for managing the suspend count and report suspend
22 * status of channel.
23 **/
24 class ChannelSuspendAgent {
25 public:
26 explicit ChannelSuspendAgent(MediaCacheStream& aCacheStream)
27 : mCacheStream(aCacheStream) {}
29 // True when the channel has been suspended or needs to be suspended.
30 bool IsSuspended();
32 // Return true when the channel is logically suspended, i.e. the suspend
33 // count goes from 0 to 1.
34 bool Suspend();
36 // Return true only when the suspend count is equal to zero.
37 bool Resume();
39 // Tell the agent to manage the suspend status of the channel.
40 void Delegate(nsIChannel* aChannel);
41 // Stop the management of the suspend status of the channel.
42 void Revoke();
44 private:
45 // Only suspends channel but not changes the suspend count.
46 void SuspendInternal();
48 nsIChannel* mChannel = nullptr;
49 MediaCacheStream& mCacheStream;
50 uint32_t mSuspendCount = 0;
51 bool mIsChannelSuspended = false;
54 DDLoggedTypeDeclNameAndBase(ChannelMediaResource, BaseMediaResource);
56 /**
57 * This is the MediaResource implementation that wraps Necko channels.
58 * Much of its functionality is actually delegated to MediaCache via
59 * an underlying MediaCacheStream.
61 * All synchronization is performed by MediaCacheStream; all off-main-
62 * thread operations are delegated directly to that object.
64 class ChannelMediaResource
65 : public BaseMediaResource,
66 public DecoderDoctorLifeLogger<ChannelMediaResource> {
67 // Store information shared among resources. Main thread only.
68 struct SharedInfo {
69 NS_INLINE_DECL_REFCOUNTING(SharedInfo);
71 nsTArray<ChannelMediaResource*> mResources;
72 // Null if there is not yet any data from any origin.
73 nsCOMPtr<nsIPrincipal> mPrincipal;
74 // Meaningful only when mPrincipal is non-null,
75 // unaffected by intermediate cross-origin redirects.
76 bool mFinalResponsesAreOpaque = false;
78 bool mHadCrossOriginRedirects = false;
80 private:
81 ~SharedInfo() = default;
83 RefPtr<SharedInfo> mSharedInfo;
85 public:
86 ChannelMediaResource(MediaResourceCallback* aDecoder, nsIChannel* aChannel,
87 nsIURI* aURI, int64_t aStreamLength,
88 bool aIsPrivateBrowsing = false);
89 ~ChannelMediaResource();
91 // These are called on the main thread by MediaCache. These must
92 // not block or grab locks, because the media cache is holding its lock.
93 // Notify that data is available from the cache. This can happen even
94 // if this stream didn't read any data, since another stream might have
95 // received data for the same resource.
96 void CacheClientNotifyDataReceived();
97 // Notify that we reached the end of the stream. This can happen even
98 // if this stream didn't read any data, since another stream might have
99 // received data for the same resource.
100 void CacheClientNotifyDataEnded(nsresult aStatus);
101 // Notify that the principal for the cached resource changed.
102 void CacheClientNotifyPrincipalChanged();
103 // Notify the decoder that the cache suspended status changed.
104 void CacheClientNotifySuspendedStatusChanged(bool aSuspended);
106 // These are called on the main thread by MediaCache. These shouldn't block,
107 // but they may grab locks --- the media cache is not holding its lock
108 // when these are called.
109 // Start a new load at the given aOffset. The old load is cancelled
110 // and no more data from the old load will be notified via
111 // MediaCacheStream::NotifyDataReceived/Ended.
112 void CacheClientSeek(int64_t aOffset, bool aResume);
113 // Suspend the current load since data is currently not wanted
114 void CacheClientSuspend();
115 // Resume the current load since data is wanted again
116 void CacheClientResume();
118 bool IsSuspended();
120 void ThrottleReadahead(bool bThrottle) override;
122 // Main thread
123 nsresult Open(nsIStreamListener** aStreamListener) override;
124 RefPtr<GenericPromise> Close() override;
125 void Suspend(bool aCloseImmediately) override;
126 void Resume() override;
127 already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
128 bool HadCrossOriginRedirects() override;
129 bool CanClone() override;
130 already_AddRefed<BaseMediaResource> CloneData(
131 MediaResourceCallback* aDecoder) override;
132 nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
133 uint32_t aCount) override;
135 // Other thread
136 void SetReadMode(MediaCacheStream::ReadMode aMode) override;
137 void SetPlaybackRate(uint32_t aBytesPerSecond) override;
138 nsresult ReadAt(int64_t offset, char* aBuffer, uint32_t aCount,
139 uint32_t* aBytes) override;
140 // Data stored in IO&lock-encumbered MediaCacheStream, caching recommended.
141 bool ShouldCacheReads() override { return true; }
143 // Any thread
144 void Pin() override;
145 void Unpin() override;
146 double GetDownloadRate(bool* aIsReliable) override;
147 int64_t GetLength() override;
148 int64_t GetNextCachedData(int64_t aOffset) override;
149 int64_t GetCachedDataEnd(int64_t aOffset) override;
150 bool IsDataCachedToEndOfResource(int64_t aOffset) override;
151 bool IsTransportSeekable() override;
152 bool IsLiveStream() const override { return mIsLiveStream; }
154 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override {
155 // Might be useful to track in the future:
156 // - mListener (seems minor)
157 size_t size = BaseMediaResource::SizeOfExcludingThis(aMallocSizeOf);
158 size += mCacheStream.SizeOfExcludingThis(aMallocSizeOf);
160 return size;
163 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
164 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
167 void GetDebugInfo(dom::MediaResourceDebugInfo& aInfo) override;
169 class Listener final : public nsIStreamListener,
170 public nsIInterfaceRequestor,
171 public nsIChannelEventSink,
172 public nsIThreadRetargetableStreamListener {
173 ~Listener() = default;
175 public:
176 Listener(ChannelMediaResource* aResource, int64_t aOffset, uint32_t aLoadID)
177 : mMutex("Listener.mMutex"),
178 mResource(aResource),
179 mOffset(aOffset),
180 mLoadID(aLoadID) {}
182 NS_DECL_THREADSAFE_ISUPPORTS
183 NS_DECL_NSIREQUESTOBSERVER
184 NS_DECL_NSISTREAMLISTENER
185 NS_DECL_NSICHANNELEVENTSINK
186 NS_DECL_NSIINTERFACEREQUESTOR
187 NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
189 void Revoke();
191 private:
192 Mutex mMutex MOZ_UNANNOTATED;
193 // mResource should only be modified on the main thread with the lock.
194 // So it can be read without lock on the main thread or on other threads
195 // with the lock.
196 RefPtr<ChannelMediaResource> mResource;
198 const int64_t mOffset;
199 const uint32_t mLoadID;
201 friend class Listener;
203 nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override;
205 protected:
206 nsresult Seek(int64_t aOffset, bool aResume);
208 // These are called on the main thread by Listener.
209 nsresult OnStartRequest(nsIRequest* aRequest, int64_t aRequestOffset);
210 nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus);
211 nsresult OnDataAvailable(uint32_t aLoadID, nsIInputStream* aStream,
212 uint32_t aCount);
213 nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew,
214 uint32_t aFlags, int64_t aOffset);
216 // Opens the channel, using an HTTP byte range request to start at aOffset
217 // if possible. Main thread only.
218 nsresult OpenChannel(int64_t aOffset);
219 nsresult RecreateChannel();
220 // Add headers to HTTP request. Main thread only.
221 nsresult SetupChannelHeaders(int64_t aOffset);
222 // Closes the channel. Main thread only.
223 void CloseChannel();
224 // Update the principal for the resource. Main thread only.
225 void UpdatePrincipal();
227 // Parses 'Content-Range' header and returns results via parameters.
228 // Returns error if header is not available, values are not parse-able or
229 // values are out of range.
230 nsresult ParseContentRangeHeader(nsIHttpChannel* aHttpChan,
231 int64_t& aRangeStart, int64_t& aRangeEnd,
232 int64_t& aRangeTotal) const;
234 // Calculates the length of the resource using HTTP headers, if this
235 // is an HTTP channel. Returns -1 on failure, or for non HTTP channels.
236 int64_t CalculateStreamLength() const;
238 struct Closure {
239 uint32_t mLoadID;
240 ChannelMediaResource* mResource;
243 static nsresult CopySegmentToCache(nsIInputStream* aInStream, void* aClosure,
244 const char* aFromSegment,
245 uint32_t aToOffset, uint32_t aCount,
246 uint32_t* aWriteCount);
248 // Main thread access only
249 // True if Close() has been called.
250 bool mClosed = false;
251 // The last reported seekability state for the underlying channel
252 bool mIsTransportSeekable = false;
253 // Length of the content first reported.
254 int64_t mFirstReadLength = -1;
255 RefPtr<Listener> mListener;
256 // A mono-increasing integer to uniquely identify the channel we are loading.
257 uint32_t mLoadID = 0;
258 bool mIsLiveStream = false;
260 // Any thread access
261 MediaCacheStream mCacheStream;
263 ChannelSuspendAgent mSuspendAgent;
265 // The size of the stream if known at construction time (such as with blob)
266 const int64_t mKnownStreamLength;
269 } // namespace mozilla
271 #endif // mozilla_dom_media_ChannelMediaResource_h