Home | History | Annotate | Download | only in android
      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/android/media_info_loader.h"
      6 
      7 #include "base/bits.h"
      8 #include "base/callback_helpers.h"
      9 #include "base/metrics/histogram.h"
     10 #include "third_party/WebKit/public/platform/WebURLError.h"
     11 #include "third_party/WebKit/public/platform/WebURLLoader.h"
     12 #include "third_party/WebKit/public/platform/WebURLResponse.h"
     13 #include "third_party/WebKit/public/web/WebFrame.h"
     14 
     15 using blink::WebFrame;
     16 using blink::WebURLError;
     17 using blink::WebURLLoader;
     18 using blink::WebURLLoaderOptions;
     19 using blink::WebURLRequest;
     20 using blink::WebURLResponse;
     21 
     22 namespace content {
     23 
     24 static const int kHttpOK = 200;
     25 static const int kHttpPartialContentOK = 206;
     26 
     27 MediaInfoLoader::MediaInfoLoader(
     28     const GURL& url,
     29     blink::WebMediaPlayer::CORSMode cors_mode,
     30     const ReadyCB& ready_cb)
     31     : loader_failed_(false),
     32       url_(url),
     33       allow_stored_credentials_(false),
     34       cors_mode_(cors_mode),
     35       single_origin_(true),
     36       ready_cb_(ready_cb) {}
     37 
     38 MediaInfoLoader::~MediaInfoLoader() {}
     39 
     40 void MediaInfoLoader::Start(blink::WebFrame* frame) {
     41   // Make sure we have not started.
     42   DCHECK(!ready_cb_.is_null());
     43   CHECK(frame);
     44 
     45   start_time_ = base::TimeTicks::Now();
     46   first_party_url_ = frame->document().firstPartyForCookies();
     47 
     48   // Prepare the request.
     49   WebURLRequest request(url_);
     50   // TODO(mkwst): Split this into video/audio.
     51   request.setRequestContext(WebURLRequest::RequestContextVideo);
     52   frame->setReferrerForRequest(request, blink::WebURL());
     53 
     54   // Since we don't actually care about the media data at this time, use a two
     55   // byte range request to avoid unnecessarily downloading resources.  Not all
     56   // servers support HEAD unfortunately, so use a range request; which is no
     57   // worse than the previous request+cancel code.  See http://crbug.com/400788
     58   request.addHTTPHeaderField("Range", "bytes=0-1");
     59 
     60   scoped_ptr<WebURLLoader> loader;
     61   if (test_loader_) {
     62     loader = test_loader_.Pass();
     63   } else {
     64     WebURLLoaderOptions options;
     65     if (cors_mode_ == blink::WebMediaPlayer::CORSModeUnspecified) {
     66       options.allowCredentials = true;
     67       options.crossOriginRequestPolicy =
     68           WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
     69       allow_stored_credentials_ = true;
     70     } else {
     71       options.exposeAllResponseHeaders = true;
     72       // The author header set is empty, no preflight should go ahead.
     73       options.preflightPolicy = WebURLLoaderOptions::PreventPreflight;
     74       options.crossOriginRequestPolicy =
     75           WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
     76       if (cors_mode_ == blink::WebMediaPlayer::CORSModeUseCredentials) {
     77         options.allowCredentials = true;
     78         allow_stored_credentials_ = true;
     79       }
     80     }
     81     loader.reset(frame->createAssociatedURLLoader(options));
     82   }
     83 
     84   // Start the resource loading.
     85   loader->loadAsynchronously(request, this);
     86   active_loader_.reset(new media::ActiveLoader(loader.Pass()));
     87 }
     88 
     89 /////////////////////////////////////////////////////////////////////////////
     90 // blink::WebURLLoaderClient implementation.
     91 void MediaInfoLoader::willSendRequest(
     92     WebURLLoader* loader,
     93     WebURLRequest& newRequest,
     94     const WebURLResponse& redirectResponse) {
     95   // The load may have been stopped and |ready_cb| is destroyed.
     96   // In this case we shouldn't do anything.
     97   if (ready_cb_.is_null()) {
     98     // Set the url in the request to an invalid value (empty url).
     99     newRequest.setURL(blink::WebURL());
    100     return;
    101   }
    102 
    103   // Only allow |single_origin_| if we haven't seen a different origin yet.
    104   if (single_origin_)
    105     single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin();
    106 
    107   url_ = newRequest.url();
    108   first_party_url_ = newRequest.firstPartyForCookies();
    109   allow_stored_credentials_ = newRequest.allowStoredCredentials();
    110 }
    111 
    112 void MediaInfoLoader::didSendData(
    113     WebURLLoader* loader,
    114     unsigned long long bytes_sent,
    115     unsigned long long total_bytes_to_be_sent) {
    116   NOTIMPLEMENTED();
    117 }
    118 
    119 void MediaInfoLoader::didReceiveResponse(
    120     WebURLLoader* loader,
    121     const WebURLResponse& response) {
    122   DVLOG(1) << "didReceiveResponse: HTTP/"
    123            << (response.httpVersion() == WebURLResponse::HTTP_0_9 ? "0.9" :
    124                response.httpVersion() == WebURLResponse::HTTP_1_0 ? "1.0" :
    125                response.httpVersion() == WebURLResponse::HTTP_1_1 ? "1.1" :
    126                "Unknown")
    127            << " " << response.httpStatusCode();
    128   DCHECK(active_loader_.get());
    129   if (!url_.SchemeIs(url::kHttpScheme) && !url_.SchemeIs(url::kHttpsScheme)) {
    130       DidBecomeReady(kOk);
    131       return;
    132   }
    133   if (response.httpStatusCode() == kHttpOK ||
    134       response.httpStatusCode() == kHttpPartialContentOK) {
    135     DidBecomeReady(kOk);
    136     return;
    137   }
    138   loader_failed_ = true;
    139   DidBecomeReady(kFailed);
    140 }
    141 
    142 void MediaInfoLoader::didReceiveData(
    143     WebURLLoader* loader,
    144     const char* data,
    145     int data_length,
    146     int encoded_data_length) {
    147   // Ignored.
    148 }
    149 
    150 void MediaInfoLoader::didDownloadData(
    151     blink::WebURLLoader* loader,
    152     int dataLength,
    153     int encodedDataLength) {
    154   NOTIMPLEMENTED();
    155 }
    156 
    157 void MediaInfoLoader::didReceiveCachedMetadata(
    158     WebURLLoader* loader,
    159     const char* data,
    160     int data_length) {
    161   NOTIMPLEMENTED();
    162 }
    163 
    164 void MediaInfoLoader::didFinishLoading(
    165     WebURLLoader* loader,
    166     double finishTime,
    167     int64_t total_encoded_data_length) {
    168   DCHECK(active_loader_.get());
    169   DidBecomeReady(kOk);
    170 }
    171 
    172 void MediaInfoLoader::didFail(
    173     WebURLLoader* loader,
    174     const WebURLError& error) {
    175   DVLOG(1) << "didFail: reason=" << error.reason
    176            << ", isCancellation=" << error.isCancellation
    177            << ", domain=" << error.domain.utf8().data()
    178            << ", localizedDescription="
    179            << error.localizedDescription.utf8().data();
    180   DCHECK(active_loader_.get());
    181   loader_failed_ = true;
    182   DidBecomeReady(kFailed);
    183 }
    184 
    185 bool MediaInfoLoader::HasSingleOrigin() const {
    186   DCHECK(ready_cb_.is_null())
    187       << "Must become ready before calling HasSingleOrigin()";
    188   return single_origin_;
    189 }
    190 
    191 bool MediaInfoLoader::DidPassCORSAccessCheck() const {
    192   DCHECK(ready_cb_.is_null())
    193       << "Must become ready before calling DidPassCORSAccessCheck()";
    194   return !loader_failed_ &&
    195       cors_mode_ != blink::WebMediaPlayer::CORSModeUnspecified;
    196 }
    197 
    198 /////////////////////////////////////////////////////////////////////////////
    199 // Helper methods.
    200 
    201 void MediaInfoLoader::DidBecomeReady(Status status) {
    202   UMA_HISTOGRAM_TIMES("Media.InfoLoadDelay",
    203                       base::TimeTicks::Now() - start_time_);
    204   active_loader_.reset();
    205   if (!ready_cb_.is_null())
    206     base::ResetAndReturn(&ready_cb_).Run(status, url_, first_party_url_,
    207                                          allow_stored_credentials_);
    208 }
    209 
    210 }  // namespace content
    211