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.
5 #include "content/renderer/media/android/media_info_loader.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"
15 using blink::WebFrame
;
16 using blink::WebURLError
;
17 using blink::WebURLLoader
;
18 using blink::WebURLLoaderOptions
;
19 using blink::WebURLRequest
;
20 using blink::WebURLResponse
;
24 static const int kHttpOK
= 200;
25 static const int kHttpPartialContentOK
= 206;
27 MediaInfoLoader::MediaInfoLoader(
29 blink::WebMediaPlayer::CORSMode cors_mode
,
30 const ReadyCB
& ready_cb
)
31 : loader_failed_(false),
33 allow_stored_credentials_(false),
34 cors_mode_(cors_mode
),
36 ready_cb_(ready_cb
) {}
38 MediaInfoLoader::~MediaInfoLoader() {}
40 void MediaInfoLoader::Start(blink::WebFrame
* frame
) {
41 // Make sure we have not started.
42 DCHECK(!ready_cb_
.is_null());
45 start_time_
= base::TimeTicks::Now();
46 first_party_url_
= frame
->document().firstPartyForCookies();
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());
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");
60 scoped_ptr
<WebURLLoader
> loader
;
62 loader
= test_loader_
.Pass();
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;
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;
81 loader
.reset(frame
->createAssociatedURLLoader(options
));
84 // Start the resource loading.
85 loader
->loadAsynchronously(request
, this);
86 active_loader_
.reset(new media::ActiveLoader(loader
.Pass()));
89 /////////////////////////////////////////////////////////////////////////////
90 // blink::WebURLLoaderClient implementation.
91 void MediaInfoLoader::willSendRequest(
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());
103 // Only allow |single_origin_| if we haven't seen a different origin yet.
105 single_origin_
= url_
.GetOrigin() == GURL(newRequest
.url()).GetOrigin();
107 url_
= newRequest
.url();
108 first_party_url_
= newRequest
.firstPartyForCookies();
109 allow_stored_credentials_
= newRequest
.allowStoredCredentials();
112 void MediaInfoLoader::didSendData(
113 WebURLLoader
* loader
,
114 unsigned long long bytes_sent
,
115 unsigned long long total_bytes_to_be_sent
) {
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" :
127 << " " << response
.httpStatusCode();
128 DCHECK(active_loader_
.get());
129 if (!url_
.SchemeIs(url::kHttpScheme
) && !url_
.SchemeIs(url::kHttpsScheme
)) {
133 if (response
.httpStatusCode() == kHttpOK
||
134 response
.httpStatusCode() == kHttpPartialContentOK
) {
138 loader_failed_
= true;
139 DidBecomeReady(kFailed
);
142 void MediaInfoLoader::didReceiveData(
143 WebURLLoader
* loader
,
146 int encoded_data_length
) {
150 void MediaInfoLoader::didDownloadData(
151 blink::WebURLLoader
* loader
,
153 int encodedDataLength
) {
157 void MediaInfoLoader::didReceiveCachedMetadata(
158 WebURLLoader
* loader
,
164 void MediaInfoLoader::didFinishLoading(
165 WebURLLoader
* loader
,
167 int64_t total_encoded_data_length
) {
168 DCHECK(active_loader_
.get());
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
);
185 bool MediaInfoLoader::HasSingleOrigin() const {
186 DCHECK(ready_cb_
.is_null())
187 << "Must become ready before calling HasSingleOrigin()";
188 return single_origin_
;
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
;
198 /////////////////////////////////////////////////////////////////////////////
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_
);
210 } // namespace content