Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(379)

Side by Side Diff: webkit/glue/media/buffered_resource_loader.cc

Issue 5756004: Separate BufferedDataSource and BufferedResourceLoader into two files. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: inlining + removing Is...Protocol methods and getting rid of GetBufferedFirstBytePosition Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 #include "webkit/glue/media/buffered_resource_loader.h"
6
7 #include "base/format_macros.h"
8 #include "base/string_util.h"
9 #include "net/base/net_errors.h"
10 #include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
11 #include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h"
12 #include "third_party/WebKit/WebKit/chromium/public/WebString.h"
13 #include "third_party/WebKit/WebKit/chromium/public/WebURLError.h"
14 #include "webkit/glue/multipart_response_delegate.h"
15 #include "webkit/glue/webkit_glue.h"
16
17 using WebKit::WebFrame;
18 using WebKit::WebString;
19 using WebKit::WebURLError;
20 using WebKit::WebURLLoader;
21 using WebKit::WebURLRequest;
22 using WebKit::WebURLResponse;
23 using webkit_glue::MultipartResponseDelegate;
24
25 namespace {
26
27 const int kHttpOK = 200;
28 const int kHttpPartialContent = 206;
29
30 // Define the number of bytes in a megabyte.
31 const size_t kMegabyte = 1024 * 1024;
32
33 // Backward capacity of the buffer, by default 2MB.
34 const size_t kBackwardCapcity = 2 * kMegabyte;
35
36 // Forward capacity of the buffer, by default 10MB.
37 const size_t kForwardCapacity = 10 * kMegabyte;
38
39 // The threshold of bytes that we should wait until the data arrives in the
40 // future instead of restarting a new connection. This number is defined in the
41 // number of bytes, we should determine this value from typical connection speed
42 // and amount of time for a suitable wait. Now I just make a guess for this
43 // number to be 2MB.
44 // TODO(hclam): determine a better value for this.
45 const int kForwardWaitThreshold = 2 * kMegabyte;
46
47 } // namespace
48
49 namespace webkit_glue {
50
51 BufferedResourceLoader::BufferedResourceLoader(
52 const GURL& url,
53 int64 first_byte_position,
54 int64 last_byte_position)
55 : buffer_(new media::SeekableBuffer(kBackwardCapcity, kForwardCapacity)),
56 deferred_(false),
57 defer_allowed_(true),
58 completed_(false),
59 range_requested_(false),
60 partial_response_(false),
61 url_(url),
62 first_byte_position_(first_byte_position),
63 last_byte_position_(last_byte_position),
64 start_callback_(NULL),
65 offset_(0),
66 content_length_(kPositionNotSpecified),
67 instance_size_(kPositionNotSpecified),
68 read_callback_(NULL),
69 read_position_(0),
70 read_size_(0),
71 read_buffer_(NULL),
72 first_offset_(0),
73 last_offset_(0),
74 keep_test_loader_(false) {
75 }
76
77 BufferedResourceLoader::~BufferedResourceLoader() {
78 if (!completed_ && url_loader_.get())
79 url_loader_->cancel();
80 }
81
82 void BufferedResourceLoader::Start(net::CompletionCallback* start_callback,
83 NetworkEventCallback* event_callback,
84 WebFrame* frame) {
85 // Make sure we have not started.
86 DCHECK(!start_callback_.get());
87 DCHECK(!event_callback_.get());
88 DCHECK(start_callback);
89 DCHECK(event_callback);
90 CHECK(frame);
91
92 start_callback_.reset(start_callback);
93 event_callback_.reset(event_callback);
94
95 if (first_byte_position_ != kPositionNotSpecified) {
96 range_requested_ = true;
97 // TODO(hclam): server may not support range request so |offset_| may not
98 // equal to |first_byte_position_|.
99 offset_ = first_byte_position_;
100 }
101
102 // Increment the reference count right before we start the request. This
103 // reference will be release when this request has ended.
104 AddRef();
105
106 // Prepare the request.
107 WebURLRequest request(url_);
108 request.setHTTPHeaderField(WebString::fromUTF8("Range"),
109 WebString::fromUTF8(GenerateHeaders(
110 first_byte_position_,
111 last_byte_position_)));
112 frame->setReferrerForRequest(request, WebKit::WebURL());
113
114 // This flag is for unittests as we don't want to reset |url_loader|
115 if (!keep_test_loader_)
116 url_loader_.reset(frame->createAssociatedURLLoader());
117
118 // Start the resource loading.
119 url_loader_->loadAsynchronously(request, this);
120 }
121
122 void BufferedResourceLoader::Stop() {
123 // Reset callbacks.
124 start_callback_.reset();
125 event_callback_.reset();
126 read_callback_.reset();
127
128 // Use the internal buffer to signal that we have been stopped.
129 // TODO(hclam): Not so pretty to do this.
130 if (!buffer_.get())
131 return;
132
133 // Destroy internal buffer.
134 buffer_.reset();
135
136 if (url_loader_.get()) {
137 if (deferred_)
138 url_loader_->setDefersLoading(false);
139 deferred_ = false;
140
141 if (!completed_) {
142 url_loader_->cancel();
143 completed_ = true;
144 }
145 }
146 }
147
148 void BufferedResourceLoader::Read(int64 position,
149 int read_size,
150 uint8* buffer,
151 net::CompletionCallback* read_callback) {
152 DCHECK(!read_callback_.get());
153 DCHECK(buffer_.get());
154 DCHECK(read_callback);
155 DCHECK(buffer);
156
157 // Save the parameter of reading.
158 read_callback_.reset(read_callback);
159 read_position_ = position;
160 read_size_ = read_size;
161 read_buffer_ = buffer;
162
163 // If read position is beyond the instance size, we cannot read there.
164 if (instance_size_ != kPositionNotSpecified &&
165 instance_size_ <= read_position_) {
166 DoneRead(0);
167 return;
168 }
169
170 // Make sure |offset_| and |read_position_| does not differ by a large
171 // amount.
172 if (read_position_ > offset_ + kint32max ||
173 read_position_ < offset_ + kint32min) {
174 DoneRead(net::ERR_CACHE_MISS);
175 return;
176 }
177
178 // Prepare the parameters.
179 first_offset_ = static_cast<int>(read_position_ - offset_);
180 last_offset_ = first_offset_ + read_size_;
181
182 // If we can serve the request now, do the actual read.
183 if (CanFulfillRead()) {
184 ReadInternal();
185 DisableDeferIfNeeded();
186 return;
187 }
188
189 // If we expected the read request to be fulfilled later, returns
190 // immediately and let more data to flow in.
191 if (WillFulfillRead())
192 return;
193
194 // Make a callback to report failure.
195 DoneRead(net::ERR_CACHE_MISS);
196 }
197
198 int64 BufferedResourceLoader::GetBufferedPosition() {
199 if (buffer_.get())
200 return offset_ + static_cast<int>(buffer_->forward_bytes()) - 1;
201 return kPositionNotSpecified;
202 }
203
204 void BufferedResourceLoader::SetAllowDefer(bool is_allowed) {
205 defer_allowed_ = is_allowed;
206 DisableDeferIfNeeded();
207 }
208
209 int64 BufferedResourceLoader::content_length() {
210 return content_length_;
211 }
212
213 int64 BufferedResourceLoader::instance_size() {
214 return instance_size_;
215 }
216
217 bool BufferedResourceLoader::partial_response() {
218 return partial_response_;
219 }
220
221 bool BufferedResourceLoader::network_activity() {
222 return !completed_ && !deferred_;
223 }
224
225 const GURL& BufferedResourceLoader::url() {
226 return url_;
227 }
228
229 void BufferedResourceLoader::SetURLLoaderForTest(WebURLLoader* mock_loader) {
230 url_loader_.reset(mock_loader);
231 keep_test_loader_ = true;
232 }
233
234 // WebKit::WebURLLoaderClient implementations.
235 void BufferedResourceLoader::willSendRequest(
236 WebURLLoader* loader,
237 WebURLRequest& newRequest,
238 const WebURLResponse& redirectResponse) {
239
240 // The load may have been stopped and |start_callback| is destroyed.
241 // In this case we shouldn't do anything.
242 if (!start_callback_.get()) {
243 // Set the url in the request to an invalid value (empty url).
244 newRequest.setURL(WebKit::WebURL());
245 return;
246 }
247
248 if (!IsProtocolSupportedForMedia(newRequest.url())) {
249 // Set the url in the request to an invalid value (empty url).
250 newRequest.setURL(WebKit::WebURL());
251 DoneStart(net::ERR_ADDRESS_INVALID);
252 Stop();
253 return;
254 }
255
256 url_ = newRequest.url();
257 }
258
259 void BufferedResourceLoader::didSendData(
260 WebURLLoader* loader,
261 unsigned long long bytes_sent,
262 unsigned long long total_bytes_to_be_sent) {
263 NOTIMPLEMENTED();
264 }
265
266 void BufferedResourceLoader::didReceiveResponse(
267 WebURLLoader* loader,
268 const WebURLResponse& response) {
269
270 // The loader may have been stopped and |start_callback| is destroyed.
271 // In this case we shouldn't do anything.
272 if (!start_callback_.get())
273 return;
274
275 // We make a strong assumption that when we reach here we have either
276 // received a response from HTTP/HTTPS protocol or the request was
277 // successful (in particular range request). So we only verify the partial
278 // response for HTTP and HTTPS protocol.
279 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) {
280 int error = net::OK;
281
282 if (response.httpStatusCode() == kHttpPartialContent)
283 partial_response_ = true;
284
285 if (range_requested_ && partial_response_) {
286 // If we have verified the partial response and it is correct, we will
287 // return net::OK.
288 if (!VerifyPartialResponse(response))
289 error = net::ERR_INVALID_RESPONSE;
290 } else if (response.httpStatusCode() != kHttpOK) {
291 // We didn't request a range but server didn't reply with "200 OK".
292 error = net::ERR_FAILED;
293 }
294
295 if (error != net::OK) {
296 DoneStart(error);
297 Stop();
298 return;
299 }
300 } else {
301 // For any protocol other than HTTP and HTTPS, assume range request is
302 // always fulfilled.
303 partial_response_ = range_requested_;
304 }
305
306 // Expected content length can be |kPositionNotSpecified|, in that case
307 // |content_length_| is not specified and this is a streaming response.
308 content_length_ = response.expectedContentLength();
309
310 // If we have not requested a range, then the size of the instance is equal
311 // to the content length.
312 if (!partial_response_)
313 instance_size_ = content_length_;
314
315 // Calls with a successful response.
316 DoneStart(net::OK);
317 }
318
319 void BufferedResourceLoader::didReceiveData(
320 WebURLLoader* loader,
321 const char* data,
322 int data_length) {
323 DCHECK(!completed_);
324 DCHECK_GT(data_length, 0);
325
326 // If this loader has been stopped, |buffer_| would be destroyed.
327 // In this case we shouldn't do anything.
328 if (!buffer_.get())
329 return;
330
331 // Writes more data to |buffer_|.
332 buffer_->Append(reinterpret_cast<const uint8*>(data), data_length);
333
334 // If there is an active read request, try to fulfill the request.
335 if (HasPendingRead() && CanFulfillRead()) {
336 ReadInternal();
337 } else if (!defer_allowed_) {
338 // If we're not allowed to defer, slide the buffer window forward instead
339 // of deferring.
340 if (buffer_->forward_bytes() > buffer_->forward_capacity()) {
341 size_t excess = buffer_->forward_bytes() - buffer_->forward_capacity();
342 bool success = buffer_->Seek(excess);
343 DCHECK(success);
344 offset_ += first_offset_ + excess;
345 }
346 }
347
348 // At last see if the buffer is full and we need to defer the downloading.
349 EnableDeferIfNeeded();
350
351 // Notify that we have received some data.
352 NotifyNetworkEvent();
353 }
354
355 void BufferedResourceLoader::didDownloadData(
356 WebKit::WebURLLoader* loader,
357 int dataLength) {
358 NOTIMPLEMENTED();
359 }
360
361 void BufferedResourceLoader::didReceiveCachedMetadata(
362 WebURLLoader* loader,
363 const char* data,
364 int data_length) {
365 NOTIMPLEMENTED();
366 }
367
368 void BufferedResourceLoader::didFinishLoading(
369 WebURLLoader* loader,
370 double finishTime) {
371 DCHECK(!completed_);
372 completed_ = true;
373
374 // If there is a start callback, calls it.
375 if (start_callback_.get()) {
376 DoneStart(net::OK);
377 }
378
379 // If there is a pending read but the request has ended, returns with what
380 // we have.
381 if (HasPendingRead()) {
382 // Make sure we have a valid buffer before we satisfy a read request.
383 DCHECK(buffer_.get());
384
385 // Try to fulfill with what is in the buffer.
386 if (CanFulfillRead())
387 ReadInternal();
388 else
389 DoneRead(net::ERR_CACHE_MISS);
390 }
391
392 // There must not be any outstanding read request.
393 DCHECK(!HasPendingRead());
394
395 // Notify that network response is completed.
396 NotifyNetworkEvent();
397
398 url_loader_.reset();
399 Release();
400 }
401
402 void BufferedResourceLoader::didFail(
403 WebURLLoader* loader,
404 const WebURLError& error) {
405 DCHECK(!completed_);
406 completed_ = true;
407
408 // If there is a start callback, calls it.
409 if (start_callback_.get()) {
410 DoneStart(error.reason);
411 }
412
413 // If there is a pending read but the request failed, return with the
414 // reason for the error.
415 if (HasPendingRead()) {
416 DoneRead(error.reason);
417 }
418
419 // Notify that network response is completed.
420 NotifyNetworkEvent();
421
422 url_loader_.reset();
423 Release();
424 }
425
426 void BufferedResourceLoader::EnableDeferIfNeeded() {
427 if (!defer_allowed_)
428 return;
429
430 if (!deferred_ &&
431 buffer_->forward_bytes() >= buffer_->forward_capacity()) {
432 deferred_ = true;
433
434 if (url_loader_.get())
435 url_loader_->setDefersLoading(true);
436
437 NotifyNetworkEvent();
438 }
439 }
440
441 void BufferedResourceLoader::DisableDeferIfNeeded() {
442 if (deferred_ &&
443 (!defer_allowed_ ||
444 buffer_->forward_bytes() < buffer_->forward_capacity() / 2)) {
445 deferred_ = false;
446
447 if (url_loader_.get())
448 url_loader_->setDefersLoading(false);
449
450 NotifyNetworkEvent();
451 }
452 }
453
454 bool BufferedResourceLoader::CanFulfillRead() {
455 // If we are reading too far in the backward direction.
456 if (first_offset_ < 0 &&
457 first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0)
458 return false;
459
460 // If the start offset is too far ahead.
461 if (first_offset_ >= static_cast<int>(buffer_->forward_bytes()))
462 return false;
463
464 // At the point, we verified that first byte requested is within the buffer.
465 // If the request has completed, then just returns with what we have now.
466 if (completed_)
467 return true;
468
469 // If the resource request is still active, make sure the whole requested
470 // range is covered.
471 if (last_offset_ > static_cast<int>(buffer_->forward_bytes()))
472 return false;
473
474 return true;
475 }
476
477 bool BufferedResourceLoader::WillFulfillRead() {
478 // Reading too far in the backward direction.
479 if (first_offset_ < 0 &&
480 first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0)
481 return false;
482
483 // Try to read too far ahead.
484 if (last_offset_ > kForwardWaitThreshold)
485 return false;
486
487 // The resource request has completed, there's no way we can fulfill the
488 // read request.
489 if (completed_)
490 return false;
491
492 return true;
493 }
494
495 void BufferedResourceLoader::ReadInternal() {
496 // Seek to the first byte requested.
497 bool ret = buffer_->Seek(first_offset_);
498 DCHECK(ret);
499
500 // Then do the read.
501 int read = static_cast<int>(buffer_->Read(read_buffer_, read_size_));
502 offset_ += first_offset_ + read;
503
504 // And report with what we have read.
505 DoneRead(read);
506 }
507
508 bool BufferedResourceLoader::VerifyPartialResponse(
509 const WebURLResponse& response) {
510 int first_byte_position, last_byte_position, instance_size;
511
512 if (!MultipartResponseDelegate::ReadContentRanges(response,
513 &first_byte_position,
514 &last_byte_position,
515 &instance_size)) {
516 return false;
517 }
518
519 if (instance_size != kPositionNotSpecified) {
520 instance_size_ = instance_size;
521 }
522
523 if (first_byte_position_ != kPositionNotSpecified &&
524 first_byte_position_ != first_byte_position) {
525 return false;
526 }
527
528 // TODO(hclam): I should also check |last_byte_position|, but since
529 // we will never make such a request that it is ok to leave it unimplemented.
530 return true;
531 }
532
533 std::string BufferedResourceLoader::GenerateHeaders(
534 int64 first_byte_position,
535 int64 last_byte_position) {
536 // Construct the value for the range header.
537 std::string header;
538 if (first_byte_position > kPositionNotSpecified &&
539 last_byte_position > kPositionNotSpecified) {
540 if (first_byte_position <= last_byte_position) {
541 header = base::StringPrintf("bytes=%" PRId64 "-%" PRId64,
542 first_byte_position,
543 last_byte_position);
544 }
545 } else if (first_byte_position > kPositionNotSpecified) {
546 header = base::StringPrintf("bytes=%" PRId64 "-",
547 first_byte_position);
548 } else if (last_byte_position > kPositionNotSpecified) {
549 NOTIMPLEMENTED() << "Suffix range not implemented";
550 }
551 return header;
552 }
553
554 void BufferedResourceLoader::DoneRead(int error) {
555 read_callback_->RunWithParams(Tuple1<int>(error));
556 read_callback_.reset();
557 read_position_ = 0;
558 read_size_ = 0;
559 read_buffer_ = NULL;
560 first_offset_ = 0;
561 last_offset_ = 0;
562 }
563
564 void BufferedResourceLoader::DoneStart(int error) {
565 start_callback_->RunWithParams(Tuple1<int>(error));
566 start_callback_.reset();
567 }
568
569 void BufferedResourceLoader::NotifyNetworkEvent() {
570 if (event_callback_.get())
571 event_callback_->Run();
572 }
573
574 } // namespace webkit_glue
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698