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