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

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

Issue 18123002: Migrate webkit/renderer/media/ to content/renderer/media/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: delegates Created 7 years, 5 months 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 2013 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/renderer/media/buffered_resource_loader.h"
6
7 #include "base/bits.h"
8 #include "base/callback_helpers.h"
9 #include "base/format_macros.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "media/base/media_log.h"
15 #include "net/http/http_request_headers.h"
16 #include "third_party/WebKit/public/platform/WebString.h"
17 #include "third_party/WebKit/public/platform/WebURLError.h"
18 #include "third_party/WebKit/public/platform/WebURLResponse.h"
19 #include "third_party/WebKit/public/web/WebKit.h"
20 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
21 #include "webkit/renderer/media/cache_util.h"
22
23 using WebKit::WebFrame;
24 using WebKit::WebString;
25 using WebKit::WebURLError;
26 using WebKit::WebURLLoader;
27 using WebKit::WebURLLoaderOptions;
28 using WebKit::WebURLRequest;
29 using WebKit::WebURLResponse;
30
31 namespace webkit_media {
32
33 static const int kHttpOK = 200;
34 static const int kHttpPartialContent = 206;
35
36 // Define the number of bytes in a megabyte.
37 static const int kMegabyte = 1024 * 1024;
38
39 // Minimum capacity of the buffer in forward or backward direction.
40 //
41 // 2MB is an arbitrary limit; it just seems to be "good enough" in practice.
42 static const int kMinBufferCapacity = 2 * kMegabyte;
43
44 // Maximum capacity of the buffer in forward or backward direction. This is
45 // effectively the largest single read the code path can handle.
46 // 20MB is an arbitrary limit; it just seems to be "good enough" in practice.
47 static const int kMaxBufferCapacity = 20 * kMegabyte;
48
49 // Maximum number of bytes outside the buffer we will wait for in order to
50 // fulfill a read. If a read starts more than 2MB away from the data we
51 // currently have in the buffer, we will not wait for buffer to reach the read's
52 // location and will instead reset the request.
53 static const int kForwardWaitThreshold = 2 * kMegabyte;
54
55 // Computes the suggested backward and forward capacity for the buffer
56 // if one wants to play at |playback_rate| * the natural playback speed.
57 // Use a value of 0 for |bitrate| if it is unknown.
58 static void ComputeTargetBufferWindow(float playback_rate, int bitrate,
59 int* out_backward_capacity,
60 int* out_forward_capacity) {
61 static const int kDefaultBitrate = 200 * 1024 * 8; // 200 Kbps.
62 static const int kMaxBitrate = 20 * kMegabyte * 8; // 20 Mbps.
63 static const float kMaxPlaybackRate = 25.0;
64 static const int kTargetSecondsBufferedAhead = 10;
65 static const int kTargetSecondsBufferedBehind = 2;
66
67 // Use a default bit rate if unknown and clamp to prevent overflow.
68 if (bitrate <= 0)
69 bitrate = kDefaultBitrate;
70 bitrate = std::min(bitrate, kMaxBitrate);
71
72 // Only scale the buffer window for playback rates greater than 1.0 in
73 // magnitude and clamp to prevent overflow.
74 bool backward_playback = false;
75 if (playback_rate < 0.0f) {
76 backward_playback = true;
77 playback_rate *= -1.0f;
78 }
79
80 playback_rate = std::max(playback_rate, 1.0f);
81 playback_rate = std::min(playback_rate, kMaxPlaybackRate);
82
83 int bytes_per_second = (bitrate / 8.0) * playback_rate;
84
85 // Clamp between kMinBufferCapacity and kMaxBufferCapacity.
86 *out_forward_capacity = std::max(
87 kTargetSecondsBufferedAhead * bytes_per_second, kMinBufferCapacity);
88 *out_backward_capacity = std::max(
89 kTargetSecondsBufferedBehind * bytes_per_second, kMinBufferCapacity);
90
91 *out_forward_capacity = std::min(*out_forward_capacity, kMaxBufferCapacity);
92 *out_backward_capacity = std::min(*out_backward_capacity, kMaxBufferCapacity);
93
94 if (backward_playback)
95 std::swap(*out_forward_capacity, *out_backward_capacity);
96 }
97
98 BufferedResourceLoader::BufferedResourceLoader(
99 const GURL& url,
100 CORSMode cors_mode,
101 int64 first_byte_position,
102 int64 last_byte_position,
103 DeferStrategy strategy,
104 int bitrate,
105 float playback_rate,
106 media::MediaLog* media_log)
107 : buffer_(kMinBufferCapacity, kMinBufferCapacity),
108 loader_failed_(false),
109 defer_strategy_(strategy),
110 might_be_reused_from_cache_in_future_(true),
111 range_supported_(false),
112 saved_forward_capacity_(0),
113 url_(url),
114 cors_mode_(cors_mode),
115 first_byte_position_(first_byte_position),
116 last_byte_position_(last_byte_position),
117 single_origin_(true),
118 offset_(0),
119 content_length_(kPositionNotSpecified),
120 instance_size_(kPositionNotSpecified),
121 read_position_(0),
122 read_size_(0),
123 read_buffer_(NULL),
124 first_offset_(0),
125 last_offset_(0),
126 bitrate_(bitrate),
127 playback_rate_(playback_rate),
128 media_log_(media_log) {
129
130 // Set the initial capacity of |buffer_| based on |bitrate_| and
131 // |playback_rate_|.
132 UpdateBufferWindow();
133 }
134
135 BufferedResourceLoader::~BufferedResourceLoader() {}
136
137 void BufferedResourceLoader::Start(
138 const StartCB& start_cb,
139 const LoadingStateChangedCB& loading_cb,
140 const ProgressCB& progress_cb,
141 WebFrame* frame) {
142 // Make sure we have not started.
143 DCHECK(start_cb_.is_null());
144 DCHECK(loading_cb_.is_null());
145 DCHECK(progress_cb_.is_null());
146 DCHECK(!start_cb.is_null());
147 DCHECK(!loading_cb.is_null());
148 DCHECK(!progress_cb.is_null());
149 CHECK(frame);
150
151 start_cb_ = start_cb;
152 loading_cb_ = loading_cb;
153 progress_cb_ = progress_cb;
154
155 if (first_byte_position_ != kPositionNotSpecified) {
156 // TODO(hclam): server may not support range request so |offset_| may not
157 // equal to |first_byte_position_|.
158 offset_ = first_byte_position_;
159 }
160
161 // Prepare the request.
162 WebURLRequest request(url_);
163 request.setTargetType(WebURLRequest::TargetIsMedia);
164
165 if (IsRangeRequest()) {
166 request.setHTTPHeaderField(
167 WebString::fromUTF8(net::HttpRequestHeaders::kRange),
168 WebString::fromUTF8(GenerateHeaders(first_byte_position_,
169 last_byte_position_)));
170 }
171
172 frame->setReferrerForRequest(request, WebKit::WebURL());
173
174 // Disable compression, compression for audio/video doesn't make sense...
175 request.setHTTPHeaderField(
176 WebString::fromUTF8(net::HttpRequestHeaders::kAcceptEncoding),
177 WebString::fromUTF8("identity;q=1, *;q=0"));
178
179 // Check for our test WebURLLoader.
180 scoped_ptr<WebURLLoader> loader;
181 if (test_loader_) {
182 loader = test_loader_.Pass();
183 } else {
184 WebURLLoaderOptions options;
185 if (cors_mode_ == kUnspecified) {
186 options.allowCredentials = true;
187 options.crossOriginRequestPolicy =
188 WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
189 } else {
190 options.exposeAllResponseHeaders = true;
191 options.crossOriginRequestPolicy =
192 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
193 if (cors_mode_ == kUseCredentials)
194 options.allowCredentials = true;
195 }
196 loader.reset(frame->createAssociatedURLLoader(options));
197 }
198
199 // Start the resource loading.
200 loader->loadAsynchronously(request, this);
201 active_loader_.reset(new ActiveLoader(loader.Pass()));
202 loading_cb_.Run(kLoading);
203 }
204
205 void BufferedResourceLoader::Stop() {
206 // Reset callbacks.
207 start_cb_.Reset();
208 loading_cb_.Reset();
209 progress_cb_.Reset();
210 read_cb_.Reset();
211
212 // Cancel and reset any active loaders.
213 active_loader_.reset();
214 }
215
216 void BufferedResourceLoader::Read(
217 int64 position,
218 int read_size,
219 uint8* buffer,
220 const ReadCB& read_cb) {
221 DCHECK(start_cb_.is_null());
222 DCHECK(read_cb_.is_null());
223 DCHECK(!read_cb.is_null());
224 DCHECK(buffer);
225 DCHECK_GT(read_size, 0);
226
227 // Save the parameter of reading.
228 read_cb_ = read_cb;
229 read_position_ = position;
230 read_size_ = read_size;
231 read_buffer_ = buffer;
232
233 // Reads should immediately fail if the loader also failed.
234 if (loader_failed_) {
235 DoneRead(kFailed, 0);
236 return;
237 }
238
239 // If we're attempting to read past the end of the file, return a zero
240 // indicating EOF.
241 //
242 // This can happen with callees that read in fixed-sized amounts for parsing
243 // or at the end of chunked 200 responses when we discover the actual length
244 // of the file.
245 if (instance_size_ != kPositionNotSpecified &&
246 instance_size_ <= read_position_) {
247 DVLOG(1) << "Appear to have seeked beyond EOS; returning 0.";
248 DoneRead(kOk, 0);
249 return;
250 }
251
252 // Make sure |offset_| and |read_position_| does not differ by a large
253 // amount.
254 if (read_position_ > offset_ + kint32max ||
255 read_position_ < offset_ + kint32min) {
256 DoneRead(kCacheMiss, 0);
257 return;
258 }
259
260 // Make sure |read_size_| is not too large for the buffer to ever be able to
261 // fulfill the read request.
262 if (read_size_ > kMaxBufferCapacity) {
263 DoneRead(kFailed, 0);
264 return;
265 }
266
267 // Prepare the parameters.
268 first_offset_ = read_position_ - offset_;
269 last_offset_ = first_offset_ + read_size_;
270
271 // If we can serve the request now, do the actual read.
272 if (CanFulfillRead()) {
273 ReadInternal();
274 UpdateDeferBehavior();
275 return;
276 }
277
278 // If we expect the read request to be fulfilled later, expand capacity as
279 // necessary and disable deferring.
280 if (WillFulfillRead()) {
281 // Advance offset as much as possible to create additional capacity.
282 int advance = std::min(first_offset_, buffer_.forward_bytes());
283 bool ret = buffer_.Seek(advance);
284 DCHECK(ret);
285
286 offset_ += advance;
287 first_offset_ -= advance;
288 last_offset_ -= advance;
289
290 // Expand capacity to accomodate a read that extends past the normal
291 // capacity.
292 //
293 // This can happen when reading in a large seek index or when the
294 // first byte of a read request falls within kForwardWaitThreshold.
295 if (last_offset_ > buffer_.forward_capacity()) {
296 saved_forward_capacity_ = buffer_.forward_capacity();
297 buffer_.set_forward_capacity(last_offset_);
298 }
299
300 // Make sure we stop deferring now that there's additional capacity.
301 DCHECK(!ShouldDefer())
302 << "Capacity was not adjusted properly to prevent deferring.";
303 UpdateDeferBehavior();
304
305 return;
306 }
307
308 // Make a callback to report failure.
309 DoneRead(kCacheMiss, 0);
310 }
311
312 int64 BufferedResourceLoader::content_length() {
313 return content_length_;
314 }
315
316 int64 BufferedResourceLoader::instance_size() {
317 return instance_size_;
318 }
319
320 bool BufferedResourceLoader::range_supported() {
321 return range_supported_;
322 }
323
324 /////////////////////////////////////////////////////////////////////////////
325 // WebKit::WebURLLoaderClient implementation.
326 void BufferedResourceLoader::willSendRequest(
327 WebURLLoader* loader,
328 WebURLRequest& newRequest,
329 const WebURLResponse& redirectResponse) {
330
331 // The load may have been stopped and |start_cb| is destroyed.
332 // In this case we shouldn't do anything.
333 if (start_cb_.is_null()) {
334 // Set the url in the request to an invalid value (empty url).
335 newRequest.setURL(WebKit::WebURL());
336 return;
337 }
338
339 // Only allow |single_origin_| if we haven't seen a different origin yet.
340 if (single_origin_)
341 single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin();
342
343 url_ = newRequest.url();
344 }
345
346 void BufferedResourceLoader::didSendData(
347 WebURLLoader* loader,
348 unsigned long long bytes_sent,
349 unsigned long long total_bytes_to_be_sent) {
350 NOTIMPLEMENTED();
351 }
352
353 void BufferedResourceLoader::didReceiveResponse(
354 WebURLLoader* loader,
355 const WebURLResponse& response) {
356 DVLOG(1) << "didReceiveResponse: HTTP/"
357 << (response.httpVersion() == WebURLResponse::HTTP_0_9 ? "0.9" :
358 response.httpVersion() == WebURLResponse::HTTP_1_0 ? "1.0" :
359 response.httpVersion() == WebURLResponse::HTTP_1_1 ? "1.1" :
360 "Unknown")
361 << " " << response.httpStatusCode();
362 DCHECK(active_loader_.get());
363
364 // The loader may have been stopped and |start_cb| is destroyed.
365 // In this case we shouldn't do anything.
366 if (start_cb_.is_null())
367 return;
368
369 uint32 reasons = GetReasonsForUncacheability(response);
370 might_be_reused_from_cache_in_future_ = reasons == 0;
371 UMA_HISTOGRAM_BOOLEAN("Media.CacheUseful", reasons == 0);
372 int shift = 0;
373 int max_enum = base::bits::Log2Ceiling(kMaxReason);
374 while (reasons) {
375 DCHECK_LT(shift, max_enum); // Sanity check.
376 if (reasons & 0x1)
377 UMA_HISTOGRAM_ENUMERATION("Media.UncacheableReason", shift, max_enum);
378 reasons >>= 1;
379 ++shift;
380 }
381
382 // Expected content length can be |kPositionNotSpecified|, in that case
383 // |content_length_| is not specified and this is a streaming response.
384 content_length_ = response.expectedContentLength();
385
386 // We make a strong assumption that when we reach here we have either
387 // received a response from HTTP/HTTPS protocol or the request was
388 // successful (in particular range request). So we only verify the partial
389 // response for HTTP and HTTPS protocol.
390 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) {
391 bool partial_response = (response.httpStatusCode() == kHttpPartialContent);
392 bool ok_response = (response.httpStatusCode() == kHttpOK);
393
394 if (IsRangeRequest()) {
395 // Check to see whether the server supports byte ranges.
396 std::string accept_ranges =
397 response.httpHeaderField("Accept-Ranges").utf8();
398 range_supported_ = (accept_ranges.find("bytes") != std::string::npos);
399
400 // If we have verified the partial response and it is correct, we will
401 // return kOk. It's also possible for a server to support range requests
402 // without advertising "Accept-Ranges: bytes".
403 if (partial_response && VerifyPartialResponse(response)) {
404 range_supported_ = true;
405 } else if (ok_response && first_byte_position_ == 0 &&
406 last_byte_position_ == kPositionNotSpecified) {
407 // We accept a 200 response for a Range:0- request, trusting the
408 // Accept-Ranges header, because Apache thinks that's a reasonable thing
409 // to return.
410 instance_size_ = content_length_;
411 } else {
412 DoneStart(kFailed);
413 return;
414 }
415 } else {
416 instance_size_ = content_length_;
417 if (response.httpStatusCode() != kHttpOK) {
418 // We didn't request a range but server didn't reply with "200 OK".
419 DoneStart(kFailed);
420 return;
421 }
422 }
423
424 } else {
425 CHECK_EQ(instance_size_, kPositionNotSpecified);
426 if (content_length_ != kPositionNotSpecified) {
427 if (first_byte_position_ == kPositionNotSpecified)
428 instance_size_ = content_length_;
429 else if (last_byte_position_ == kPositionNotSpecified)
430 instance_size_ = content_length_ + first_byte_position_;
431 }
432 }
433
434 // Calls with a successful response.
435 DoneStart(kOk);
436 }
437
438 void BufferedResourceLoader::didReceiveData(
439 WebURLLoader* loader,
440 const char* data,
441 int data_length,
442 int encoded_data_length) {
443 DVLOG(1) << "didReceiveData: " << data_length << " bytes";
444 DCHECK(active_loader_.get());
445 DCHECK_GT(data_length, 0);
446
447 buffer_.Append(reinterpret_cast<const uint8*>(data), data_length);
448
449 // If there is an active read request, try to fulfill the request.
450 if (HasPendingRead() && CanFulfillRead())
451 ReadInternal();
452
453 // At last see if the buffer is full and we need to defer the downloading.
454 UpdateDeferBehavior();
455
456 // Consume excess bytes from our in-memory buffer if necessary.
457 if (buffer_.forward_bytes() > buffer_.forward_capacity()) {
458 int excess = buffer_.forward_bytes() - buffer_.forward_capacity();
459 bool success = buffer_.Seek(excess);
460 DCHECK(success);
461 offset_ += first_offset_ + excess;
462 }
463
464 // Notify latest progress and buffered offset.
465 progress_cb_.Run(offset_ + buffer_.forward_bytes() - 1);
466 Log();
467 }
468
469 void BufferedResourceLoader::didDownloadData(
470 WebKit::WebURLLoader* loader,
471 int dataLength) {
472 NOTIMPLEMENTED();
473 }
474
475 void BufferedResourceLoader::didReceiveCachedMetadata(
476 WebURLLoader* loader,
477 const char* data,
478 int data_length) {
479 NOTIMPLEMENTED();
480 }
481
482 void BufferedResourceLoader::didFinishLoading(
483 WebURLLoader* loader,
484 double finishTime) {
485 DVLOG(1) << "didFinishLoading";
486 DCHECK(active_loader_.get());
487
488 // We're done with the loader.
489 active_loader_.reset();
490 loading_cb_.Run(kLoadingFinished);
491
492 // If we didn't know the |instance_size_| we do now.
493 if (instance_size_ == kPositionNotSpecified) {
494 instance_size_ = offset_ + buffer_.forward_bytes();
495 }
496
497 // If there is a start callback, run it.
498 if (!start_cb_.is_null()) {
499 DCHECK(read_cb_.is_null())
500 << "Shouldn't have a read callback during start";
501 DoneStart(kOk);
502 return;
503 }
504
505 // Don't leave read callbacks hanging around.
506 if (HasPendingRead()) {
507 // Try to fulfill with what is in the buffer.
508 if (CanFulfillRead())
509 ReadInternal();
510 else
511 DoneRead(kCacheMiss, 0);
512 }
513 }
514
515 void BufferedResourceLoader::didFail(
516 WebURLLoader* loader,
517 const WebURLError& error) {
518 DVLOG(1) << "didFail: reason=" << error.reason
519 << ", isCancellation=" << error.isCancellation
520 << ", domain=" << error.domain.utf8().data()
521 << ", localizedDescription="
522 << error.localizedDescription.utf8().data();
523 DCHECK(active_loader_.get());
524
525 // We don't need to continue loading after failure.
526 //
527 // Keep it alive until we exit this method so that |error| remains valid.
528 scoped_ptr<ActiveLoader> active_loader = active_loader_.Pass();
529 loader_failed_ = true;
530 loading_cb_.Run(kLoadingFailed);
531
532 // Don't leave start callbacks hanging around.
533 if (!start_cb_.is_null()) {
534 DCHECK(read_cb_.is_null())
535 << "Shouldn't have a read callback during start";
536 DoneStart(kFailed);
537 return;
538 }
539
540 // Don't leave read callbacks hanging around.
541 if (HasPendingRead()) {
542 DoneRead(kFailed, 0);
543 }
544 }
545
546 bool BufferedResourceLoader::HasSingleOrigin() const {
547 DCHECK(start_cb_.is_null())
548 << "Start() must complete before calling HasSingleOrigin()";
549 return single_origin_;
550 }
551
552 bool BufferedResourceLoader::DidPassCORSAccessCheck() const {
553 DCHECK(start_cb_.is_null())
554 << "Start() must complete before calling DidPassCORSAccessCheck()";
555 return !loader_failed_ && cors_mode_ != kUnspecified;
556 }
557
558 void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) {
559 if (!might_be_reused_from_cache_in_future_ && strategy == kNeverDefer)
560 strategy = kCapacityDefer;
561 defer_strategy_ = strategy;
562 UpdateDeferBehavior();
563 }
564
565 void BufferedResourceLoader::SetPlaybackRate(float playback_rate) {
566 playback_rate_ = playback_rate;
567
568 // This is a pause so don't bother updating the buffer window as we'll likely
569 // get unpaused in the future.
570 if (playback_rate_ == 0.0)
571 return;
572
573 UpdateBufferWindow();
574 }
575
576 void BufferedResourceLoader::SetBitrate(int bitrate) {
577 DCHECK(bitrate >= 0);
578 bitrate_ = bitrate;
579 UpdateBufferWindow();
580 }
581
582 /////////////////////////////////////////////////////////////////////////////
583 // Helper methods.
584
585 void BufferedResourceLoader::UpdateBufferWindow() {
586 int backward_capacity;
587 int forward_capacity;
588 ComputeTargetBufferWindow(
589 playback_rate_, bitrate_, &backward_capacity, &forward_capacity);
590
591 // This does not evict data from the buffer if the new capacities are less
592 // than the current capacities; the new limits will be enforced after the
593 // existing excess buffered data is consumed.
594 buffer_.set_backward_capacity(backward_capacity);
595 buffer_.set_forward_capacity(forward_capacity);
596 }
597
598 void BufferedResourceLoader::UpdateDeferBehavior() {
599 if (!active_loader_)
600 return;
601
602 SetDeferred(ShouldDefer());
603 }
604
605 void BufferedResourceLoader::SetDeferred(bool deferred) {
606 if (active_loader_->deferred() == deferred)
607 return;
608
609 active_loader_->SetDeferred(deferred);
610 loading_cb_.Run(deferred ? kLoadingDeferred : kLoading);
611 }
612
613 bool BufferedResourceLoader::ShouldDefer() const {
614 switch(defer_strategy_) {
615 case kNeverDefer:
616 return false;
617
618 case kReadThenDefer:
619 DCHECK(read_cb_.is_null() || last_offset_ > buffer_.forward_bytes())
620 << "We shouldn't stop deferring if we can fulfill the read";
621 return read_cb_.is_null();
622
623 case kCapacityDefer:
624 return buffer_.forward_bytes() >= buffer_.forward_capacity();
625 }
626 NOTREACHED();
627 return false;
628 }
629
630 bool BufferedResourceLoader::CanFulfillRead() const {
631 // If we are reading too far in the backward direction.
632 if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0)
633 return false;
634
635 // If the start offset is too far ahead.
636 if (first_offset_ >= buffer_.forward_bytes())
637 return false;
638
639 // At the point, we verified that first byte requested is within the buffer.
640 // If the request has completed, then just returns with what we have now.
641 if (!active_loader_)
642 return true;
643
644 // If the resource request is still active, make sure the whole requested
645 // range is covered.
646 if (last_offset_ > buffer_.forward_bytes())
647 return false;
648
649 return true;
650 }
651
652 bool BufferedResourceLoader::WillFulfillRead() const {
653 // Trying to read too far behind.
654 if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0)
655 return false;
656
657 // Trying to read too far ahead.
658 if ((first_offset_ - buffer_.forward_bytes()) >= kForwardWaitThreshold)
659 return false;
660
661 // The resource request has completed, there's no way we can fulfill the
662 // read request.
663 if (!active_loader_)
664 return false;
665
666 return true;
667 }
668
669 void BufferedResourceLoader::ReadInternal() {
670 // Seek to the first byte requested.
671 bool ret = buffer_.Seek(first_offset_);
672 DCHECK(ret);
673
674 // Then do the read.
675 int read = buffer_.Read(read_buffer_, read_size_);
676 offset_ += first_offset_ + read;
677
678 // And report with what we have read.
679 DoneRead(kOk, read);
680 }
681
682 int64 BufferedResourceLoader::first_byte_position() const {
683 return first_byte_position_;
684 }
685
686 // static
687 bool BufferedResourceLoader::ParseContentRange(
688 const std::string& content_range_str, int64* first_byte_position,
689 int64* last_byte_position, int64* instance_size) {
690 const std::string kUpThroughBytesUnit = "bytes ";
691 if (content_range_str.find(kUpThroughBytesUnit) != 0)
692 return false;
693 std::string range_spec =
694 content_range_str.substr(kUpThroughBytesUnit.length());
695 size_t dash_offset = range_spec.find("-");
696 size_t slash_offset = range_spec.find("/");
697
698 if (dash_offset == std::string::npos || slash_offset == std::string::npos ||
699 slash_offset < dash_offset || slash_offset + 1 == range_spec.length()) {
700 return false;
701 }
702 if (!base::StringToInt64(range_spec.substr(0, dash_offset),
703 first_byte_position) ||
704 !base::StringToInt64(range_spec.substr(dash_offset + 1,
705 slash_offset - dash_offset - 1),
706 last_byte_position)) {
707 return false;
708 }
709 if (slash_offset == range_spec.length() - 2 &&
710 range_spec[slash_offset + 1] == '*') {
711 *instance_size = kPositionNotSpecified;
712 } else {
713 if (!base::StringToInt64(range_spec.substr(slash_offset + 1),
714 instance_size)) {
715 return false;
716 }
717 }
718 if (*last_byte_position < *first_byte_position ||
719 (*instance_size != kPositionNotSpecified &&
720 *last_byte_position >= *instance_size)) {
721 return false;
722 }
723
724 return true;
725 }
726
727 bool BufferedResourceLoader::VerifyPartialResponse(
728 const WebURLResponse& response) {
729 int64 first_byte_position, last_byte_position, instance_size;
730 if (!ParseContentRange(response.httpHeaderField("Content-Range").utf8(),
731 &first_byte_position, &last_byte_position,
732 &instance_size)) {
733 return false;
734 }
735
736 if (instance_size != kPositionNotSpecified) {
737 instance_size_ = instance_size;
738 }
739
740 if (first_byte_position_ != kPositionNotSpecified &&
741 first_byte_position_ != first_byte_position) {
742 return false;
743 }
744
745 // TODO(hclam): I should also check |last_byte_position|, but since
746 // we will never make such a request that it is ok to leave it unimplemented.
747 return true;
748 }
749
750 std::string BufferedResourceLoader::GenerateHeaders(
751 int64 first_byte_position,
752 int64 last_byte_position) {
753 // Construct the value for the range header.
754 std::string header;
755 if (first_byte_position > kPositionNotSpecified &&
756 last_byte_position > kPositionNotSpecified) {
757 if (first_byte_position <= last_byte_position) {
758 header = base::StringPrintf("bytes=%" PRId64 "-%" PRId64,
759 first_byte_position,
760 last_byte_position);
761 }
762 } else if (first_byte_position > kPositionNotSpecified) {
763 header = base::StringPrintf("bytes=%" PRId64 "-",
764 first_byte_position);
765 } else if (last_byte_position > kPositionNotSpecified) {
766 NOTIMPLEMENTED() << "Suffix range not implemented";
767 }
768 return header;
769 }
770
771 void BufferedResourceLoader::DoneRead(Status status, int bytes_read) {
772 if (saved_forward_capacity_) {
773 buffer_.set_forward_capacity(saved_forward_capacity_);
774 saved_forward_capacity_ = 0;
775 }
776 read_position_ = 0;
777 read_size_ = 0;
778 read_buffer_ = NULL;
779 first_offset_ = 0;
780 last_offset_ = 0;
781 Log();
782
783 base::ResetAndReturn(&read_cb_).Run(status, bytes_read);
784 }
785
786
787 void BufferedResourceLoader::DoneStart(Status status) {
788 base::ResetAndReturn(&start_cb_).Run(status);
789 }
790
791 bool BufferedResourceLoader::IsRangeRequest() const {
792 return first_byte_position_ != kPositionNotSpecified;
793 }
794
795 void BufferedResourceLoader::Log() {
796 media_log_->AddEvent(
797 media_log_->CreateBufferedExtentsChangedEvent(
798 offset_ - buffer_.backward_bytes(),
799 offset_,
800 offset_ + buffer_.forward_bytes()));
801 }
802
803 } // namespace webkit_media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698