| Index: content/renderer/media/buffered_resource_loader.cc
 | 
| diff --git a/content/renderer/media/buffered_resource_loader.cc b/content/renderer/media/buffered_resource_loader.cc
 | 
| deleted file mode 100644
 | 
| index b43359c982914496418fd8eca6bc0d9b4ed3ad69..0000000000000000000000000000000000000000
 | 
| --- a/content/renderer/media/buffered_resource_loader.cc
 | 
| +++ /dev/null
 | 
| @@ -1,787 +0,0 @@
 | 
| -// Copyright 2013 The Chromium Authors. All rights reserved.
 | 
| -// Use of this source code is governed by a BSD-style license that can be
 | 
| -// found in the LICENSE file.
 | 
| -
 | 
| -#include "content/renderer/media/buffered_resource_loader.h"
 | 
| -
 | 
| -#include "base/bits.h"
 | 
| -#include "base/callback_helpers.h"
 | 
| -#include "base/metrics/histogram.h"
 | 
| -#include "base/strings/string_number_conversions.h"
 | 
| -#include "base/strings/string_util.h"
 | 
| -#include "content/public/common/url_constants.h"
 | 
| -#include "content/renderer/media/cache_util.h"
 | 
| -#include "media/base/media_log.h"
 | 
| -#include "net/http/http_byte_range.h"
 | 
| -#include "net/http/http_request_headers.h"
 | 
| -#include "third_party/WebKit/public/platform/WebString.h"
 | 
| -#include "third_party/WebKit/public/platform/WebURLError.h"
 | 
| -#include "third_party/WebKit/public/platform/WebURLResponse.h"
 | 
| -#include "third_party/WebKit/public/web/WebKit.h"
 | 
| -#include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
 | 
| -
 | 
| -using blink::WebFrame;
 | 
| -using blink::WebString;
 | 
| -using blink::WebURLError;
 | 
| -using blink::WebURLLoader;
 | 
| -using blink::WebURLLoaderOptions;
 | 
| -using blink::WebURLRequest;
 | 
| -using blink::WebURLResponse;
 | 
| -
 | 
| -namespace content {
 | 
| -
 | 
| -static const int kHttpOK = 200;
 | 
| -static const int kHttpPartialContent = 206;
 | 
| -
 | 
| -// Define the number of bytes in a megabyte.
 | 
| -static const int kMegabyte = 1024 * 1024;
 | 
| -
 | 
| -// Minimum capacity of the buffer in forward or backward direction.
 | 
| -//
 | 
| -// 2MB is an arbitrary limit; it just seems to be "good enough" in practice.
 | 
| -static const int kMinBufferCapacity = 2 * kMegabyte;
 | 
| -
 | 
| -// Maximum capacity of the buffer in forward or backward direction. This is
 | 
| -// effectively the largest single read the code path can handle.
 | 
| -// 20MB is an arbitrary limit; it just seems to be "good enough" in practice.
 | 
| -static const int kMaxBufferCapacity = 20 * kMegabyte;
 | 
| -
 | 
| -// Maximum number of bytes outside the buffer we will wait for in order to
 | 
| -// fulfill a read. If a read starts more than 2MB away from the data we
 | 
| -// currently have in the buffer, we will not wait for buffer to reach the read's
 | 
| -// location and will instead reset the request.
 | 
| -static const int kForwardWaitThreshold = 2 * kMegabyte;
 | 
| -
 | 
| -// Computes the suggested backward and forward capacity for the buffer
 | 
| -// if one wants to play at |playback_rate| * the natural playback speed.
 | 
| -// Use a value of 0 for |bitrate| if it is unknown.
 | 
| -static void ComputeTargetBufferWindow(float playback_rate, int bitrate,
 | 
| -                                      int* out_backward_capacity,
 | 
| -                                      int* out_forward_capacity) {
 | 
| -  static const int kDefaultBitrate = 200 * 1024 * 8;  // 200 Kbps.
 | 
| -  static const int kMaxBitrate = 20 * kMegabyte * 8;  // 20 Mbps.
 | 
| -  static const float kMaxPlaybackRate = 25.0;
 | 
| -  static const int kTargetSecondsBufferedAhead = 10;
 | 
| -  static const int kTargetSecondsBufferedBehind = 2;
 | 
| -
 | 
| -  // Use a default bit rate if unknown and clamp to prevent overflow.
 | 
| -  if (bitrate <= 0)
 | 
| -    bitrate = kDefaultBitrate;
 | 
| -  bitrate = std::min(bitrate, kMaxBitrate);
 | 
| -
 | 
| -  // Only scale the buffer window for playback rates greater than 1.0 in
 | 
| -  // magnitude and clamp to prevent overflow.
 | 
| -  bool backward_playback = false;
 | 
| -  if (playback_rate < 0.0f) {
 | 
| -    backward_playback = true;
 | 
| -    playback_rate *= -1.0f;
 | 
| -  }
 | 
| -
 | 
| -  playback_rate = std::max(playback_rate, 1.0f);
 | 
| -  playback_rate = std::min(playback_rate, kMaxPlaybackRate);
 | 
| -
 | 
| -  int bytes_per_second = (bitrate / 8.0) * playback_rate;
 | 
| -
 | 
| -  // Clamp between kMinBufferCapacity and kMaxBufferCapacity.
 | 
| -  *out_forward_capacity = std::max(
 | 
| -      kTargetSecondsBufferedAhead * bytes_per_second, kMinBufferCapacity);
 | 
| -  *out_backward_capacity = std::max(
 | 
| -      kTargetSecondsBufferedBehind * bytes_per_second, kMinBufferCapacity);
 | 
| -
 | 
| -  *out_forward_capacity = std::min(*out_forward_capacity, kMaxBufferCapacity);
 | 
| -  *out_backward_capacity = std::min(*out_backward_capacity, kMaxBufferCapacity);
 | 
| -
 | 
| -  if (backward_playback)
 | 
| -    std::swap(*out_forward_capacity, *out_backward_capacity);
 | 
| -}
 | 
| -
 | 
| -BufferedResourceLoader::BufferedResourceLoader(
 | 
| -    const GURL& url,
 | 
| -    CORSMode cors_mode,
 | 
| -    int64 first_byte_position,
 | 
| -    int64 last_byte_position,
 | 
| -    DeferStrategy strategy,
 | 
| -    int bitrate,
 | 
| -    float playback_rate,
 | 
| -    media::MediaLog* media_log)
 | 
| -    : buffer_(kMinBufferCapacity, kMinBufferCapacity),
 | 
| -      loader_failed_(false),
 | 
| -      defer_strategy_(strategy),
 | 
| -      might_be_reused_from_cache_in_future_(true),
 | 
| -      range_supported_(false),
 | 
| -      saved_forward_capacity_(0),
 | 
| -      url_(url),
 | 
| -      cors_mode_(cors_mode),
 | 
| -      first_byte_position_(first_byte_position),
 | 
| -      last_byte_position_(last_byte_position),
 | 
| -      single_origin_(true),
 | 
| -      offset_(0),
 | 
| -      content_length_(kPositionNotSpecified),
 | 
| -      instance_size_(kPositionNotSpecified),
 | 
| -      read_position_(0),
 | 
| -      read_size_(0),
 | 
| -      read_buffer_(NULL),
 | 
| -      first_offset_(0),
 | 
| -      last_offset_(0),
 | 
| -      bitrate_(bitrate),
 | 
| -      playback_rate_(playback_rate),
 | 
| -      media_log_(media_log) {
 | 
| -
 | 
| -  // Set the initial capacity of |buffer_| based on |bitrate_| and
 | 
| -  // |playback_rate_|.
 | 
| -  UpdateBufferWindow();
 | 
| -}
 | 
| -
 | 
| -BufferedResourceLoader::~BufferedResourceLoader() {}
 | 
| -
 | 
| -void BufferedResourceLoader::Start(
 | 
| -    const StartCB& start_cb,
 | 
| -    const LoadingStateChangedCB& loading_cb,
 | 
| -    const ProgressCB& progress_cb,
 | 
| -    WebFrame* frame) {
 | 
| -  // Make sure we have not started.
 | 
| -  DCHECK(start_cb_.is_null());
 | 
| -  DCHECK(loading_cb_.is_null());
 | 
| -  DCHECK(progress_cb_.is_null());
 | 
| -  DCHECK(!start_cb.is_null());
 | 
| -  DCHECK(!loading_cb.is_null());
 | 
| -  DCHECK(!progress_cb.is_null());
 | 
| -  CHECK(frame);
 | 
| -
 | 
| -  start_cb_ = start_cb;
 | 
| -  loading_cb_ = loading_cb;
 | 
| -  progress_cb_ = progress_cb;
 | 
| -
 | 
| -  if (first_byte_position_ != kPositionNotSpecified) {
 | 
| -    // TODO(hclam): server may not support range request so |offset_| may not
 | 
| -    // equal to |first_byte_position_|.
 | 
| -    offset_ = first_byte_position_;
 | 
| -  }
 | 
| -
 | 
| -  // Prepare the request.
 | 
| -  WebURLRequest request(url_);
 | 
| -  // TODO(mkwst): Split this into video/audio.
 | 
| -  request.setRequestContext(WebURLRequest::RequestContextVideo);
 | 
| -
 | 
| -  if (IsRangeRequest()) {
 | 
| -    request.setHTTPHeaderField(
 | 
| -        WebString::fromUTF8(net::HttpRequestHeaders::kRange),
 | 
| -        WebString::fromUTF8(net::HttpByteRange::Bounded(
 | 
| -            first_byte_position_, last_byte_position_).GetHeaderValue()));
 | 
| -  }
 | 
| -
 | 
| -  frame->setReferrerForRequest(request, blink::WebURL());
 | 
| -
 | 
| -  // Disable compression, compression for audio/video doesn't make sense...
 | 
| -  request.setHTTPHeaderField(
 | 
| -      WebString::fromUTF8(net::HttpRequestHeaders::kAcceptEncoding),
 | 
| -      WebString::fromUTF8("identity;q=1, *;q=0"));
 | 
| -
 | 
| -  // Check for our test WebURLLoader.
 | 
| -  scoped_ptr<WebURLLoader> loader;
 | 
| -  if (test_loader_) {
 | 
| -    loader = test_loader_.Pass();
 | 
| -  } else {
 | 
| -    WebURLLoaderOptions options;
 | 
| -    if (cors_mode_ == kUnspecified) {
 | 
| -      options.allowCredentials = true;
 | 
| -      options.crossOriginRequestPolicy =
 | 
| -          WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
 | 
| -    } else {
 | 
| -      options.exposeAllResponseHeaders = true;
 | 
| -      // The author header set is empty, no preflight should go ahead.
 | 
| -      options.preflightPolicy = WebURLLoaderOptions::PreventPreflight;
 | 
| -      options.crossOriginRequestPolicy =
 | 
| -          WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
 | 
| -      if (cors_mode_ == kUseCredentials)
 | 
| -        options.allowCredentials = true;
 | 
| -    }
 | 
| -    loader.reset(frame->createAssociatedURLLoader(options));
 | 
| -  }
 | 
| -
 | 
| -  // Start the resource loading.
 | 
| -  loader->loadAsynchronously(request, this);
 | 
| -  active_loader_.reset(new ActiveLoader(loader.Pass()));
 | 
| -  loading_cb_.Run(kLoading);
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::Stop() {
 | 
| -  // Reset callbacks.
 | 
| -  start_cb_.Reset();
 | 
| -  loading_cb_.Reset();
 | 
| -  progress_cb_.Reset();
 | 
| -  read_cb_.Reset();
 | 
| -
 | 
| -  // Cancel and reset any active loaders.
 | 
| -  active_loader_.reset();
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::Read(
 | 
| -    int64 position,
 | 
| -    int read_size,
 | 
| -    uint8* buffer,
 | 
| -    const ReadCB& read_cb) {
 | 
| -  DCHECK(start_cb_.is_null());
 | 
| -  DCHECK(read_cb_.is_null());
 | 
| -  DCHECK(!read_cb.is_null());
 | 
| -  DCHECK(buffer);
 | 
| -  DCHECK_GT(read_size, 0);
 | 
| -
 | 
| -  // Save the parameter of reading.
 | 
| -  read_cb_ = read_cb;
 | 
| -  read_position_ = position;
 | 
| -  read_size_ = read_size;
 | 
| -  read_buffer_ = buffer;
 | 
| -
 | 
| -  // Reads should immediately fail if the loader also failed.
 | 
| -  if (loader_failed_) {
 | 
| -    DoneRead(kFailed, 0);
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // If we're attempting to read past the end of the file, return a zero
 | 
| -  // indicating EOF.
 | 
| -  //
 | 
| -  // This can happen with callees that read in fixed-sized amounts for parsing
 | 
| -  // or at the end of chunked 200 responses when we discover the actual length
 | 
| -  // of the file.
 | 
| -  if (instance_size_ != kPositionNotSpecified &&
 | 
| -      instance_size_ <= read_position_) {
 | 
| -    DVLOG(1) << "Appear to have seeked beyond EOS; returning 0.";
 | 
| -    DoneRead(kOk, 0);
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Make sure |offset_| and |read_position_| does not differ by a large
 | 
| -  // amount.
 | 
| -  if (read_position_ > offset_ + kint32max ||
 | 
| -      read_position_ < offset_ + kint32min) {
 | 
| -    DoneRead(kCacheMiss, 0);
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Make sure |read_size_| is not too large for the buffer to ever be able to
 | 
| -  // fulfill the read request.
 | 
| -  if (read_size_ > kMaxBufferCapacity) {
 | 
| -    DoneRead(kFailed, 0);
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Prepare the parameters.
 | 
| -  first_offset_ = read_position_ - offset_;
 | 
| -  last_offset_ = first_offset_ + read_size_;
 | 
| -
 | 
| -  // If we can serve the request now, do the actual read.
 | 
| -  if (CanFulfillRead()) {
 | 
| -    ReadInternal();
 | 
| -    UpdateDeferBehavior();
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // If we expect the read request to be fulfilled later, expand capacity as
 | 
| -  // necessary and disable deferring.
 | 
| -  if (WillFulfillRead()) {
 | 
| -    // Advance offset as much as possible to create additional capacity.
 | 
| -    int advance = std::min(first_offset_, buffer_.forward_bytes());
 | 
| -    bool ret = buffer_.Seek(advance);
 | 
| -    DCHECK(ret);
 | 
| -
 | 
| -    offset_ += advance;
 | 
| -    first_offset_ -= advance;
 | 
| -    last_offset_ -= advance;
 | 
| -
 | 
| -    // Expand capacity to accomodate a read that extends past the normal
 | 
| -    // capacity.
 | 
| -    //
 | 
| -    // This can happen when reading in a large seek index or when the
 | 
| -    // first byte of a read request falls within kForwardWaitThreshold.
 | 
| -    if (last_offset_ > buffer_.forward_capacity()) {
 | 
| -      saved_forward_capacity_ = buffer_.forward_capacity();
 | 
| -      buffer_.set_forward_capacity(last_offset_);
 | 
| -    }
 | 
| -
 | 
| -    // Make sure we stop deferring now that there's additional capacity.
 | 
| -    DCHECK(!ShouldDefer())
 | 
| -        << "Capacity was not adjusted properly to prevent deferring.";
 | 
| -    UpdateDeferBehavior();
 | 
| -
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Make a callback to report failure.
 | 
| -  DoneRead(kCacheMiss, 0);
 | 
| -}
 | 
| -
 | 
| -int64 BufferedResourceLoader::content_length() {
 | 
| -  return content_length_;
 | 
| -}
 | 
| -
 | 
| -int64 BufferedResourceLoader::instance_size() {
 | 
| -  return instance_size_;
 | 
| -}
 | 
| -
 | 
| -bool BufferedResourceLoader::range_supported() {
 | 
| -  return range_supported_;
 | 
| -}
 | 
| -
 | 
| -/////////////////////////////////////////////////////////////////////////////
 | 
| -// blink::WebURLLoaderClient implementation.
 | 
| -void BufferedResourceLoader::willSendRequest(
 | 
| -    WebURLLoader* loader,
 | 
| -    WebURLRequest& newRequest,
 | 
| -    const WebURLResponse& redirectResponse) {
 | 
| -
 | 
| -  // The load may have been stopped and |start_cb| is destroyed.
 | 
| -  // In this case we shouldn't do anything.
 | 
| -  if (start_cb_.is_null()) {
 | 
| -    // Set the url in the request to an invalid value (empty url).
 | 
| -    newRequest.setURL(blink::WebURL());
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Only allow |single_origin_| if we haven't seen a different origin yet.
 | 
| -  if (single_origin_)
 | 
| -    single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin();
 | 
| -
 | 
| -  url_ = newRequest.url();
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::didSendData(
 | 
| -    WebURLLoader* loader,
 | 
| -    unsigned long long bytes_sent,
 | 
| -    unsigned long long total_bytes_to_be_sent) {
 | 
| -  NOTIMPLEMENTED();
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::didReceiveResponse(
 | 
| -    WebURLLoader* loader,
 | 
| -    const WebURLResponse& response) {
 | 
| -  DVLOG(1) << "didReceiveResponse: HTTP/"
 | 
| -           << (response.httpVersion() == WebURLResponse::HTTP_0_9 ? "0.9" :
 | 
| -               response.httpVersion() == WebURLResponse::HTTP_1_0 ? "1.0" :
 | 
| -               response.httpVersion() == WebURLResponse::HTTP_1_1 ? "1.1" :
 | 
| -               "Unknown")
 | 
| -           << " " << response.httpStatusCode();
 | 
| -  DCHECK(active_loader_.get());
 | 
| -
 | 
| -  // The loader may have been stopped and |start_cb| is destroyed.
 | 
| -  // In this case we shouldn't do anything.
 | 
| -  if (start_cb_.is_null())
 | 
| -    return;
 | 
| -
 | 
| -  uint32 reasons = GetReasonsForUncacheability(response);
 | 
| -  might_be_reused_from_cache_in_future_ = reasons == 0;
 | 
| -  UMA_HISTOGRAM_BOOLEAN("Media.CacheUseful", reasons == 0);
 | 
| -  int shift = 0;
 | 
| -  int max_enum = base::bits::Log2Ceiling(kMaxReason);
 | 
| -  while (reasons) {
 | 
| -    DCHECK_LT(shift, max_enum);  // Sanity check.
 | 
| -    if (reasons & 0x1)
 | 
| -      UMA_HISTOGRAM_ENUMERATION("Media.UncacheableReason", shift, max_enum);
 | 
| -    reasons >>= 1;
 | 
| -    ++shift;
 | 
| -  }
 | 
| -
 | 
| -  // Expected content length can be |kPositionNotSpecified|, in that case
 | 
| -  // |content_length_| is not specified and this is a streaming response.
 | 
| -  content_length_ = response.expectedContentLength();
 | 
| -
 | 
| -  // We make a strong assumption that when we reach here we have either
 | 
| -  // received a response from HTTP/HTTPS protocol or the request was
 | 
| -  // successful (in particular range request). So we only verify the partial
 | 
| -  // response for HTTP and HTTPS protocol.
 | 
| -  if (url_.SchemeIsHTTPOrHTTPS()) {
 | 
| -    bool partial_response = (response.httpStatusCode() == kHttpPartialContent);
 | 
| -    bool ok_response = (response.httpStatusCode() == kHttpOK);
 | 
| -
 | 
| -    if (IsRangeRequest()) {
 | 
| -      // Check to see whether the server supports byte ranges.
 | 
| -      std::string accept_ranges =
 | 
| -          response.httpHeaderField("Accept-Ranges").utf8();
 | 
| -      range_supported_ = (accept_ranges.find("bytes") != std::string::npos);
 | 
| -
 | 
| -      // If we have verified the partial response and it is correct, we will
 | 
| -      // return kOk. It's also possible for a server to support range requests
 | 
| -      // without advertising "Accept-Ranges: bytes".
 | 
| -      if (partial_response && VerifyPartialResponse(response)) {
 | 
| -        range_supported_ = true;
 | 
| -      } else if (ok_response && first_byte_position_ == 0 &&
 | 
| -                 last_byte_position_ == kPositionNotSpecified) {
 | 
| -        // We accept a 200 response for a Range:0- request, trusting the
 | 
| -        // Accept-Ranges header, because Apache thinks that's a reasonable thing
 | 
| -        // to return.
 | 
| -        instance_size_ = content_length_;
 | 
| -      } else {
 | 
| -        DoneStart(kFailed);
 | 
| -        return;
 | 
| -      }
 | 
| -    } else {
 | 
| -      instance_size_ = content_length_;
 | 
| -      if (response.httpStatusCode() != kHttpOK) {
 | 
| -        // We didn't request a range but server didn't reply with "200 OK".
 | 
| -        DoneStart(kFailed);
 | 
| -        return;
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -  } else {
 | 
| -    CHECK_EQ(instance_size_, kPositionNotSpecified);
 | 
| -    if (content_length_ != kPositionNotSpecified) {
 | 
| -      if (first_byte_position_ == kPositionNotSpecified)
 | 
| -        instance_size_ = content_length_;
 | 
| -      else if (last_byte_position_ == kPositionNotSpecified)
 | 
| -        instance_size_ = content_length_ + first_byte_position_;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  // Calls with a successful response.
 | 
| -  DoneStart(kOk);
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::didReceiveData(
 | 
| -    WebURLLoader* loader,
 | 
| -    const char* data,
 | 
| -    int data_length,
 | 
| -    int encoded_data_length) {
 | 
| -  DVLOG(1) << "didReceiveData: " << data_length << " bytes";
 | 
| -  DCHECK(active_loader_.get());
 | 
| -  DCHECK_GT(data_length, 0);
 | 
| -
 | 
| -  buffer_.Append(reinterpret_cast<const uint8*>(data), data_length);
 | 
| -
 | 
| -  // If there is an active read request, try to fulfill the request.
 | 
| -  if (HasPendingRead() && CanFulfillRead())
 | 
| -    ReadInternal();
 | 
| -
 | 
| -  // At last see if the buffer is full and we need to defer the downloading.
 | 
| -  UpdateDeferBehavior();
 | 
| -
 | 
| -  // Consume excess bytes from our in-memory buffer if necessary.
 | 
| -  if (buffer_.forward_bytes() > buffer_.forward_capacity()) {
 | 
| -    int excess = buffer_.forward_bytes() - buffer_.forward_capacity();
 | 
| -    bool success = buffer_.Seek(excess);
 | 
| -    DCHECK(success);
 | 
| -    offset_ += first_offset_ + excess;
 | 
| -  }
 | 
| -
 | 
| -  // Notify latest progress and buffered offset.
 | 
| -  progress_cb_.Run(offset_ + buffer_.forward_bytes() - 1);
 | 
| -  Log();
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::didDownloadData(
 | 
| -    blink::WebURLLoader* loader,
 | 
| -    int dataLength,
 | 
| -    int encoded_data_length) {
 | 
| -  NOTIMPLEMENTED();
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::didReceiveCachedMetadata(
 | 
| -    WebURLLoader* loader,
 | 
| -    const char* data,
 | 
| -    int data_length) {
 | 
| -  NOTIMPLEMENTED();
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::didFinishLoading(
 | 
| -    WebURLLoader* loader,
 | 
| -    double finishTime,
 | 
| -    int64_t total_encoded_data_length) {
 | 
| -  DVLOG(1) << "didFinishLoading";
 | 
| -  DCHECK(active_loader_.get());
 | 
| -
 | 
| -  // We're done with the loader.
 | 
| -  active_loader_.reset();
 | 
| -  loading_cb_.Run(kLoadingFinished);
 | 
| -
 | 
| -  // If we didn't know the |instance_size_| we do now.
 | 
| -  if (instance_size_ == kPositionNotSpecified) {
 | 
| -    instance_size_ = offset_ + buffer_.forward_bytes();
 | 
| -  }
 | 
| -
 | 
| -  // If there is a start callback, run it.
 | 
| -  if (!start_cb_.is_null()) {
 | 
| -    DCHECK(read_cb_.is_null())
 | 
| -        << "Shouldn't have a read callback during start";
 | 
| -    DoneStart(kOk);
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Don't leave read callbacks hanging around.
 | 
| -  if (HasPendingRead()) {
 | 
| -    // Try to fulfill with what is in the buffer.
 | 
| -    if (CanFulfillRead())
 | 
| -      ReadInternal();
 | 
| -    else
 | 
| -      DoneRead(kCacheMiss, 0);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::didFail(
 | 
| -    WebURLLoader* loader,
 | 
| -    const WebURLError& error) {
 | 
| -  DVLOG(1) << "didFail: reason=" << error.reason
 | 
| -           << ", isCancellation=" << error.isCancellation
 | 
| -           << ", domain=" << error.domain.utf8().data()
 | 
| -           << ", localizedDescription="
 | 
| -           << error.localizedDescription.utf8().data();
 | 
| -  DCHECK(active_loader_.get());
 | 
| -
 | 
| -  // We don't need to continue loading after failure.
 | 
| -  //
 | 
| -  // Keep it alive until we exit this method so that |error| remains valid.
 | 
| -  scoped_ptr<ActiveLoader> active_loader = active_loader_.Pass();
 | 
| -  loader_failed_ = true;
 | 
| -  loading_cb_.Run(kLoadingFailed);
 | 
| -
 | 
| -  // Don't leave start callbacks hanging around.
 | 
| -  if (!start_cb_.is_null()) {
 | 
| -    DCHECK(read_cb_.is_null())
 | 
| -        << "Shouldn't have a read callback during start";
 | 
| -    DoneStart(kFailed);
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Don't leave read callbacks hanging around.
 | 
| -  if (HasPendingRead()) {
 | 
| -    DoneRead(kFailed, 0);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -bool BufferedResourceLoader::HasSingleOrigin() const {
 | 
| -  DCHECK(start_cb_.is_null())
 | 
| -      << "Start() must complete before calling HasSingleOrigin()";
 | 
| -  return single_origin_;
 | 
| -}
 | 
| -
 | 
| -bool BufferedResourceLoader::DidPassCORSAccessCheck() const {
 | 
| -  DCHECK(start_cb_.is_null())
 | 
| -      << "Start() must complete before calling DidPassCORSAccessCheck()";
 | 
| -  return !loader_failed_ && cors_mode_ != kUnspecified;
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) {
 | 
| -  if (!might_be_reused_from_cache_in_future_ && strategy == kNeverDefer)
 | 
| -    strategy = kCapacityDefer;
 | 
| -  defer_strategy_ = strategy;
 | 
| -  UpdateDeferBehavior();
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::SetPlaybackRate(float playback_rate) {
 | 
| -  playback_rate_ = playback_rate;
 | 
| -
 | 
| -  // This is a pause so don't bother updating the buffer window as we'll likely
 | 
| -  // get unpaused in the future.
 | 
| -  if (playback_rate_ == 0.0)
 | 
| -    return;
 | 
| -
 | 
| -  UpdateBufferWindow();
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::SetBitrate(int bitrate) {
 | 
| -  DCHECK(bitrate >= 0);
 | 
| -  bitrate_ = bitrate;
 | 
| -  UpdateBufferWindow();
 | 
| -}
 | 
| -
 | 
| -/////////////////////////////////////////////////////////////////////////////
 | 
| -// Helper methods.
 | 
| -
 | 
| -void BufferedResourceLoader::UpdateBufferWindow() {
 | 
| -  int backward_capacity;
 | 
| -  int forward_capacity;
 | 
| -  ComputeTargetBufferWindow(
 | 
| -      playback_rate_, bitrate_, &backward_capacity, &forward_capacity);
 | 
| -
 | 
| -  // This does not evict data from the buffer if the new capacities are less
 | 
| -  // than the current capacities; the new limits will be enforced after the
 | 
| -  // existing excess buffered data is consumed.
 | 
| -  buffer_.set_backward_capacity(backward_capacity);
 | 
| -  buffer_.set_forward_capacity(forward_capacity);
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::UpdateDeferBehavior() {
 | 
| -  if (!active_loader_)
 | 
| -    return;
 | 
| -
 | 
| -  SetDeferred(ShouldDefer());
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::SetDeferred(bool deferred) {
 | 
| -  if (active_loader_->deferred() == deferred)
 | 
| -    return;
 | 
| -
 | 
| -  active_loader_->SetDeferred(deferred);
 | 
| -  loading_cb_.Run(deferred ? kLoadingDeferred : kLoading);
 | 
| -}
 | 
| -
 | 
| -bool BufferedResourceLoader::ShouldDefer() const {
 | 
| -  switch(defer_strategy_) {
 | 
| -    case kNeverDefer:
 | 
| -      return false;
 | 
| -
 | 
| -    case kReadThenDefer:
 | 
| -      DCHECK(read_cb_.is_null() || last_offset_ > buffer_.forward_bytes())
 | 
| -          << "We shouldn't stop deferring if we can fulfill the read";
 | 
| -      return read_cb_.is_null();
 | 
| -
 | 
| -    case kCapacityDefer:
 | 
| -      return buffer_.forward_bytes() >= buffer_.forward_capacity();
 | 
| -  }
 | 
| -  NOTREACHED();
 | 
| -  return false;
 | 
| -}
 | 
| -
 | 
| -bool BufferedResourceLoader::CanFulfillRead() const {
 | 
| -  // If we are reading too far in the backward direction.
 | 
| -  if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0)
 | 
| -    return false;
 | 
| -
 | 
| -  // If the start offset is too far ahead.
 | 
| -  if (first_offset_ >= buffer_.forward_bytes())
 | 
| -    return false;
 | 
| -
 | 
| -  // At the point, we verified that first byte requested is within the buffer.
 | 
| -  // If the request has completed, then just returns with what we have now.
 | 
| -  if (!active_loader_)
 | 
| -    return true;
 | 
| -
 | 
| -  // If the resource request is still active, make sure the whole requested
 | 
| -  // range is covered.
 | 
| -  if (last_offset_ > buffer_.forward_bytes())
 | 
| -    return false;
 | 
| -
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool BufferedResourceLoader::WillFulfillRead() const {
 | 
| -  // Trying to read too far behind.
 | 
| -  if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0)
 | 
| -    return false;
 | 
| -
 | 
| -  // Trying to read too far ahead.
 | 
| -  if ((first_offset_ - buffer_.forward_bytes()) >= kForwardWaitThreshold)
 | 
| -    return false;
 | 
| -
 | 
| -  // The resource request has completed, there's no way we can fulfill the
 | 
| -  // read request.
 | 
| -  if (!active_loader_)
 | 
| -    return false;
 | 
| -
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::ReadInternal() {
 | 
| -  // Seek to the first byte requested.
 | 
| -  bool ret = buffer_.Seek(first_offset_);
 | 
| -  DCHECK(ret);
 | 
| -
 | 
| -  // Then do the read.
 | 
| -  int read = buffer_.Read(read_buffer_, read_size_);
 | 
| -  offset_ += first_offset_ + read;
 | 
| -
 | 
| -  // And report with what we have read.
 | 
| -  DoneRead(kOk, read);
 | 
| -}
 | 
| -
 | 
| -int64 BufferedResourceLoader::first_byte_position() const {
 | 
| -  return first_byte_position_;
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -bool BufferedResourceLoader::ParseContentRange(
 | 
| -    const std::string& content_range_str, int64* first_byte_position,
 | 
| -    int64* last_byte_position, int64* instance_size) {
 | 
| -  const std::string kUpThroughBytesUnit = "bytes ";
 | 
| -  if (content_range_str.find(kUpThroughBytesUnit) != 0)
 | 
| -    return false;
 | 
| -  std::string range_spec =
 | 
| -      content_range_str.substr(kUpThroughBytesUnit.length());
 | 
| -  size_t dash_offset = range_spec.find("-");
 | 
| -  size_t slash_offset = range_spec.find("/");
 | 
| -
 | 
| -  if (dash_offset == std::string::npos || slash_offset == std::string::npos ||
 | 
| -      slash_offset < dash_offset || slash_offset + 1 == range_spec.length()) {
 | 
| -    return false;
 | 
| -  }
 | 
| -  if (!base::StringToInt64(range_spec.substr(0, dash_offset),
 | 
| -                           first_byte_position) ||
 | 
| -      !base::StringToInt64(range_spec.substr(dash_offset + 1,
 | 
| -                                             slash_offset - dash_offset - 1),
 | 
| -                           last_byte_position)) {
 | 
| -    return false;
 | 
| -  }
 | 
| -  if (slash_offset == range_spec.length() - 2 &&
 | 
| -      range_spec[slash_offset + 1] == '*') {
 | 
| -    *instance_size = kPositionNotSpecified;
 | 
| -  } else {
 | 
| -    if (!base::StringToInt64(range_spec.substr(slash_offset + 1),
 | 
| -                             instance_size)) {
 | 
| -      return false;
 | 
| -    }
 | 
| -  }
 | 
| -  if (*last_byte_position < *first_byte_position ||
 | 
| -      (*instance_size != kPositionNotSpecified &&
 | 
| -       *last_byte_position >= *instance_size)) {
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool BufferedResourceLoader::VerifyPartialResponse(
 | 
| -    const WebURLResponse& response) {
 | 
| -  int64 first_byte_position, last_byte_position, instance_size;
 | 
| -  if (!ParseContentRange(response.httpHeaderField("Content-Range").utf8(),
 | 
| -                         &first_byte_position, &last_byte_position,
 | 
| -                         &instance_size)) {
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  if (instance_size != kPositionNotSpecified) {
 | 
| -    instance_size_ = instance_size;
 | 
| -  }
 | 
| -
 | 
| -  if (first_byte_position_ != kPositionNotSpecified &&
 | 
| -      first_byte_position_ != first_byte_position) {
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  // TODO(hclam): I should also check |last_byte_position|, but since
 | 
| -  // we will never make such a request that it is ok to leave it unimplemented.
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::DoneRead(Status status, int bytes_read) {
 | 
| -  if (saved_forward_capacity_) {
 | 
| -    buffer_.set_forward_capacity(saved_forward_capacity_);
 | 
| -    saved_forward_capacity_ = 0;
 | 
| -  }
 | 
| -  read_position_ = 0;
 | 
| -  read_size_ = 0;
 | 
| -  read_buffer_ = NULL;
 | 
| -  first_offset_ = 0;
 | 
| -  last_offset_ = 0;
 | 
| -  Log();
 | 
| -
 | 
| -  base::ResetAndReturn(&read_cb_).Run(status, bytes_read);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void BufferedResourceLoader::DoneStart(Status status) {
 | 
| -  base::ResetAndReturn(&start_cb_).Run(status);
 | 
| -}
 | 
| -
 | 
| -bool BufferedResourceLoader::IsRangeRequest() const {
 | 
| -  return first_byte_position_ != kPositionNotSpecified;
 | 
| -}
 | 
| -
 | 
| -void BufferedResourceLoader::Log() {
 | 
| -  media_log_->AddEvent(
 | 
| -      media_log_->CreateBufferedExtentsChangedEvent(
 | 
| -          offset_ - buffer_.backward_bytes(),
 | 
| -          offset_,
 | 
| -          offset_ + buffer_.forward_bytes()));
 | 
| -}
 | 
| -
 | 
| -}  // namespace content
 | 
| 
 |