Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / buffered_resource_loader.cc
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 "content/renderer/media/buffered_resource_loader.h"
6
7 #include "base/bits.h"
8 #include "base/callback_helpers.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "content/public/common/url_constants.h"
13 #include "content/renderer/media/cache_util.h"
14 #include "media/base/media_log.h"
15 #include "net/http/http_byte_range.h"
16 #include "net/http/http_request_headers.h"
17 #include "third_party/WebKit/public/platform/WebString.h"
18 #include "third_party/WebKit/public/platform/WebURLError.h"
19 #include "third_party/WebKit/public/platform/WebURLResponse.h"
20 #include "third_party/WebKit/public/web/WebKit.h"
21 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
22
23 using blink::WebFrame;
24 using blink::WebString;
25 using blink::WebURLError;
26 using blink::WebURLLoader;
27 using blink::WebURLLoaderOptions;
28 using blink::WebURLRequest;
29 using blink::WebURLResponse;
30
31 namespace content {
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(net::HttpByteRange::Bounded(
169             first_byte_position_, last_byte_position_).GetHeaderValue()));
170   }
171
172   frame->setReferrerForRequest(request, blink::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       // The author header set is empty, no preflight should go ahead.
192       options.preflightPolicy = WebURLLoaderOptions::PreventPreflight;
193       options.crossOriginRequestPolicy =
194           WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
195       if (cors_mode_ == kUseCredentials)
196         options.allowCredentials = true;
197     }
198     loader.reset(frame->createAssociatedURLLoader(options));
199   }
200
201   // Start the resource loading.
202   loader->loadAsynchronously(request, this);
203   active_loader_.reset(new ActiveLoader(loader.Pass()));
204   loading_cb_.Run(kLoading);
205 }
206
207 void BufferedResourceLoader::Stop() {
208   // Reset callbacks.
209   start_cb_.Reset();
210   loading_cb_.Reset();
211   progress_cb_.Reset();
212   read_cb_.Reset();
213
214   // Cancel and reset any active loaders.
215   active_loader_.reset();
216 }
217
218 void BufferedResourceLoader::Read(
219     int64 position,
220     int read_size,
221     uint8* buffer,
222     const ReadCB& read_cb) {
223   DCHECK(start_cb_.is_null());
224   DCHECK(read_cb_.is_null());
225   DCHECK(!read_cb.is_null());
226   DCHECK(buffer);
227   DCHECK_GT(read_size, 0);
228
229   // Save the parameter of reading.
230   read_cb_ = read_cb;
231   read_position_ = position;
232   read_size_ = read_size;
233   read_buffer_ = buffer;
234
235   // Reads should immediately fail if the loader also failed.
236   if (loader_failed_) {
237     DoneRead(kFailed, 0);
238     return;
239   }
240
241   // If we're attempting to read past the end of the file, return a zero
242   // indicating EOF.
243   //
244   // This can happen with callees that read in fixed-sized amounts for parsing
245   // or at the end of chunked 200 responses when we discover the actual length
246   // of the file.
247   if (instance_size_ != kPositionNotSpecified &&
248       instance_size_ <= read_position_) {
249     DVLOG(1) << "Appear to have seeked beyond EOS; returning 0.";
250     DoneRead(kOk, 0);
251     return;
252   }
253
254   // Make sure |offset_| and |read_position_| does not differ by a large
255   // amount.
256   if (read_position_ > offset_ + kint32max ||
257       read_position_ < offset_ + kint32min) {
258     DoneRead(kCacheMiss, 0);
259     return;
260   }
261
262   // Make sure |read_size_| is not too large for the buffer to ever be able to
263   // fulfill the read request.
264   if (read_size_ > kMaxBufferCapacity) {
265     DoneRead(kFailed, 0);
266     return;
267   }
268
269   // Prepare the parameters.
270   first_offset_ = read_position_ - offset_;
271   last_offset_ = first_offset_ + read_size_;
272
273   // If we can serve the request now, do the actual read.
274   if (CanFulfillRead()) {
275     ReadInternal();
276     UpdateDeferBehavior();
277     return;
278   }
279
280   // If we expect the read request to be fulfilled later, expand capacity as
281   // necessary and disable deferring.
282   if (WillFulfillRead()) {
283     // Advance offset as much as possible to create additional capacity.
284     int advance = std::min(first_offset_, buffer_.forward_bytes());
285     bool ret = buffer_.Seek(advance);
286     DCHECK(ret);
287
288     offset_ += advance;
289     first_offset_ -= advance;
290     last_offset_ -= advance;
291
292     // Expand capacity to accomodate a read that extends past the normal
293     // capacity.
294     //
295     // This can happen when reading in a large seek index or when the
296     // first byte of a read request falls within kForwardWaitThreshold.
297     if (last_offset_ > buffer_.forward_capacity()) {
298       saved_forward_capacity_ = buffer_.forward_capacity();
299       buffer_.set_forward_capacity(last_offset_);
300     }
301
302     // Make sure we stop deferring now that there's additional capacity.
303     DCHECK(!ShouldDefer())
304         << "Capacity was not adjusted properly to prevent deferring.";
305     UpdateDeferBehavior();
306
307     return;
308   }
309
310   // Make a callback to report failure.
311   DoneRead(kCacheMiss, 0);
312 }
313
314 int64 BufferedResourceLoader::content_length() {
315   return content_length_;
316 }
317
318 int64 BufferedResourceLoader::instance_size() {
319   return instance_size_;
320 }
321
322 bool BufferedResourceLoader::range_supported() {
323   return range_supported_;
324 }
325
326 /////////////////////////////////////////////////////////////////////////////
327 // blink::WebURLLoaderClient implementation.
328 void BufferedResourceLoader::willSendRequest(
329     WebURLLoader* loader,
330     WebURLRequest& newRequest,
331     const WebURLResponse& redirectResponse) {
332
333   // The load may have been stopped and |start_cb| is destroyed.
334   // In this case we shouldn't do anything.
335   if (start_cb_.is_null()) {
336     // Set the url in the request to an invalid value (empty url).
337     newRequest.setURL(blink::WebURL());
338     return;
339   }
340
341   // Only allow |single_origin_| if we haven't seen a different origin yet.
342   if (single_origin_)
343     single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin();
344
345   url_ = newRequest.url();
346 }
347
348 void BufferedResourceLoader::didSendData(
349     WebURLLoader* loader,
350     unsigned long long bytes_sent,
351     unsigned long long total_bytes_to_be_sent) {
352   NOTIMPLEMENTED();
353 }
354
355 void BufferedResourceLoader::didReceiveResponse(
356     WebURLLoader* loader,
357     const WebURLResponse& response) {
358   DVLOG(1) << "didReceiveResponse: HTTP/"
359            << (response.httpVersion() == WebURLResponse::HTTP_0_9 ? "0.9" :
360                response.httpVersion() == WebURLResponse::HTTP_1_0 ? "1.0" :
361                response.httpVersion() == WebURLResponse::HTTP_1_1 ? "1.1" :
362                "Unknown")
363            << " " << response.httpStatusCode();
364   DCHECK(active_loader_.get());
365
366   // The loader may have been stopped and |start_cb| is destroyed.
367   // In this case we shouldn't do anything.
368   if (start_cb_.is_null())
369     return;
370
371   uint32 reasons = GetReasonsForUncacheability(response);
372   might_be_reused_from_cache_in_future_ = reasons == 0;
373   UMA_HISTOGRAM_BOOLEAN("Media.CacheUseful", reasons == 0);
374   int shift = 0;
375   int max_enum = base::bits::Log2Ceiling(kMaxReason);
376   while (reasons) {
377     DCHECK_LT(shift, max_enum);  // Sanity check.
378     if (reasons & 0x1)
379       UMA_HISTOGRAM_ENUMERATION("Media.UncacheableReason", shift, max_enum);
380     reasons >>= 1;
381     ++shift;
382   }
383
384   // Expected content length can be |kPositionNotSpecified|, in that case
385   // |content_length_| is not specified and this is a streaming response.
386   content_length_ = response.expectedContentLength();
387
388   // We make a strong assumption that when we reach here we have either
389   // received a response from HTTP/HTTPS protocol or the request was
390   // successful (in particular range request). So we only verify the partial
391   // response for HTTP and HTTPS protocol.
392   if (url_.SchemeIs(url::kHttpScheme) || url_.SchemeIs(url::kHttpsScheme)) {
393     bool partial_response = (response.httpStatusCode() == kHttpPartialContent);
394     bool ok_response = (response.httpStatusCode() == kHttpOK);
395
396     if (IsRangeRequest()) {
397       // Check to see whether the server supports byte ranges.
398       std::string accept_ranges =
399           response.httpHeaderField("Accept-Ranges").utf8();
400       range_supported_ = (accept_ranges.find("bytes") != std::string::npos);
401
402       // If we have verified the partial response and it is correct, we will
403       // return kOk. It's also possible for a server to support range requests
404       // without advertising "Accept-Ranges: bytes".
405       if (partial_response && VerifyPartialResponse(response)) {
406         range_supported_ = true;
407       } else if (ok_response && first_byte_position_ == 0 &&
408                  last_byte_position_ == kPositionNotSpecified) {
409         // We accept a 200 response for a Range:0- request, trusting the
410         // Accept-Ranges header, because Apache thinks that's a reasonable thing
411         // to return.
412         instance_size_ = content_length_;
413       } else {
414         DoneStart(kFailed);
415         return;
416       }
417     } else {
418       instance_size_ = content_length_;
419       if (response.httpStatusCode() != kHttpOK) {
420         // We didn't request a range but server didn't reply with "200 OK".
421         DoneStart(kFailed);
422         return;
423       }
424     }
425
426   } else {
427     CHECK_EQ(instance_size_, kPositionNotSpecified);
428     if (content_length_ != kPositionNotSpecified) {
429       if (first_byte_position_ == kPositionNotSpecified)
430         instance_size_ = content_length_;
431       else if (last_byte_position_ == kPositionNotSpecified)
432         instance_size_ = content_length_ + first_byte_position_;
433     }
434   }
435
436   // Calls with a successful response.
437   DoneStart(kOk);
438 }
439
440 void BufferedResourceLoader::didReceiveData(
441     WebURLLoader* loader,
442     const char* data,
443     int data_length,
444     int encoded_data_length) {
445   DVLOG(1) << "didReceiveData: " << data_length << " bytes";
446   DCHECK(active_loader_.get());
447   DCHECK_GT(data_length, 0);
448
449   buffer_.Append(reinterpret_cast<const uint8*>(data), data_length);
450
451   // If there is an active read request, try to fulfill the request.
452   if (HasPendingRead() && CanFulfillRead())
453     ReadInternal();
454
455   // At last see if the buffer is full and we need to defer the downloading.
456   UpdateDeferBehavior();
457
458   // Consume excess bytes from our in-memory buffer if necessary.
459   if (buffer_.forward_bytes() > buffer_.forward_capacity()) {
460     int excess = buffer_.forward_bytes() - buffer_.forward_capacity();
461     bool success = buffer_.Seek(excess);
462     DCHECK(success);
463     offset_ += first_offset_ + excess;
464   }
465
466   // Notify latest progress and buffered offset.
467   progress_cb_.Run(offset_ + buffer_.forward_bytes() - 1);
468   Log();
469 }
470
471 void BufferedResourceLoader::didDownloadData(
472     blink::WebURLLoader* loader,
473     int dataLength,
474     int encoded_data_length) {
475   NOTIMPLEMENTED();
476 }
477
478 void BufferedResourceLoader::didReceiveCachedMetadata(
479     WebURLLoader* loader,
480     const char* data,
481     int data_length) {
482   NOTIMPLEMENTED();
483 }
484
485 void BufferedResourceLoader::didFinishLoading(
486     WebURLLoader* loader,
487     double finishTime,
488     int64_t total_encoded_data_length) {
489   DVLOG(1) << "didFinishLoading";
490   DCHECK(active_loader_.get());
491
492   // We're done with the loader.
493   active_loader_.reset();
494   loading_cb_.Run(kLoadingFinished);
495
496   // If we didn't know the |instance_size_| we do now.
497   if (instance_size_ == kPositionNotSpecified) {
498     instance_size_ = offset_ + buffer_.forward_bytes();
499   }
500
501   // If there is a start callback, run it.
502   if (!start_cb_.is_null()) {
503     DCHECK(read_cb_.is_null())
504         << "Shouldn't have a read callback during start";
505     DoneStart(kOk);
506     return;
507   }
508
509   // Don't leave read callbacks hanging around.
510   if (HasPendingRead()) {
511     // Try to fulfill with what is in the buffer.
512     if (CanFulfillRead())
513       ReadInternal();
514     else
515       DoneRead(kCacheMiss, 0);
516   }
517 }
518
519 void BufferedResourceLoader::didFail(
520     WebURLLoader* loader,
521     const WebURLError& error) {
522   DVLOG(1) << "didFail: reason=" << error.reason
523            << ", isCancellation=" << error.isCancellation
524            << ", domain=" << error.domain.utf8().data()
525            << ", localizedDescription="
526            << error.localizedDescription.utf8().data();
527   DCHECK(active_loader_.get());
528
529   // We don't need to continue loading after failure.
530   //
531   // Keep it alive until we exit this method so that |error| remains valid.
532   scoped_ptr<ActiveLoader> active_loader = active_loader_.Pass();
533   loader_failed_ = true;
534   loading_cb_.Run(kLoadingFailed);
535
536   // Don't leave start callbacks hanging around.
537   if (!start_cb_.is_null()) {
538     DCHECK(read_cb_.is_null())
539         << "Shouldn't have a read callback during start";
540     DoneStart(kFailed);
541     return;
542   }
543
544   // Don't leave read callbacks hanging around.
545   if (HasPendingRead()) {
546     DoneRead(kFailed, 0);
547   }
548 }
549
550 bool BufferedResourceLoader::HasSingleOrigin() const {
551   DCHECK(start_cb_.is_null())
552       << "Start() must complete before calling HasSingleOrigin()";
553   return single_origin_;
554 }
555
556 bool BufferedResourceLoader::DidPassCORSAccessCheck() const {
557   DCHECK(start_cb_.is_null())
558       << "Start() must complete before calling DidPassCORSAccessCheck()";
559   return !loader_failed_ && cors_mode_ != kUnspecified;
560 }
561
562 void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) {
563   if (!might_be_reused_from_cache_in_future_ && strategy == kNeverDefer)
564     strategy = kCapacityDefer;
565   defer_strategy_ = strategy;
566   UpdateDeferBehavior();
567 }
568
569 void BufferedResourceLoader::SetPlaybackRate(float playback_rate) {
570   playback_rate_ = playback_rate;
571
572   // This is a pause so don't bother updating the buffer window as we'll likely
573   // get unpaused in the future.
574   if (playback_rate_ == 0.0)
575     return;
576
577   UpdateBufferWindow();
578 }
579
580 void BufferedResourceLoader::SetBitrate(int bitrate) {
581   DCHECK(bitrate >= 0);
582   bitrate_ = bitrate;
583   UpdateBufferWindow();
584 }
585
586 /////////////////////////////////////////////////////////////////////////////
587 // Helper methods.
588
589 void BufferedResourceLoader::UpdateBufferWindow() {
590   int backward_capacity;
591   int forward_capacity;
592   ComputeTargetBufferWindow(
593       playback_rate_, bitrate_, &backward_capacity, &forward_capacity);
594
595   // This does not evict data from the buffer if the new capacities are less
596   // than the current capacities; the new limits will be enforced after the
597   // existing excess buffered data is consumed.
598   buffer_.set_backward_capacity(backward_capacity);
599   buffer_.set_forward_capacity(forward_capacity);
600 }
601
602 void BufferedResourceLoader::UpdateDeferBehavior() {
603   if (!active_loader_)
604     return;
605
606   SetDeferred(ShouldDefer());
607 }
608
609 void BufferedResourceLoader::SetDeferred(bool deferred) {
610   if (active_loader_->deferred() == deferred)
611     return;
612
613   active_loader_->SetDeferred(deferred);
614   loading_cb_.Run(deferred ? kLoadingDeferred : kLoading);
615 }
616
617 bool BufferedResourceLoader::ShouldDefer() const {
618   switch(defer_strategy_) {
619     case kNeverDefer:
620       return false;
621
622     case kReadThenDefer:
623       DCHECK(read_cb_.is_null() || last_offset_ > buffer_.forward_bytes())
624           << "We shouldn't stop deferring if we can fulfill the read";
625       return read_cb_.is_null();
626
627     case kCapacityDefer:
628       return buffer_.forward_bytes() >= buffer_.forward_capacity();
629   }
630   NOTREACHED();
631   return false;
632 }
633
634 bool BufferedResourceLoader::CanFulfillRead() const {
635   // If we are reading too far in the backward direction.
636   if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0)
637     return false;
638
639   // If the start offset is too far ahead.
640   if (first_offset_ >= buffer_.forward_bytes())
641     return false;
642
643   // At the point, we verified that first byte requested is within the buffer.
644   // If the request has completed, then just returns with what we have now.
645   if (!active_loader_)
646     return true;
647
648   // If the resource request is still active, make sure the whole requested
649   // range is covered.
650   if (last_offset_ > buffer_.forward_bytes())
651     return false;
652
653   return true;
654 }
655
656 bool BufferedResourceLoader::WillFulfillRead() const {
657   // Trying to read too far behind.
658   if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0)
659     return false;
660
661   // Trying to read too far ahead.
662   if ((first_offset_ - buffer_.forward_bytes()) >= kForwardWaitThreshold)
663     return false;
664
665   // The resource request has completed, there's no way we can fulfill the
666   // read request.
667   if (!active_loader_)
668     return false;
669
670   return true;
671 }
672
673 void BufferedResourceLoader::ReadInternal() {
674   // Seek to the first byte requested.
675   bool ret = buffer_.Seek(first_offset_);
676   DCHECK(ret);
677
678   // Then do the read.
679   int read = buffer_.Read(read_buffer_, read_size_);
680   offset_ += first_offset_ + read;
681
682   // And report with what we have read.
683   DoneRead(kOk, read);
684 }
685
686 int64 BufferedResourceLoader::first_byte_position() const {
687   return first_byte_position_;
688 }
689
690 // static
691 bool BufferedResourceLoader::ParseContentRange(
692     const std::string& content_range_str, int64* first_byte_position,
693     int64* last_byte_position, int64* instance_size) {
694   const std::string kUpThroughBytesUnit = "bytes ";
695   if (content_range_str.find(kUpThroughBytesUnit) != 0)
696     return false;
697   std::string range_spec =
698       content_range_str.substr(kUpThroughBytesUnit.length());
699   size_t dash_offset = range_spec.find("-");
700   size_t slash_offset = range_spec.find("/");
701
702   if (dash_offset == std::string::npos || slash_offset == std::string::npos ||
703       slash_offset < dash_offset || slash_offset + 1 == range_spec.length()) {
704     return false;
705   }
706   if (!base::StringToInt64(range_spec.substr(0, dash_offset),
707                            first_byte_position) ||
708       !base::StringToInt64(range_spec.substr(dash_offset + 1,
709                                              slash_offset - dash_offset - 1),
710                            last_byte_position)) {
711     return false;
712   }
713   if (slash_offset == range_spec.length() - 2 &&
714       range_spec[slash_offset + 1] == '*') {
715     *instance_size = kPositionNotSpecified;
716   } else {
717     if (!base::StringToInt64(range_spec.substr(slash_offset + 1),
718                              instance_size)) {
719       return false;
720     }
721   }
722   if (*last_byte_position < *first_byte_position ||
723       (*instance_size != kPositionNotSpecified &&
724        *last_byte_position >= *instance_size)) {
725     return false;
726   }
727
728   return true;
729 }
730
731 bool BufferedResourceLoader::VerifyPartialResponse(
732     const WebURLResponse& response) {
733   int64 first_byte_position, last_byte_position, instance_size;
734   if (!ParseContentRange(response.httpHeaderField("Content-Range").utf8(),
735                          &first_byte_position, &last_byte_position,
736                          &instance_size)) {
737     return false;
738   }
739
740   if (instance_size != kPositionNotSpecified) {
741     instance_size_ = instance_size;
742   }
743
744   if (first_byte_position_ != kPositionNotSpecified &&
745       first_byte_position_ != first_byte_position) {
746     return false;
747   }
748
749   // TODO(hclam): I should also check |last_byte_position|, but since
750   // we will never make such a request that it is ok to leave it unimplemented.
751   return true;
752 }
753
754 void BufferedResourceLoader::DoneRead(Status status, int bytes_read) {
755   if (saved_forward_capacity_) {
756     buffer_.set_forward_capacity(saved_forward_capacity_);
757     saved_forward_capacity_ = 0;
758   }
759   read_position_ = 0;
760   read_size_ = 0;
761   read_buffer_ = NULL;
762   first_offset_ = 0;
763   last_offset_ = 0;
764   Log();
765
766   base::ResetAndReturn(&read_cb_).Run(status, bytes_read);
767 }
768
769
770 void BufferedResourceLoader::DoneStart(Status status) {
771   base::ResetAndReturn(&start_cb_).Run(status);
772 }
773
774 bool BufferedResourceLoader::IsRangeRequest() const {
775   return first_byte_position_ != kPositionNotSpecified;
776 }
777
778 void BufferedResourceLoader::Log() {
779   media_log_->AddEvent(
780       media_log_->CreateBufferedExtentsChangedEvent(
781           offset_ - buffer_.backward_bytes(),
782           offset_,
783           offset_ + buffer_.forward_bytes()));
784 }
785
786 }  // namespace content