summaryrefslogtreecommitdiffstats
path: root/media/blink/url_index.h
blob: be96858825b964904f5d8bd0ba24228c2970aef2 (plain)
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
// 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/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 "third_party/WebKit/public/web/WebFrame.h"
#include "url/gurl.h"

namespace media {

const int64_t kPositionNotSpecified = -1;

class UrlData;

// A multibuffer for loading media resources which knows
// how to create MultiBufferDataProviders to load data
// into the cache.
class MEDIA_BLINK_EXPORT ResourceMultiBuffer
    : NON_EXPORTED_BASE(public MultiBuffer) {
 public:
  ResourceMultiBuffer(UrlData* url_data_, int block_shift);
  ~ResourceMultiBuffer() override;

  // MultiBuffer implementation.
  scoped_ptr<MultiBuffer::DataProvider> CreateWriter(
      const BlockId& pos) 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;

  // 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_; }

  // 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 our url_index, or nullptr if it's been destroyed.
  UrlIndex* url_index() const { return url_index_.get(); }

  // 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();

  // 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);

  // 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() const;

  // Virtual so we can override it for testing.
  virtual ResourceMultiBuffer* multibuffer();

  // Accessor
  blink::WebFrame* frame() const { return frame_; }

 protected:
  UrlData(const GURL& url,
          CORSMode cors_mode,
          const base::WeakPtr<UrlIndex>& url_index);
  virtual ~UrlData();

 private:
  friend class ResourceMultiBuffer;
  friend class UrlIndex;
  friend class base::RefCounted<UrlData>;

  void OnEmpty();
  void MergeFrom(const scoped_refptr<UrlData>& other);

  // Url we represent, note that there may be multiple UrlData for
  // the same url.
  const GURL url_;

  // Cross-origin access mode.
  const CORSMode cors_mode_;

  base::WeakPtr<UrlIndex> url_index_;

  // Length of resource this url points to. (in bytes)
  int64_t length_;

  // 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_;

  // 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_;

  ResourceMultiBuffer multibuffer_;
  std::vector<RedirectCB> redirect_callbacks_;

  blink::WebFrame* frame_;

  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(blink::WebFrame*);
  UrlIndex(blink::WebFrame*, 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.
  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.
  // TODO(hubbe): Add etag support.
  scoped_refptr<UrlData> TryInsert(const scoped_refptr<UrlData>& url_data);

  blink::WebFrame* frame() const { return frame_; }
  int block_shift() const { return block_shift_; }

 private:
  friend class UrlData;
  friend class ResourceMultiBuffer;
  void RemoveUrlDataIfEmpty(const scoped_refptr<UrlData>& url_data);

  // Virtual so we can override it in tests.
  virtual scoped_refptr<UrlData> NewUrlData(const GURL& url,
                                            UrlData::CORSMode cors_mode);

  std::map<UrlData::KeyType, scoped_refptr<UrlData>> by_url_;
  blink::WebFrame* frame_;
  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_;

 protected:
  base::WeakPtrFactory<UrlIndex> weak_factory_;
};

}  // namespace media
#endif  // MEDIA_BLINK_URL_INDEX_H_