Home | History | Annotate | Download | only in media
      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/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 "content/renderer/media/cache_util.h"
     15 #include "media/base/media_log.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 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 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(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 content
    804