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