1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef MEDIA_BLINK_URL_INDEX_H_ 6 #define MEDIA_BLINK_URL_INDEX_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <map> 12 #include <vector> 13 14 #include "base/macros.h" 15 #include "base/memory/memory_pressure_listener.h" 16 #include "base/memory/ref_counted.h" 17 #include "base/memory/weak_ptr.h" 18 #include "base/threading/thread_checker.h" 19 #include "media/blink/lru.h" 20 #include "media/blink/media_blink_export.h" 21 #include "media/blink/multibuffer.h" 22 #include "services/network/public/mojom/fetch_api.mojom.h" 23 #include "url/gurl.h" 24 25 namespace media { 26 27 const int64_t kPositionNotSpecified = -1; 28 29 class ResourceFetchContext; 30 class UrlData; 31 class UrlIndexTest; 32 33 // A multibuffer for loading media resources which knows 34 // how to create MultiBufferDataProviders to load data 35 // into the cache. 36 class MEDIA_BLINK_EXPORT ResourceMultiBuffer : public MultiBuffer { 37 public: 38 ResourceMultiBuffer(UrlData* url_data_, int block_shift); 39 ~ResourceMultiBuffer() override; 40 41 // MultiBuffer implementation. 42 std::unique_ptr<MultiBuffer::DataProvider> CreateWriter( 43 const BlockId& pos, 44 bool is_client_audio_element) override; 45 bool RangeSupported() const override; 46 void OnEmpty() override; 47 48 protected: 49 // Do not access from destructor, it is a pointer to the 50 // object that contains us. 51 UrlData* url_data_; 52 }; 53 54 class UrlIndex; 55 56 // All the data & metadata for a single resource. 57 // Data is cached using a MultiBuffer instance. 58 class MEDIA_BLINK_EXPORT UrlData : public base::RefCounted<UrlData> { 59 public: 60 // Keep in sync with WebMediaPlayer::CorsMode. 61 enum CorsMode { CORS_UNSPECIFIED, CORS_ANONYMOUS, CORS_USE_CREDENTIALS }; 62 typedef std::pair<GURL, CorsMode> KeyType; 63 64 // Accessors url()65 const GURL& url() const { return url_; } 66 67 // Cross-origin access mode cors_mode()68 CorsMode cors_mode() const { return cors_mode_; } 69 has_access_control()70 bool has_access_control() const { return has_access_control_; } 71 72 // Are HTTP range requests supported? range_supported()73 bool range_supported() const { return range_supported_; } 74 75 // True if we found a reason why this URL won't be stored in the 76 // HTTP disk cache. cacheable()77 bool cacheable() const { return cacheable_; } 78 79 // Last used time. last_used()80 base::Time last_used() const { return last_used_; } 81 82 // Last modified time. last_modified()83 base::Time last_modified() const { return last_modified_; } 84 etag()85 const std::string& etag() const { return etag_; } 86 87 // Expiration time. valid_until()88 base::Time valid_until() const { return valid_until_; } 89 90 // The key used by UrlIndex to find this UrlData. 91 KeyType key() const; 92 93 // Length of data associated with url or |kPositionNotSpecified| length()94 int64_t length() const { return length_; } 95 96 // Returns the number of blocks cached for this resource. 97 size_t CachedSize(); 98 99 // Returns true if this resource is fully cached in memory. 100 bool FullyCached(); 101 102 // Returns our url_index. url_index()103 UrlIndex* url_index() const { return url_index_; } 104 105 // This must be called after the response arrives. is_cors_cross_origin()106 bool is_cors_cross_origin() const { return is_cors_cross_origin_; } 107 108 // Notifies the url index that this is currently used. 109 // The url <-> URLData mapping will be eventually be invalidated if 110 // this is not called regularly. 111 void Use(); 112 113 // Call this before we add some data to the multibuffer(). 114 // If the multibuffer is empty, the data origin is set from 115 // |origin| and returns true. If not, it compares |origin| 116 // to the previous origin and returns whether they match or not. 117 bool ValidateDataOrigin(const GURL& origin); 118 119 // Setters. 120 void set_length(int64_t length); 121 void set_cacheable(bool cacheable); 122 void set_valid_until(base::Time valid_until); 123 void set_range_supported(); 124 void set_last_modified(base::Time last_modified); 125 void set_etag(const std::string& etag); 126 void set_is_cors_cross_origin(bool is_cors_cross_origin); 127 void set_has_access_control(); 128 129 // A redirect has occurred (or we've found a better UrlData for the same 130 // resource). 131 void RedirectTo(const scoped_refptr<UrlData>& to); 132 133 // Fail, tell all clients that a failure has occurred. 134 void Fail(); 135 136 // Callback for receiving notifications when a redirect occurs. 137 using RedirectCB = base::OnceCallback<void(const scoped_refptr<UrlData>&)>; 138 139 // Register a callback to be called when a redirect occurs. 140 // Callbacks are cleared when a redirect occurs, so clients must call 141 // OnRedirect again if they wish to continue receiving callbacks. 142 void OnRedirect(RedirectCB cb); 143 144 // Returns true it is valid to keep using this to access cached data. 145 // A single media player instance may choose to ignore this for resources 146 // that have already been opened. 147 bool Valid(); 148 149 // Virtual so we can override it for testing. 150 virtual ResourceMultiBuffer* multibuffer(); 151 AddBytesRead(int64_t b)152 void AddBytesRead(int64_t b) { bytes_read_from_cache_ += b; } BytesReadFromCache()153 int64_t BytesReadFromCache() const { return bytes_read_from_cache_; } 154 155 protected: 156 UrlData(const GURL& url, CorsMode cors_mode, UrlIndex* url_index); 157 virtual ~UrlData(); 158 159 private: 160 friend class ResourceMultiBuffer; 161 friend class UrlIndex; 162 friend class UrlIndexTest; 163 friend class base::RefCounted<UrlData>; 164 165 void OnEmpty(); 166 void MergeFrom(const scoped_refptr<UrlData>& other); 167 168 // Url we represent, note that there may be multiple UrlData for 169 // the same url. 170 const GURL url_; 171 172 // Origin of the data, should only be different from the url_.GetOrigin() 173 // when service workers are involved. 174 GURL data_origin_; 175 bool have_data_origin_; 176 177 // Cross-origin access mode. 178 const CorsMode cors_mode_; 179 bool has_access_control_; 180 181 UrlIndex* const url_index_; 182 183 // Length of resource this url points to. (in bytes) 184 int64_t length_; 185 186 // Number of bytes read from this resource. 187 int64_t bytes_read_from_cache_ = 0; 188 189 // Does the server support ranges? 190 bool range_supported_; 191 192 // Set to false if we have reason to believe the chrome disk cache 193 // will not cache this url. 194 bool cacheable_; 195 196 // https://html.spec.whatwg.org/#cors-cross-origin 197 bool is_cors_cross_origin_ = false; 198 199 // Last time some media time used this resource. 200 // Note that we use base::Time rather than base::TimeTicks because 201 // TimeTicks will stop advancing when a machine goes to sleep. 202 // base::Time can go backwards, jump hours at a time and be generally 203 // unpredictable, but it doesn't stop, which is preferable here. 204 // (False negatives are better than false positivies.) 205 base::Time last_used_; 206 207 // Expiration time according to http headers. 208 base::Time valid_until_; 209 210 // Last modification time according to http headers. 211 base::Time last_modified_; 212 213 // Etag from HTTP reply. 214 std::string etag_; 215 216 ResourceMultiBuffer multibuffer_; 217 std::vector<RedirectCB> redirect_callbacks_; 218 219 base::ThreadChecker thread_checker_; 220 DISALLOW_COPY_AND_ASSIGN(UrlData); 221 }; 222 223 // The UrlIndex lets you look up UrlData instances by url. 224 class MEDIA_BLINK_EXPORT UrlIndex { 225 public: 226 explicit UrlIndex(ResourceFetchContext* fetch_context); 227 UrlIndex(ResourceFetchContext* fetch_context, int block_shift); 228 virtual ~UrlIndex(); 229 230 // Look up an UrlData in the index and return it. If none is found, 231 // create a new one. Note that newly created UrlData entries are NOT 232 // added to the index, instead you must call TryInsert on them after 233 // initializing relevant parameters, like whether it support 234 // ranges and it's last modified time. 235 // Because the returned UrlData has a raw reference to |this|, it must be 236 // released before |this| is destroyed. 237 scoped_refptr<UrlData> GetByUrl(const GURL& gurl, 238 UrlData::CorsMode cors_mode); 239 240 // Add the given UrlData to the index if possible. If a better UrlData 241 // is already present in the index, return it instead. (If not, we just 242 // return the given UrlData.) Please make sure to initialize all the data 243 // that can be gathered from HTTP headers in |url_data| before calling this. 244 // In particular, the following fields are important: 245 // o range_supported: Entries which do not support ranges cannot be 246 // shared and are not added to the index. 247 // o valid_until, last_used: Entries have to be valid to be inserted 248 // into the index, this means that they have to have been recently 249 // used or have an Expires: header that says when they stop being valid. 250 // o last_modified: Expired cache entries can be re-used if last_modified 251 // matches. 252 // Because the returned UrlData has a raw reference to |this|, it must be 253 // released before |this| is destroyed. 254 // TODO(hubbe): Add etag support. 255 scoped_refptr<UrlData> TryInsert(const scoped_refptr<UrlData>& url_data); 256 fetch_context()257 ResourceFetchContext* fetch_context() const { return fetch_context_; } block_shift()258 int block_shift() const { return block_shift_; } 259 260 // Returns true kMaxParallelPreload or more urls are loading at the same time. 261 bool HasReachedMaxParallelPreload() const; 262 263 // Protected rather than private for testing. 264 protected: 265 friend class UrlData; 266 friend class ResourceMultiBuffer; 267 friend class UrlIndexTest; 268 void RemoveUrlData(const scoped_refptr<UrlData>& url_data); 269 270 // Virtual so we can override it in tests. 271 virtual scoped_refptr<UrlData> NewUrlData(const GURL& url, 272 UrlData::CorsMode cors_mode); 273 274 void OnMemoryPressure( 275 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level); 276 277 ResourceFetchContext* fetch_context_; 278 using UrlDataMap = std::map<UrlData::KeyType, scoped_refptr<UrlData>>; 279 UrlDataMap indexed_data_; 280 scoped_refptr<MultiBuffer::GlobalLRU> lru_; 281 282 // log2 of block size in multibuffer cache. Defaults to kBlockSizeShift. 283 // Currently only changed for testing purposes. 284 const int block_shift_; 285 286 std::deque<scoped_refptr<UrlData>> loading_queue_; 287 288 base::MemoryPressureListener memory_pressure_listener_; 289 }; 290 291 } // namespace media 292 #endif // MEDIA_BLINK_URL_INDEX_H_ 293