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
MediaInfoLoader(const GURL & url,blink::WebMediaPlayer::CORSMode cors_mode,const ReadyCB & ready_cb)26 MediaInfoLoader::MediaInfoLoader(
27 const GURL& url,
28 blink::WebMediaPlayer::CORSMode cors_mode,
29 const ReadyCB& ready_cb)
30 : loader_failed_(false),
31 url_(url),
32 cors_mode_(cors_mode),
33 single_origin_(true),
34 ready_cb_(ready_cb) {}
35
~MediaInfoLoader()36 MediaInfoLoader::~MediaInfoLoader() {}
37
Start(blink::WebFrame * frame)38 void MediaInfoLoader::Start(blink::WebFrame* frame) {
39 // Make sure we have not started.
40 DCHECK(!ready_cb_.is_null());
41 CHECK(frame);
42
43 start_time_ = base::TimeTicks::Now();
44
45 // Prepare the request.
46 WebURLRequest request(url_);
47 request.setTargetType(WebURLRequest::TargetIsMedia);
48 frame->setReferrerForRequest(request, blink::WebURL());
49
50 scoped_ptr<WebURLLoader> loader;
51 if (test_loader_) {
52 loader = test_loader_.Pass();
53 } else {
54 WebURLLoaderOptions options;
55 if (cors_mode_ == blink::WebMediaPlayer::CORSModeUnspecified) {
56 options.allowCredentials = true;
57 options.crossOriginRequestPolicy =
58 WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
59 } else {
60 options.exposeAllResponseHeaders = true;
61 // The author header set is empty, no preflight should go ahead.
62 options.preflightPolicy = WebURLLoaderOptions::PreventPreflight;
63 options.crossOriginRequestPolicy =
64 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
65 if (cors_mode_ == blink::WebMediaPlayer::CORSModeUseCredentials)
66 options.allowCredentials = true;
67 }
68 loader.reset(frame->createAssociatedURLLoader(options));
69 }
70
71 // Start the resource loading.
72 loader->loadAsynchronously(request, this);
73 active_loader_.reset(new ActiveLoader(loader.Pass()));
74 }
75
76 /////////////////////////////////////////////////////////////////////////////
77 // blink::WebURLLoaderClient implementation.
willSendRequest(WebURLLoader * loader,WebURLRequest & newRequest,const WebURLResponse & redirectResponse)78 void MediaInfoLoader::willSendRequest(
79 WebURLLoader* loader,
80 WebURLRequest& newRequest,
81 const WebURLResponse& redirectResponse) {
82 // The load may have been stopped and |ready_cb| is destroyed.
83 // In this case we shouldn't do anything.
84 if (ready_cb_.is_null()) {
85 // Set the url in the request to an invalid value (empty url).
86 newRequest.setURL(blink::WebURL());
87 return;
88 }
89
90 // Only allow |single_origin_| if we haven't seen a different origin yet.
91 if (single_origin_)
92 single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin();
93
94 url_ = newRequest.url();
95 }
96
didSendData(WebURLLoader * loader,unsigned long long bytes_sent,unsigned long long total_bytes_to_be_sent)97 void MediaInfoLoader::didSendData(
98 WebURLLoader* loader,
99 unsigned long long bytes_sent,
100 unsigned long long total_bytes_to_be_sent) {
101 NOTIMPLEMENTED();
102 }
103
didReceiveResponse(WebURLLoader * loader,const WebURLResponse & response)104 void MediaInfoLoader::didReceiveResponse(
105 WebURLLoader* loader,
106 const WebURLResponse& response) {
107 DVLOG(1) << "didReceiveResponse: HTTP/"
108 << (response.httpVersion() == WebURLResponse::HTTP_0_9 ? "0.9" :
109 response.httpVersion() == WebURLResponse::HTTP_1_0 ? "1.0" :
110 response.httpVersion() == WebURLResponse::HTTP_1_1 ? "1.1" :
111 "Unknown")
112 << " " << response.httpStatusCode();
113 DCHECK(active_loader_.get());
114 if (!url_.SchemeIs("http") && !url_.SchemeIs("https")) {
115 DidBecomeReady(kOk);
116 return;
117 }
118 if (response.httpStatusCode() == kHttpOK) {
119 DidBecomeReady(kOk);
120 return;
121 }
122 loader_failed_ = true;
123 DidBecomeReady(kFailed);
124 }
125
didReceiveData(WebURLLoader * loader,const char * data,int data_length,int encoded_data_length)126 void MediaInfoLoader::didReceiveData(
127 WebURLLoader* loader,
128 const char* data,
129 int data_length,
130 int encoded_data_length) {
131 // Ignored.
132 }
133
didDownloadData(blink::WebURLLoader * loader,int dataLength,int encodedDataLength)134 void MediaInfoLoader::didDownloadData(
135 blink::WebURLLoader* loader,
136 int dataLength,
137 int encodedDataLength) {
138 NOTIMPLEMENTED();
139 }
140
didReceiveCachedMetadata(WebURLLoader * loader,const char * data,int data_length)141 void MediaInfoLoader::didReceiveCachedMetadata(
142 WebURLLoader* loader,
143 const char* data,
144 int data_length) {
145 NOTIMPLEMENTED();
146 }
147
didFinishLoading(WebURLLoader * loader,double finishTime)148 void MediaInfoLoader::didFinishLoading(
149 WebURLLoader* loader,
150 double finishTime) {
151 DCHECK(active_loader_.get());
152 DidBecomeReady(kOk);
153 }
154
didFail(WebURLLoader * loader,const WebURLError & error)155 void MediaInfoLoader::didFail(
156 WebURLLoader* loader,
157 const WebURLError& error) {
158 DVLOG(1) << "didFail: reason=" << error.reason
159 << ", isCancellation=" << error.isCancellation
160 << ", domain=" << error.domain.utf8().data()
161 << ", localizedDescription="
162 << error.localizedDescription.utf8().data();
163 DCHECK(active_loader_.get());
164 loader_failed_ = true;
165 DidBecomeReady(kFailed);
166 }
167
HasSingleOrigin() const168 bool MediaInfoLoader::HasSingleOrigin() const {
169 DCHECK(ready_cb_.is_null())
170 << "Must become ready before calling HasSingleOrigin()";
171 return single_origin_;
172 }
173
DidPassCORSAccessCheck() const174 bool MediaInfoLoader::DidPassCORSAccessCheck() const {
175 DCHECK(ready_cb_.is_null())
176 << "Must become ready before calling DidPassCORSAccessCheck()";
177 return !loader_failed_ &&
178 cors_mode_ != blink::WebMediaPlayer::CORSModeUnspecified;
179 }
180
181 /////////////////////////////////////////////////////////////////////////////
182 // Helper methods.
183
DidBecomeReady(Status status)184 void MediaInfoLoader::DidBecomeReady(Status status) {
185 UMA_HISTOGRAM_TIMES("Media.InfoLoadDelay",
186 base::TimeTicks::Now() - start_time_);
187 active_loader_.reset();
188 if (!ready_cb_.is_null())
189 base::ResetAndReturn(&ready_cb_).Run(status);
190 }
191
192 } // namespace content
193