Home | History | Annotate | Download | only in media
      1 // Copyright (c) 2011 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 "webkit/glue/media/buffered_resource_loader.h"
      6 
      7 #include "base/format_macros.h"
      8 #include "base/string_util.h"
      9 #include "net/base/net_errors.h"
     10 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
     11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKitClient.h"
     12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
     13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLError.h"
     14 #include "webkit/glue/multipart_response_delegate.h"
     15 #include "webkit/glue/webkit_glue.h"
     16 
     17 using WebKit::WebFrame;
     18 using WebKit::WebString;
     19 using WebKit::WebURLError;
     20 using WebKit::WebURLLoader;
     21 using WebKit::WebURLRequest;
     22 using WebKit::WebURLResponse;
     23 using webkit_glue::MultipartResponseDelegate;
     24 
     25 namespace webkit_glue {
     26 
     27 static const int kHttpOK = 200;
     28 static const int kHttpPartialContent = 206;
     29 
     30 // Define the number of bytes in a megabyte.
     31 static const size_t kMegabyte = 1024 * 1024;
     32 
     33 // Backward capacity of the buffer, by default 2MB.
     34 static const size_t kBackwardCapcity = 2 * kMegabyte;
     35 
     36 // Forward capacity of the buffer, by default 10MB.
     37 static const size_t kForwardCapacity = 10 * kMegabyte;
     38 
     39 // The threshold of bytes that we should wait until the data arrives in the
     40 // future instead of restarting a new connection. This number is defined in the
     41 // number of bytes, we should determine this value from typical connection speed
     42 // and amount of time for a suitable wait. Now I just make a guess for this
     43 // number to be 2MB.
     44 // TODO(hclam): determine a better value for this.
     45 static const int kForwardWaitThreshold = 2 * kMegabyte;
     46 
     47 BufferedResourceLoader::BufferedResourceLoader(
     48     const GURL& url,
     49     int64 first_byte_position,
     50     int64 last_byte_position)
     51     : buffer_(new media::SeekableBuffer(kBackwardCapcity, kForwardCapacity)),
     52       deferred_(false),
     53       defer_strategy_(kReadThenDefer),
     54       completed_(false),
     55       range_requested_(false),
     56       range_supported_(false),
     57       url_(url),
     58       first_byte_position_(first_byte_position),
     59       last_byte_position_(last_byte_position),
     60       single_origin_(true),
     61       start_callback_(NULL),
     62       offset_(0),
     63       content_length_(kPositionNotSpecified),
     64       instance_size_(kPositionNotSpecified),
     65       read_callback_(NULL),
     66       read_position_(0),
     67       read_size_(0),
     68       read_buffer_(NULL),
     69       first_offset_(0),
     70       last_offset_(0),
     71       keep_test_loader_(false) {
     72 }
     73 
     74 BufferedResourceLoader::~BufferedResourceLoader() {
     75   if (!completed_ && url_loader_.get())
     76     url_loader_->cancel();
     77 }
     78 
     79 void BufferedResourceLoader::Start(net::CompletionCallback* start_callback,
     80                                    NetworkEventCallback* event_callback,
     81                                    WebFrame* frame) {
     82   // Make sure we have not started.
     83   DCHECK(!start_callback_.get());
     84   DCHECK(!event_callback_.get());
     85   DCHECK(start_callback);
     86   DCHECK(event_callback);
     87   CHECK(frame);
     88 
     89   start_callback_.reset(start_callback);
     90   event_callback_.reset(event_callback);
     91 
     92   if (first_byte_position_ != kPositionNotSpecified) {
     93     // TODO(hclam): server may not support range request so |offset_| may not
     94     // equal to |first_byte_position_|.
     95     offset_ = first_byte_position_;
     96   }
     97 
     98   // Increment the reference count right before we start the request. This
     99   // reference will be release when this request has ended.
    100   AddRef();
    101 
    102   // Prepare the request.
    103   WebURLRequest request(url_);
    104   request.setTargetType(WebURLRequest::TargetIsMedia);
    105 
    106   if (IsRangeRequest()) {
    107     range_requested_ = true;
    108     request.setHTTPHeaderField(WebString::fromUTF8("Range"),
    109                                WebString::fromUTF8(GenerateHeaders(
    110                                    first_byte_position_,
    111                                    last_byte_position_)));
    112   }
    113   frame->setReferrerForRequest(request, WebKit::WebURL());
    114 
    115   // This flag is for unittests as we don't want to reset |url_loader|
    116   if (!keep_test_loader_)
    117     url_loader_.reset(frame->createAssociatedURLLoader());
    118 
    119   // Start the resource loading.
    120   url_loader_->loadAsynchronously(request, this);
    121 }
    122 
    123 void BufferedResourceLoader::Stop() {
    124   // Reset callbacks.
    125   start_callback_.reset();
    126   event_callback_.reset();
    127   read_callback_.reset();
    128 
    129   // Use the internal buffer to signal that we have been stopped.
    130   // TODO(hclam): Not so pretty to do this.
    131   if (!buffer_.get())
    132     return;
    133 
    134   // Destroy internal buffer.
    135   buffer_.reset();
    136 
    137   if (url_loader_.get()) {
    138     if (deferred_)
    139       url_loader_->setDefersLoading(false);
    140     deferred_ = false;
    141 
    142     if (!completed_) {
    143       url_loader_->cancel();
    144       completed_ = true;
    145     }
    146   }
    147 }
    148 
    149 void BufferedResourceLoader::Read(int64 position,
    150                                   int read_size,
    151                                   uint8* buffer,
    152                                   net::CompletionCallback* read_callback) {
    153   DCHECK(!read_callback_.get());
    154   DCHECK(buffer_.get());
    155   DCHECK(read_callback);
    156   DCHECK(buffer);
    157 
    158   // Save the parameter of reading.
    159   read_callback_.reset(read_callback);
    160   read_position_ = position;
    161   read_size_ = read_size;
    162   read_buffer_ = buffer;
    163 
    164   // If read position is beyond the instance size, we cannot read there.
    165   if (instance_size_ != kPositionNotSpecified &&
    166       instance_size_ <= read_position_) {
    167     DoneRead(0);
    168     return;
    169   }
    170 
    171   // Make sure |offset_| and |read_position_| does not differ by a large
    172   // amount.
    173   if (read_position_ > offset_ + kint32max ||
    174       read_position_ < offset_ + kint32min) {
    175     DoneRead(net::ERR_CACHE_MISS);
    176     return;
    177   }
    178 
    179   // Prepare the parameters.
    180   first_offset_ = static_cast<int>(read_position_ - offset_);
    181   last_offset_ = first_offset_ + read_size_;
    182 
    183   // If we can serve the request now, do the actual read.
    184   if (CanFulfillRead()) {
    185     ReadInternal();
    186     UpdateDeferBehavior();
    187     return;
    188   }
    189 
    190   // If you're deferred and you can't fulfill the read because you don't have
    191   // enough data, you will never fulfill the read.
    192   // Update defer behavior to re-enable deferring if need be.
    193   UpdateDeferBehavior();
    194 
    195   // If we expected the read request to be fulfilled later, returns
    196   // immediately and let more data to flow in.
    197   if (WillFulfillRead())
    198     return;
    199 
    200   // Make a callback to report failure.
    201   DoneRead(net::ERR_CACHE_MISS);
    202 }
    203 
    204 int64 BufferedResourceLoader::GetBufferedPosition() {
    205   if (buffer_.get())
    206     return offset_ + static_cast<int>(buffer_->forward_bytes()) - 1;
    207   return kPositionNotSpecified;
    208 }
    209 
    210 int64 BufferedResourceLoader::content_length() {
    211   return content_length_;
    212 }
    213 
    214 int64 BufferedResourceLoader::instance_size() {
    215   return instance_size_;
    216 }
    217 
    218 bool BufferedResourceLoader::range_supported() {
    219   return range_supported_;
    220 }
    221 
    222 bool BufferedResourceLoader::network_activity() {
    223   return !completed_ && !deferred_;
    224 }
    225 
    226 const GURL& BufferedResourceLoader::url() {
    227   return url_;
    228 }
    229 
    230 void BufferedResourceLoader::SetURLLoaderForTest(WebURLLoader* mock_loader) {
    231   url_loader_.reset(mock_loader);
    232   keep_test_loader_ = true;
    233 }
    234 
    235 /////////////////////////////////////////////////////////////////////////////
    236 // WebKit::WebURLLoaderClient implementation.
    237 void BufferedResourceLoader::willSendRequest(
    238     WebURLLoader* loader,
    239     WebURLRequest& newRequest,
    240     const WebURLResponse& redirectResponse) {
    241 
    242   // The load may have been stopped and |start_callback| is destroyed.
    243   // In this case we shouldn't do anything.
    244   if (!start_callback_.get()) {
    245     // Set the url in the request to an invalid value (empty url).
    246     newRequest.setURL(WebKit::WebURL());
    247     return;
    248   }
    249 
    250   // Only allow |single_origin_| if we haven't seen a different origin yet.
    251   if (single_origin_)
    252     single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin();
    253 
    254   if (!IsProtocolSupportedForMedia(newRequest.url())) {
    255     // Set the url in the request to an invalid value (empty url).
    256     newRequest.setURL(WebKit::WebURL());
    257     DoneStart(net::ERR_ADDRESS_INVALID);
    258     return;
    259   }
    260 
    261   url_ = newRequest.url();
    262 }
    263 
    264 void BufferedResourceLoader::didSendData(
    265     WebURLLoader* loader,
    266     unsigned long long bytes_sent,
    267     unsigned long long total_bytes_to_be_sent) {
    268   NOTIMPLEMENTED();
    269 }
    270 
    271 void BufferedResourceLoader::didReceiveResponse(
    272     WebURLLoader* loader,
    273     const WebURLResponse& response) {
    274 
    275   // The loader may have been stopped and |start_callback| is destroyed.
    276   // In this case we shouldn't do anything.
    277   if (!start_callback_.get())
    278     return;
    279 
    280   bool partial_response = false;
    281 
    282   // We make a strong assumption that when we reach here we have either
    283   // received a response from HTTP/HTTPS protocol or the request was
    284   // successful (in particular range request). So we only verify the partial
    285   // response for HTTP and HTTPS protocol.
    286   if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) {
    287     int error = net::OK;
    288 
    289     // Check to see whether the server supports byte ranges.
    290     std::string accept_ranges =
    291         response.httpHeaderField("Accept-Ranges").utf8();
    292     range_supported_ = (accept_ranges.find("bytes") != std::string::npos);
    293 
    294     partial_response = (response.httpStatusCode() == kHttpPartialContent);
    295 
    296     if (range_requested_) {
    297       // If we have verified the partial response and it is correct, we will
    298       // return net::OK. It's also possible for a server to support range
    299       // requests without advertising Accept-Ranges: bytes.
    300       if (partial_response && VerifyPartialResponse(response))
    301         range_supported_ = true;
    302       else
    303         error = net::ERR_INVALID_RESPONSE;
    304     } else if (response.httpStatusCode() != kHttpOK) {
    305       // We didn't request a range but server didn't reply with "200 OK".
    306       error = net::ERR_FAILED;
    307     }
    308 
    309     if (error != net::OK) {
    310       DoneStart(error);
    311       Stop();
    312       return;
    313     }
    314   } else {
    315     // For any protocol other than HTTP and HTTPS, assume range request is
    316     // always fulfilled.
    317     partial_response = range_requested_;
    318   }
    319 
    320   // Expected content length can be |kPositionNotSpecified|, in that case
    321   // |content_length_| is not specified and this is a streaming response.
    322   content_length_ = response.expectedContentLength();
    323 
    324   // If we have not requested a range, then the size of the instance is equal
    325   // to the content length.
    326   if (!partial_response)
    327     instance_size_ = content_length_;
    328 
    329   // Calls with a successful response.
    330   DoneStart(net::OK);
    331 }
    332 
    333 void BufferedResourceLoader::didReceiveData(
    334     WebURLLoader* loader,
    335     const char* data,
    336     int data_length,
    337     int encoded_data_length) {
    338   DCHECK(!completed_);
    339   DCHECK_GT(data_length, 0);
    340 
    341   // If this loader has been stopped, |buffer_| would be destroyed.
    342   // In this case we shouldn't do anything.
    343   if (!buffer_.get())
    344     return;
    345 
    346   // Writes more data to |buffer_|.
    347   buffer_->Append(reinterpret_cast<const uint8*>(data), data_length);
    348 
    349   // If there is an active read request, try to fulfill the request.
    350   if (HasPendingRead() && CanFulfillRead())
    351     ReadInternal();
    352 
    353   // At last see if the buffer is full and we need to defer the downloading.
    354   UpdateDeferBehavior();
    355 
    356   // Consume excess bytes from our in-memory buffer if necessary.
    357   if (buffer_->forward_bytes() > buffer_->forward_capacity()) {
    358     size_t excess = buffer_->forward_bytes() - buffer_->forward_capacity();
    359     bool success = buffer_->Seek(excess);
    360     DCHECK(success);
    361     offset_ += first_offset_ + excess;
    362   }
    363 
    364   // Notify that we have received some data.
    365   NotifyNetworkEvent();
    366 }
    367 
    368 void BufferedResourceLoader::didDownloadData(
    369     WebKit::WebURLLoader* loader,
    370     int dataLength) {
    371   NOTIMPLEMENTED();
    372 }
    373 
    374 void BufferedResourceLoader::didReceiveCachedMetadata(
    375     WebURLLoader* loader,
    376     const char* data,
    377     int data_length) {
    378   NOTIMPLEMENTED();
    379 }
    380 
    381 void BufferedResourceLoader::didFinishLoading(
    382     WebURLLoader* loader,
    383     double finishTime) {
    384   DCHECK(!completed_);
    385   completed_ = true;
    386 
    387   // If we didn't know the |instance_size_| we do now.
    388   if (instance_size_ == kPositionNotSpecified) {
    389     instance_size_ = offset_ + buffer_->forward_bytes();
    390   }
    391 
    392   // If there is a start callback, calls it.
    393   if (start_callback_.get()) {
    394     DoneStart(net::OK);
    395   }
    396 
    397   // If there is a pending read but the request has ended, returns with what
    398   // we have.
    399   if (HasPendingRead()) {
    400     // Make sure we have a valid buffer before we satisfy a read request.
    401     DCHECK(buffer_.get());
    402 
    403     // Try to fulfill with what is in the buffer.
    404     if (CanFulfillRead())
    405       ReadInternal();
    406     else
    407       DoneRead(net::ERR_CACHE_MISS);
    408   }
    409 
    410   // There must not be any outstanding read request.
    411   DCHECK(!HasPendingRead());
    412 
    413   // Notify that network response is completed.
    414   NotifyNetworkEvent();
    415 
    416   url_loader_.reset();
    417   Release();
    418 }
    419 
    420 void BufferedResourceLoader::didFail(
    421     WebURLLoader* loader,
    422     const WebURLError& error) {
    423   DCHECK(!completed_);
    424   completed_ = true;
    425 
    426   // If there is a start callback, calls it.
    427   if (start_callback_.get()) {
    428     DoneStart(error.reason);
    429   }
    430 
    431   // If there is a pending read but the request failed, return with the
    432   // reason for the error.
    433   if (HasPendingRead()) {
    434     DoneRead(error.reason);
    435   }
    436 
    437   // Notify that network response is completed.
    438   NotifyNetworkEvent();
    439 
    440   url_loader_.reset();
    441   Release();
    442 }
    443 
    444 bool BufferedResourceLoader::HasSingleOrigin() const {
    445   return single_origin_;
    446 }
    447 
    448 /////////////////////////////////////////////////////////////////////////////
    449 // Helper methods.
    450 void BufferedResourceLoader::UpdateDeferBehavior() {
    451   if (!url_loader_.get() || !buffer_.get())
    452     return;
    453 
    454   if ((deferred_ && ShouldDisableDefer()) ||
    455       (!deferred_ && ShouldEnableDefer())) {
    456     bool eventOccurred = ToggleDeferring();
    457     if (eventOccurred)
    458       NotifyNetworkEvent();
    459   }
    460 }
    461 
    462 void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) {
    463   defer_strategy_ = strategy;
    464   UpdateDeferBehavior();
    465 }
    466 
    467 bool BufferedResourceLoader::ShouldEnableDefer() {
    468   // If we're already deferring, then enabling makes no sense.
    469   if (deferred_)
    470     return false;
    471 
    472   switch(defer_strategy_) {
    473     // Never defer at all, so never enable defer.
    474     case kNeverDefer:
    475       return false;
    476 
    477     // Defer if nothing is being requested.
    478     case kReadThenDefer:
    479       return !read_callback_.get();
    480 
    481     // Defer if we've reached the max capacity of the threshold.
    482     case kThresholdDefer:
    483       return buffer_->forward_bytes() >= buffer_->forward_capacity();
    484   }
    485   // Otherwise don't enable defer.
    486   return false;
    487 }
    488 
    489 bool BufferedResourceLoader::ShouldDisableDefer() {
    490   // If we're not deferring, then disabling makes no sense.
    491   if (!deferred_)
    492     return false;
    493 
    494   switch(defer_strategy_) {
    495     // Always disable deferring.
    496     case kNeverDefer:
    497       return true;
    498 
    499     // We have an outstanding read request, and we have not buffered enough
    500     // yet to fulfill the request; disable defer to get more data.
    501     case kReadThenDefer: {
    502       size_t amount_buffered = buffer_->forward_bytes();
    503       size_t amount_to_read = static_cast<size_t>(read_size_);
    504       return read_callback_.get() && amount_buffered < amount_to_read;
    505     }
    506 
    507     // We have less than half the capacity of our threshold, so
    508     // disable defer to get more data.
    509     case kThresholdDefer: {
    510       size_t amount_buffered = buffer_->forward_bytes();
    511       size_t half_capacity = buffer_->forward_capacity() / 2;
    512       return amount_buffered < half_capacity;
    513     }
    514   }
    515 
    516   // Otherwise keep deferring.
    517   return false;
    518 }
    519 
    520 bool BufferedResourceLoader::ToggleDeferring() {
    521   deferred_ = !deferred_;
    522   if (url_loader_.get()) {
    523     url_loader_->setDefersLoading(deferred_);
    524     return true;
    525   }
    526   return false;
    527 }
    528 
    529 bool BufferedResourceLoader::CanFulfillRead() {
    530   // If we are reading too far in the backward direction.
    531   if (first_offset_ < 0 &&
    532       first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0)
    533     return false;
    534 
    535   // If the start offset is too far ahead.
    536   if (first_offset_ >= static_cast<int>(buffer_->forward_bytes()))
    537     return false;
    538 
    539   // At the point, we verified that first byte requested is within the buffer.
    540   // If the request has completed, then just returns with what we have now.
    541   if (completed_)
    542     return true;
    543 
    544   // If the resource request is still active, make sure the whole requested
    545   // range is covered.
    546   if (last_offset_ > static_cast<int>(buffer_->forward_bytes()))
    547     return false;
    548 
    549   return true;
    550 }
    551 
    552 bool BufferedResourceLoader::WillFulfillRead() {
    553   // Reading too far in the backward direction.
    554   if (first_offset_ < 0 &&
    555       first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0)
    556     return false;
    557 
    558   // Try to read too far ahead.
    559   if (last_offset_ > kForwardWaitThreshold)
    560     return false;
    561 
    562   // The resource request has completed, there's no way we can fulfill the
    563   // read request.
    564   if (completed_)
    565     return false;
    566 
    567   return true;
    568 }
    569 
    570 void BufferedResourceLoader::ReadInternal() {
    571   // Seek to the first byte requested.
    572   bool ret = buffer_->Seek(first_offset_);
    573   DCHECK(ret);
    574 
    575   // Then do the read.
    576   int read = static_cast<int>(buffer_->Read(read_buffer_, read_size_));
    577   offset_ += first_offset_ + read;
    578 
    579   // And report with what we have read.
    580   DoneRead(read);
    581 }
    582 
    583 bool BufferedResourceLoader::VerifyPartialResponse(
    584     const WebURLResponse& response) {
    585   int first_byte_position, last_byte_position, instance_size;
    586 
    587   if (!MultipartResponseDelegate::ReadContentRanges(response,
    588                          &first_byte_position,
    589                          &last_byte_position,
    590                          &instance_size)) {
    591     return false;
    592   }
    593 
    594   if (instance_size != kPositionNotSpecified) {
    595     instance_size_ = instance_size;
    596   }
    597 
    598   if (first_byte_position_ != kPositionNotSpecified &&
    599       first_byte_position_ != first_byte_position) {
    600     return false;
    601   }
    602 
    603   // TODO(hclam): I should also check |last_byte_position|, but since
    604   // we will never make such a request that it is ok to leave it unimplemented.
    605   return true;
    606 }
    607 
    608 std::string BufferedResourceLoader::GenerateHeaders(
    609     int64 first_byte_position,
    610     int64 last_byte_position) {
    611   // Construct the value for the range header.
    612   std::string header;
    613   if (first_byte_position > kPositionNotSpecified &&
    614       last_byte_position > kPositionNotSpecified) {
    615     if (first_byte_position <= last_byte_position) {
    616       header = base::StringPrintf("bytes=%" PRId64 "-%" PRId64,
    617                                   first_byte_position,
    618                                   last_byte_position);
    619     }
    620   } else if (first_byte_position > kPositionNotSpecified) {
    621     header = base::StringPrintf("bytes=%" PRId64 "-",
    622                                 first_byte_position);
    623   } else if (last_byte_position > kPositionNotSpecified) {
    624     NOTIMPLEMENTED() << "Suffix range not implemented";
    625   }
    626   return header;
    627 }
    628 
    629 void BufferedResourceLoader::DoneRead(int error) {
    630   read_callback_->RunWithParams(Tuple1<int>(error));
    631   read_callback_.reset();
    632   read_position_ = 0;
    633   read_size_ = 0;
    634   read_buffer_ = NULL;
    635   first_offset_ = 0;
    636   last_offset_ = 0;
    637 }
    638 
    639 void BufferedResourceLoader::DoneStart(int error) {
    640   start_callback_->RunWithParams(Tuple1<int>(error));
    641   start_callback_.reset();
    642 }
    643 
    644 void BufferedResourceLoader::NotifyNetworkEvent() {
    645   if (event_callback_.get())
    646     event_callback_->Run();
    647 }
    648 
    649 bool BufferedResourceLoader::IsRangeRequest() const {
    650   return first_byte_position_ != kPositionNotSpecified;
    651 }
    652 
    653 }  // namespace webkit_glue
    654