• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
MediaInfoLoader(const GURL & url,blink::WebMediaPlayer::CORSMode cors_mode,const ReadyCB & ready_cb)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 
~MediaInfoLoader()38 MediaInfoLoader::~MediaInfoLoader() {}
39 
Start(blink::WebFrame * frame)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.
willSendRequest(WebURLLoader * loader,WebURLRequest & newRequest,const WebURLResponse & redirectResponse)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 
didSendData(WebURLLoader * loader,unsigned long long bytes_sent,unsigned long long total_bytes_to_be_sent)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 
didReceiveResponse(WebURLLoader * loader,const WebURLResponse & response)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 
didReceiveData(WebURLLoader * loader,const char * data,int data_length,int encoded_data_length)142 void MediaInfoLoader::didReceiveData(
143     WebURLLoader* loader,
144     const char* data,
145     int data_length,
146     int encoded_data_length) {
147   // Ignored.
148 }
149 
didDownloadData(blink::WebURLLoader * loader,int dataLength,int encodedDataLength)150 void MediaInfoLoader::didDownloadData(
151     blink::WebURLLoader* loader,
152     int dataLength,
153     int encodedDataLength) {
154   NOTIMPLEMENTED();
155 }
156 
didReceiveCachedMetadata(WebURLLoader * loader,const char * data,int data_length)157 void MediaInfoLoader::didReceiveCachedMetadata(
158     WebURLLoader* loader,
159     const char* data,
160     int data_length) {
161   NOTIMPLEMENTED();
162 }
163 
didFinishLoading(WebURLLoader * loader,double finishTime,int64_t total_encoded_data_length)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 
didFail(WebURLLoader * loader,const WebURLError & error)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 
HasSingleOrigin() const185 bool MediaInfoLoader::HasSingleOrigin() const {
186   DCHECK(ready_cb_.is_null())
187       << "Must become ready before calling HasSingleOrigin()";
188   return single_origin_;
189 }
190 
DidPassCORSAccessCheck() const191 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 
DidBecomeReady(Status status)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