Home | History | Annotate | Download | only in blink
      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 "media/blink/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 "media/base/media_log.h"
     13 #include "media/blink/cache_util.h"
     14 #include "net/http/http_byte_range.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 
     22 using blink::WebFrame;
     23 using blink::WebString;
     24 using blink::WebURLError;
     25 using blink::WebURLLoader;
     26 using blink::WebURLLoaderOptions;
     27 using blink::WebURLRequest;
     28 using blink::WebURLResponse;
     29 
     30 namespace media {
     31 
     32 static const int kHttpOK = 200;
     33 static const int kHttpPartialContent = 206;
     34 
     35 // Define the number of bytes in a megabyte.
     36 static const int kMegabyte = 1024 * 1024;
     37 
     38 // Minimum capacity of the buffer in forward or backward direction.
     39 //
     40 // 2MB is an arbitrary limit; it just seems to be "good enough" in practice.
     41 static const int kMinBufferCapacity = 2 * kMegabyte;
     42 
     43 // Maximum capacity of the buffer in forward or backward direction. This is
     44 // effectively the largest single read the code path can handle.
     45 // 20MB is an arbitrary limit; it just seems to be "good enough" in practice.
     46 static const int kMaxBufferCapacity = 20 * kMegabyte;
     47 
     48 // Maximum number of bytes outside the buffer we will wait for in order to
     49 // fulfill a read. If a read starts more than 2MB away from the data we
     50 // currently have in the buffer, we will not wait for buffer to reach the read's
     51 // location and will instead reset the request.
     52 static const int kForwardWaitThreshold = 2 * kMegabyte;
     53 
     54 // Computes the suggested backward and forward capacity for the buffer
     55 // if one wants to play at |playback_rate| * the natural playback speed.
     56 // Use a value of 0 for |bitrate| if it is unknown.
     57 static void ComputeTargetBufferWindow(float playback_rate, int bitrate,
     58                                       int* out_backward_capacity,
     59                                       int* out_forward_capacity) {
     60   static const int kDefaultBitrate = 200 * 1024 * 8;  // 200 Kbps.
     61   static const int kMaxBitrate = 20 * kMegabyte * 8;  // 20 Mbps.
     62   static const float kMaxPlaybackRate = 25.0;
     63   static const int kTargetSecondsBufferedAhead = 10;
     64   static const int kTargetSecondsBufferedBehind = 2;
     65 
     66   // Use a default bit rate if unknown and clamp to prevent overflow.
     67   if (bitrate <= 0)
     68     bitrate = kDefaultBitrate;
     69   bitrate = std::min(bitrate, kMaxBitrate);
     70 
     71   // Only scale the buffer window for playback rates greater than 1.0 in
     72   // magnitude and clamp to prevent overflow.
     73   bool backward_playback = false;
     74   if (playback_rate < 0.0f) {
     75     backward_playback = true;
     76     playback_rate *= -1.0f;
     77   }
     78 
     79   playback_rate = std::max(playback_rate, 1.0f);
     80   playback_rate = std::min(playback_rate, kMaxPlaybackRate);
     81 
     82   int bytes_per_second = (bitrate / 8.0) * playback_rate;
     83 
     84   // Clamp between kMinBufferCapacity and kMaxBufferCapacity.
     85   *out_forward_capacity = std::max(
     86       kTargetSecondsBufferedAhead * bytes_per_second, kMinBufferCapacity);
     87   *out_backward_capacity = std::max(
     88       kTargetSecondsBufferedBehind * bytes_per_second, kMinBufferCapacity);
     89 
     90   *out_forward_capacity = std::min(*out_forward_capacity, kMaxBufferCapacity);
     91   *out_backward_capacity = std::min(*out_backward_capacity, kMaxBufferCapacity);
     92 
     93   if (backward_playback)
     94     std::swap(*out_forward_capacity, *out_backward_capacity);
     95 }
     96 
     97 BufferedResourceLoader::BufferedResourceLoader(
     98     const GURL& url,
     99     CORSMode cors_mode,
    100     int64 first_byte_position,
    101     int64 last_byte_position,
    102     DeferStrategy strategy,
    103     int bitrate,
    104     float playback_rate,
    105     MediaLog* media_log)
    106     : buffer_(kMinBufferCapacity, kMinBufferCapacity),
    107       loader_failed_(false),
    108       defer_strategy_(strategy),
    109       might_be_reused_from_cache_in_future_(true),
    110       range_supported_(false),
    111       saved_forward_capacity_(0),
    112       url_(url),
    113       cors_mode_(cors_mode),
    114       first_byte_position_(first_byte_position),
    115       last_byte_position_(last_byte_position),
    116       single_origin_(true),
    117       offset_(0),
    118       content_length_(kPositionNotSpecified),
    119       instance_size_(kPositionNotSpecified),
    120       read_position_(0),
    121       read_size_(0),
    122       read_buffer_(NULL),
    123       first_offset_(0),
    124       last_offset_(0),
    125       bitrate_(bitrate),
    126       playback_rate_(playback_rate),
    127       media_log_(media_log) {
    128 
    129   // Set the initial capacity of |buffer_| based on |bitrate_| and
    130   // |playback_rate_|.
    131   UpdateBufferWindow();
    132 }
    133 
    134 BufferedResourceLoader::~BufferedResourceLoader() {}
    135 
    136 void BufferedResourceLoader::Start(
    137     const StartCB& start_cb,
    138     const LoadingStateChangedCB& loading_cb,
    139     const ProgressCB& progress_cb,
    140     WebFrame* frame) {
    141   // Make sure we have not started.
    142   DCHECK(start_cb_.is_null());
    143   DCHECK(loading_cb_.is_null());
    144   DCHECK(progress_cb_.is_null());
    145   DCHECK(!start_cb.is_null());
    146   DCHECK(!loading_cb.is_null());
    147   DCHECK(!progress_cb.is_null());
    148   CHECK(frame);
    149 
    150   start_cb_ = start_cb;
    151   loading_cb_ = loading_cb;
    152   progress_cb_ = progress_cb;
    153 
    154   if (first_byte_position_ != kPositionNotSpecified) {
    155     // TODO(hclam): server may not support range request so |offset_| may not
    156     // equal to |first_byte_position_|.
    157     offset_ = first_byte_position_;
    158   }
    159 
    160   // Prepare the request.
    161   WebURLRequest request(url_);
    162   // TODO(mkwst): Split this into video/audio.
    163   request.setRequestContext(WebURLRequest::RequestContextVideo);
    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",
    380                                 shift,
    381                                 max_enum); // PRESUBMIT_IGNORE_UMA_MAX
    382     }
    383 
    384     reasons >>= 1;
    385     ++shift;
    386   }
    387 
    388   // Expected content length can be |kPositionNotSpecified|, in that case
    389   // |content_length_| is not specified and this is a streaming response.
    390   content_length_ = response.expectedContentLength();
    391 
    392   // We make a strong assumption that when we reach here we have either
    393   // received a response from HTTP/HTTPS protocol or the request was
    394   // successful (in particular range request). So we only verify the partial
    395   // response for HTTP and HTTPS protocol.
    396   if (url_.SchemeIsHTTPOrHTTPS()) {
    397     bool partial_response = (response.httpStatusCode() == kHttpPartialContent);
    398     bool ok_response = (response.httpStatusCode() == kHttpOK);
    399 
    400     if (IsRangeRequest()) {
    401       // Check to see whether the server supports byte ranges.
    402       std::string accept_ranges =
    403           response.httpHeaderField("Accept-Ranges").utf8();
    404       range_supported_ = (accept_ranges.find("bytes") != std::string::npos);
    405 
    406       // If we have verified the partial response and it is correct, we will
    407       // return kOk. It's also possible for a server to support range requests
    408       // without advertising "Accept-Ranges: bytes".
    409       if (partial_response && VerifyPartialResponse(response)) {
    410         range_supported_ = true;
    411       } else if (ok_response && first_byte_position_ == 0 &&
    412                  last_byte_position_ == kPositionNotSpecified) {
    413         // We accept a 200 response for a Range:0- request, trusting the
    414         // Accept-Ranges header, because Apache thinks that's a reasonable thing
    415         // to return.
    416         instance_size_ = content_length_;
    417       } else {
    418         DoneStart(kFailed);
    419         return;
    420       }
    421     } else {
    422       instance_size_ = content_length_;
    423       if (response.httpStatusCode() != kHttpOK) {
    424         // We didn't request a range but server didn't reply with "200 OK".
    425         DoneStart(kFailed);
    426         return;
    427       }
    428     }
    429 
    430   } else {
    431     CHECK_EQ(instance_size_, kPositionNotSpecified);
    432     if (content_length_ != kPositionNotSpecified) {
    433       if (first_byte_position_ == kPositionNotSpecified)
    434         instance_size_ = content_length_;
    435       else if (last_byte_position_ == kPositionNotSpecified)
    436         instance_size_ = content_length_ + first_byte_position_;
    437     }
    438   }
    439 
    440   // Calls with a successful response.
    441   DoneStart(kOk);
    442 }
    443 
    444 void BufferedResourceLoader::didReceiveData(
    445     WebURLLoader* loader,
    446     const char* data,
    447     int data_length,
    448     int encoded_data_length) {
    449   DVLOG(1) << "didReceiveData: " << data_length << " bytes";
    450   DCHECK(active_loader_.get());
    451   DCHECK_GT(data_length, 0);
    452 
    453   buffer_.Append(reinterpret_cast<const uint8*>(data), data_length);
    454 
    455   // If there is an active read request, try to fulfill the request.
    456   if (HasPendingRead() && CanFulfillRead())
    457     ReadInternal();
    458 
    459   // At last see if the buffer is full and we need to defer the downloading.
    460   UpdateDeferBehavior();
    461 
    462   // Consume excess bytes from our in-memory buffer if necessary.
    463   if (buffer_.forward_bytes() > buffer_.forward_capacity()) {
    464     int excess = buffer_.forward_bytes() - buffer_.forward_capacity();
    465     bool success = buffer_.Seek(excess);
    466     DCHECK(success);
    467     offset_ += first_offset_ + excess;
    468   }
    469 
    470   // Notify latest progress and buffered offset.
    471   progress_cb_.Run(offset_ + buffer_.forward_bytes() - 1);
    472   Log();
    473 }
    474 
    475 void BufferedResourceLoader::didDownloadData(
    476     blink::WebURLLoader* loader,
    477     int dataLength,
    478     int encoded_data_length) {
    479   NOTIMPLEMENTED();
    480 }
    481 
    482 void BufferedResourceLoader::didReceiveCachedMetadata(
    483     WebURLLoader* loader,
    484     const char* data,
    485     int data_length) {
    486   NOTIMPLEMENTED();
    487 }
    488 
    489 void BufferedResourceLoader::didFinishLoading(
    490     WebURLLoader* loader,
    491     double finishTime,
    492     int64_t total_encoded_data_length) {
    493   DVLOG(1) << "didFinishLoading";
    494   DCHECK(active_loader_.get());
    495 
    496   // We're done with the loader.
    497   active_loader_.reset();
    498   loading_cb_.Run(kLoadingFinished);
    499 
    500   // If we didn't know the |instance_size_| we do now.
    501   if (instance_size_ == kPositionNotSpecified) {
    502     instance_size_ = offset_ + buffer_.forward_bytes();
    503   }
    504 
    505   // If there is a start callback, run it.
    506   if (!start_cb_.is_null()) {
    507     DCHECK(read_cb_.is_null())
    508         << "Shouldn't have a read callback during start";
    509     DoneStart(kOk);
    510     return;
    511   }
    512 
    513   // Don't leave read callbacks hanging around.
    514   if (HasPendingRead()) {
    515     // Try to fulfill with what is in the buffer.
    516     if (CanFulfillRead())
    517       ReadInternal();
    518     else
    519       DoneRead(kCacheMiss, 0);
    520   }
    521 }
    522 
    523 void BufferedResourceLoader::didFail(
    524     WebURLLoader* loader,
    525     const WebURLError& error) {
    526   DVLOG(1) << "didFail: reason=" << error.reason
    527            << ", isCancellation=" << error.isCancellation
    528            << ", domain=" << error.domain.utf8().data()
    529            << ", localizedDescription="
    530            << error.localizedDescription.utf8().data();
    531   DCHECK(active_loader_.get());
    532 
    533   // We don't need to continue loading after failure.
    534   //
    535   // Keep it alive until we exit this method so that |error| remains valid.
    536   scoped_ptr<ActiveLoader> active_loader = active_loader_.Pass();
    537   loader_failed_ = true;
    538   loading_cb_.Run(kLoadingFailed);
    539 
    540   // Don't leave start callbacks hanging around.
    541   if (!start_cb_.is_null()) {
    542     DCHECK(read_cb_.is_null())
    543         << "Shouldn't have a read callback during start";
    544     DoneStart(kFailed);
    545     return;
    546   }
    547 
    548   // Don't leave read callbacks hanging around.
    549   if (HasPendingRead()) {
    550     DoneRead(kFailed, 0);
    551   }
    552 }
    553 
    554 bool BufferedResourceLoader::HasSingleOrigin() const {
    555   DCHECK(start_cb_.is_null())
    556       << "Start() must complete before calling HasSingleOrigin()";
    557   return single_origin_;
    558 }
    559 
    560 bool BufferedResourceLoader::DidPassCORSAccessCheck() const {
    561   DCHECK(start_cb_.is_null())
    562       << "Start() must complete before calling DidPassCORSAccessCheck()";
    563   return !loader_failed_ && cors_mode_ != kUnspecified;
    564 }
    565 
    566 void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) {
    567   if (!might_be_reused_from_cache_in_future_ && strategy == kNeverDefer)
    568     strategy = kCapacityDefer;
    569   defer_strategy_ = strategy;
    570   UpdateDeferBehavior();
    571 }
    572 
    573 void BufferedResourceLoader::SetPlaybackRate(float playback_rate) {
    574   playback_rate_ = playback_rate;
    575 
    576   // This is a pause so don't bother updating the buffer window as we'll likely
    577   // get unpaused in the future.
    578   if (playback_rate_ == 0.0)
    579     return;
    580 
    581   UpdateBufferWindow();
    582 }
    583 
    584 void BufferedResourceLoader::SetBitrate(int bitrate) {
    585   DCHECK(bitrate >= 0);
    586   bitrate_ = bitrate;
    587   UpdateBufferWindow();
    588 }
    589 
    590 /////////////////////////////////////////////////////////////////////////////
    591 // Helper methods.
    592 
    593 void BufferedResourceLoader::UpdateBufferWindow() {
    594   int backward_capacity;
    595   int forward_capacity;
    596   ComputeTargetBufferWindow(
    597       playback_rate_, bitrate_, &backward_capacity, &forward_capacity);
    598 
    599   // This does not evict data from the buffer if the new capacities are less
    600   // than the current capacities; the new limits will be enforced after the
    601   // existing excess buffered data is consumed.
    602   buffer_.set_backward_capacity(backward_capacity);
    603   buffer_.set_forward_capacity(forward_capacity);
    604 }
    605 
    606 void BufferedResourceLoader::UpdateDeferBehavior() {
    607   if (!active_loader_)
    608     return;
    609 
    610   SetDeferred(ShouldDefer());
    611 }
    612 
    613 void BufferedResourceLoader::SetDeferred(bool deferred) {
    614   if (active_loader_->deferred() == deferred)
    615     return;
    616 
    617   active_loader_->SetDeferred(deferred);
    618   loading_cb_.Run(deferred ? kLoadingDeferred : kLoading);
    619 }
    620 
    621 bool BufferedResourceLoader::ShouldDefer() const {
    622   switch(defer_strategy_) {
    623     case kNeverDefer:
    624       return false;
    625 
    626     case kReadThenDefer:
    627       DCHECK(read_cb_.is_null() || last_offset_ > buffer_.forward_bytes())
    628           << "We shouldn't stop deferring if we can fulfill the read";
    629       return read_cb_.is_null();
    630 
    631     case kCapacityDefer:
    632       return buffer_.forward_bytes() >= buffer_.forward_capacity();
    633   }
    634   NOTREACHED();
    635   return false;
    636 }
    637 
    638 bool BufferedResourceLoader::CanFulfillRead() const {
    639   // If we are reading too far in the backward direction.
    640   if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0)
    641     return false;
    642 
    643   // If the start offset is too far ahead.
    644   if (first_offset_ >= buffer_.forward_bytes())
    645     return false;
    646 
    647   // At the point, we verified that first byte requested is within the buffer.
    648   // If the request has completed, then just returns with what we have now.
    649   if (!active_loader_)
    650     return true;
    651 
    652   // If the resource request is still active, make sure the whole requested
    653   // range is covered.
    654   if (last_offset_ > buffer_.forward_bytes())
    655     return false;
    656 
    657   return true;
    658 }
    659 
    660 bool BufferedResourceLoader::WillFulfillRead() const {
    661   // Trying to read too far behind.
    662   if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0)
    663     return false;
    664 
    665   // Trying to read too far ahead.
    666   if ((first_offset_ - buffer_.forward_bytes()) >= kForwardWaitThreshold)
    667     return false;
    668 
    669   // The resource request has completed, there's no way we can fulfill the
    670   // read request.
    671   if (!active_loader_)
    672     return false;
    673 
    674   return true;
    675 }
    676 
    677 void BufferedResourceLoader::ReadInternal() {
    678   // Seek to the first byte requested.
    679   bool ret = buffer_.Seek(first_offset_);
    680   DCHECK(ret);
    681 
    682   // Then do the read.
    683   int read = buffer_.Read(read_buffer_, read_size_);
    684   offset_ += first_offset_ + read;
    685 
    686   // And report with what we have read.
    687   DoneRead(kOk, read);
    688 }
    689 
    690 int64 BufferedResourceLoader::first_byte_position() const {
    691   return first_byte_position_;
    692 }
    693 
    694 // static
    695 bool BufferedResourceLoader::ParseContentRange(
    696     const std::string& content_range_str, int64* first_byte_position,
    697     int64* last_byte_position, int64* instance_size) {
    698   const std::string kUpThroughBytesUnit = "bytes ";
    699   if (content_range_str.find(kUpThroughBytesUnit) != 0)
    700     return false;
    701   std::string range_spec =
    702       content_range_str.substr(kUpThroughBytesUnit.length());
    703   size_t dash_offset = range_spec.find("-");
    704   size_t slash_offset = range_spec.find("/");
    705 
    706   if (dash_offset == std::string::npos || slash_offset == std::string::npos ||
    707       slash_offset < dash_offset || slash_offset + 1 == range_spec.length()) {
    708     return false;
    709   }
    710   if (!base::StringToInt64(range_spec.substr(0, dash_offset),
    711                            first_byte_position) ||
    712       !base::StringToInt64(range_spec.substr(dash_offset + 1,
    713                                              slash_offset - dash_offset - 1),
    714                            last_byte_position)) {
    715     return false;
    716   }
    717   if (slash_offset == range_spec.length() - 2 &&
    718       range_spec[slash_offset + 1] == '*') {
    719     *instance_size = kPositionNotSpecified;
    720   } else {
    721     if (!base::StringToInt64(range_spec.substr(slash_offset + 1),
    722                              instance_size)) {
    723       return false;
    724     }
    725   }
    726   if (*last_byte_position < *first_byte_position ||
    727       (*instance_size != kPositionNotSpecified &&
    728        *last_byte_position >= *instance_size)) {
    729     return false;
    730   }
    731 
    732   return true;
    733 }
    734 
    735 bool BufferedResourceLoader::VerifyPartialResponse(
    736     const WebURLResponse& response) {
    737   int64 first_byte_position, last_byte_position, instance_size;
    738   if (!ParseContentRange(response.httpHeaderField("Content-Range").utf8(),
    739                          &first_byte_position, &last_byte_position,
    740                          &instance_size)) {
    741     return false;
    742   }
    743 
    744   if (instance_size != kPositionNotSpecified) {
    745     instance_size_ = instance_size;
    746   }
    747 
    748   if (first_byte_position_ != kPositionNotSpecified &&
    749       first_byte_position_ != first_byte_position) {
    750     return false;
    751   }
    752 
    753   // TODO(hclam): I should also check |last_byte_position|, but since
    754   // we will never make such a request that it is ok to leave it unimplemented.
    755   return true;
    756 }
    757 
    758 void BufferedResourceLoader::DoneRead(Status status, int bytes_read) {
    759   if (saved_forward_capacity_) {
    760     buffer_.set_forward_capacity(saved_forward_capacity_);
    761     saved_forward_capacity_ = 0;
    762   }
    763   read_position_ = 0;
    764   read_size_ = 0;
    765   read_buffer_ = NULL;
    766   first_offset_ = 0;
    767   last_offset_ = 0;
    768   Log();
    769 
    770   base::ResetAndReturn(&read_cb_).Run(status, bytes_read);
    771 }
    772 
    773 
    774 void BufferedResourceLoader::DoneStart(Status status) {
    775   base::ResetAndReturn(&start_cb_).Run(status);
    776 }
    777 
    778 bool BufferedResourceLoader::IsRangeRequest() const {
    779   return first_byte_position_ != kPositionNotSpecified;
    780 }
    781 
    782 void BufferedResourceLoader::Log() {
    783   media_log_->AddEvent(
    784       media_log_->CreateBufferedExtentsChangedEvent(
    785           offset_ - buffer_.backward_bytes(),
    786           offset_,
    787           offset_ + buffer_.forward_bytes()));
    788 }
    789 
    790 }  // namespace media
    791