OLD | NEW |
| (Empty) |
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/simple_data_source.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/message_loop.h" | |
9 #include "base/process_util.h" | |
10 #include "media/base/filter_host.h" | |
11 #include "media/base/media_log.h" | |
12 #include "net/base/data_url.h" | |
13 #include "net/base/load_flags.h" | |
14 #include "net/http/http_request_headers.h" | |
15 #include "net/url_request/url_request_status.h" | |
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" | |
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKitPlatformSupport
.h" | |
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" | |
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderOptions.h
" | |
20 #include "webkit/glue/media/web_data_source_factory.h" | |
21 #include "webkit/glue/webkit_glue.h" | |
22 | |
23 using WebKit::WebString; | |
24 using WebKit::WebURLLoaderOptions; | |
25 | |
26 namespace webkit_glue { | |
27 | |
28 static const char kDataScheme[] = "data"; | |
29 | |
30 static WebDataSource* NewSimpleDataSource(MessageLoop* render_loop, | |
31 WebKit::WebFrame* frame, | |
32 media::MediaLog* media_log) { | |
33 return new SimpleDataSource(render_loop, frame); | |
34 } | |
35 | |
36 // static | |
37 media::DataSourceFactory* SimpleDataSource::CreateFactory( | |
38 MessageLoop* render_loop, | |
39 WebKit::WebFrame* frame, | |
40 media::MediaLog* media_log, | |
41 const WebDataSourceBuildObserverHack& build_observer) { | |
42 return new WebDataSourceFactory(render_loop, frame, media_log, | |
43 &NewSimpleDataSource, build_observer); | |
44 } | |
45 | |
46 SimpleDataSource::SimpleDataSource( | |
47 MessageLoop* render_loop, | |
48 WebKit::WebFrame* frame) | |
49 : render_loop_(render_loop), | |
50 frame_(frame), | |
51 size_(-1), | |
52 single_origin_(true), | |
53 state_(UNINITIALIZED), | |
54 keep_test_loader_(false) { | |
55 DCHECK(render_loop); | |
56 } | |
57 | |
58 SimpleDataSource::~SimpleDataSource() { | |
59 base::AutoLock auto_lock(lock_); | |
60 DCHECK(state_ == UNINITIALIZED || state_ == STOPPED); | |
61 } | |
62 | |
63 void SimpleDataSource::set_host(media::FilterHost* host) { | |
64 DataSource::set_host(host); | |
65 | |
66 base::AutoLock auto_lock(lock_); | |
67 if (state_ == INITIALIZED) { | |
68 UpdateHostState(); | |
69 } | |
70 } | |
71 | |
72 void SimpleDataSource::Stop(const base::Closure& callback) { | |
73 base::AutoLock auto_lock(lock_); | |
74 state_ = STOPPED; | |
75 if (!callback.is_null()) | |
76 callback.Run(); | |
77 | |
78 // Post a task to the render thread to cancel loading the resource. | |
79 render_loop_->PostTask(FROM_HERE, | |
80 base::Bind(&SimpleDataSource::CancelTask, this)); | |
81 } | |
82 | |
83 void SimpleDataSource::Initialize( | |
84 const std::string& url, | |
85 const media::PipelineStatusCB& callback) { | |
86 // Reference to prevent destruction while inside the |initialize_cb_| | |
87 // call. This is a temporary fix to prevent crashes caused by holding the | |
88 // lock and running the destructor. | |
89 scoped_refptr<SimpleDataSource> destruction_guard(this); | |
90 { | |
91 base::AutoLock auto_lock(lock_); | |
92 DCHECK_EQ(state_, UNINITIALIZED); | |
93 DCHECK(!callback.is_null()); | |
94 state_ = INITIALIZING; | |
95 initialize_cb_ = callback; | |
96 | |
97 // Validate the URL. | |
98 url_ = GURL(url); | |
99 if (!url_.is_valid() || !IsProtocolSupportedForMedia(url_)) { | |
100 DoneInitialization_Locked(false); | |
101 return; | |
102 } | |
103 | |
104 // Post a task to the render thread to start loading the resource. | |
105 render_loop_->PostTask(FROM_HERE, | |
106 base::Bind(&SimpleDataSource::StartTask, this)); | |
107 } | |
108 } | |
109 | |
110 void SimpleDataSource::CancelInitialize() { | |
111 base::AutoLock auto_lock(lock_); | |
112 DCHECK(!initialize_cb_.is_null()); | |
113 state_ = STOPPED; | |
114 initialize_cb_.Reset(); | |
115 | |
116 // Post a task to the render thread to cancel loading the resource. | |
117 render_loop_->PostTask(FROM_HERE, | |
118 base::Bind(&SimpleDataSource::CancelTask, this)); | |
119 } | |
120 | |
121 void SimpleDataSource::Read(int64 position, | |
122 size_t size, | |
123 uint8* data, | |
124 const DataSource::ReadCallback& read_callback) { | |
125 DCHECK_GE(size_, 0); | |
126 if (position >= size_) { | |
127 read_callback.Run(0); | |
128 } else { | |
129 size_t copied = std::min(size, static_cast<size_t>(size_ - position)); | |
130 memcpy(data, data_.c_str() + position, copied); | |
131 read_callback.Run(copied); | |
132 } | |
133 } | |
134 | |
135 bool SimpleDataSource::GetSize(int64* size_out) { | |
136 *size_out = size_; | |
137 return true; | |
138 } | |
139 | |
140 bool SimpleDataSource::IsStreaming() { | |
141 return false; | |
142 } | |
143 | |
144 void SimpleDataSource::SetPreload(media::Preload preload) { | |
145 } | |
146 | |
147 void SimpleDataSource::SetBitrate(int bitrate) { | |
148 } | |
149 | |
150 void SimpleDataSource::SetURLLoaderForTest(WebKit::WebURLLoader* mock_loader) { | |
151 url_loader_.reset(mock_loader); | |
152 keep_test_loader_ = true; | |
153 } | |
154 | |
155 void SimpleDataSource::willSendRequest( | |
156 WebKit::WebURLLoader* loader, | |
157 WebKit::WebURLRequest& newRequest, | |
158 const WebKit::WebURLResponse& redirectResponse) { | |
159 DCHECK(MessageLoop::current() == render_loop_); | |
160 base::AutoLock auto_lock(lock_); | |
161 | |
162 // Only allow |single_origin_| if we haven't seen a different origin yet. | |
163 if (single_origin_) | |
164 single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin(); | |
165 | |
166 url_ = newRequest.url(); | |
167 } | |
168 | |
169 void SimpleDataSource::didSendData( | |
170 WebKit::WebURLLoader* loader, | |
171 unsigned long long bytesSent, | |
172 unsigned long long totalBytesToBeSent) { | |
173 NOTIMPLEMENTED(); | |
174 } | |
175 | |
176 void SimpleDataSource::didReceiveResponse( | |
177 WebKit::WebURLLoader* loader, | |
178 const WebKit::WebURLResponse& response) { | |
179 DCHECK(MessageLoop::current() == render_loop_); | |
180 size_ = response.expectedContentLength(); | |
181 } | |
182 | |
183 void SimpleDataSource::didDownloadData( | |
184 WebKit::WebURLLoader* loader, | |
185 int dataLength) { | |
186 NOTIMPLEMENTED(); | |
187 } | |
188 | |
189 void SimpleDataSource::didReceiveData( | |
190 WebKit::WebURLLoader* loader, | |
191 const char* data, | |
192 int data_length, | |
193 int encoded_data_length) { | |
194 DCHECK(MessageLoop::current() == render_loop_); | |
195 data_.append(data, data_length); | |
196 } | |
197 | |
198 void SimpleDataSource::didReceiveCachedMetadata( | |
199 WebKit::WebURLLoader* loader, | |
200 const char* data, | |
201 int dataLength) { | |
202 NOTIMPLEMENTED(); | |
203 } | |
204 | |
205 void SimpleDataSource::didFinishLoading( | |
206 WebKit::WebURLLoader* loader, | |
207 double finishTime) { | |
208 DCHECK(MessageLoop::current() == render_loop_); | |
209 // Reference to prevent destruction while inside the |initialize_cb_| | |
210 // call. This is a temporary fix to prevent crashes caused by holding the | |
211 // lock and running the destructor. | |
212 scoped_refptr<SimpleDataSource> destruction_guard(this); | |
213 { | |
214 base::AutoLock auto_lock(lock_); | |
215 // It's possible this gets called after Stop(), in which case |host_| is no | |
216 // longer valid. | |
217 if (state_ == STOPPED) | |
218 return; | |
219 | |
220 // Otherwise we should be initializing and have created a WebURLLoader. | |
221 DCHECK_EQ(state_, INITIALIZING); | |
222 | |
223 // If we don't get a content length or the request has failed, report it | |
224 // as a network error. | |
225 if (size_ == -1) | |
226 size_ = data_.length(); | |
227 DCHECK(static_cast<size_t>(size_) == data_.length()); | |
228 | |
229 DoneInitialization_Locked(true); | |
230 } | |
231 } | |
232 | |
233 void SimpleDataSource::didFail( | |
234 WebKit::WebURLLoader* loader, | |
235 const WebKit::WebURLError& error) { | |
236 DCHECK(MessageLoop::current() == render_loop_); | |
237 // Reference to prevent destruction while inside the |initialize_cb_| | |
238 // call. This is a temporary fix to prevent crashes caused by holding the | |
239 // lock and running the destructor. | |
240 scoped_refptr<SimpleDataSource> destruction_guard(this); | |
241 { | |
242 base::AutoLock auto_lock(lock_); | |
243 // It's possible this gets called after Stop(), in which case |host_| is no | |
244 // longer valid. | |
245 if (state_ == STOPPED) | |
246 return; | |
247 | |
248 // Otherwise we should be initializing and have created a WebURLLoader. | |
249 DCHECK_EQ(state_, INITIALIZING); | |
250 | |
251 // If we don't get a content length or the request has failed, report it | |
252 // as a network error. | |
253 if (size_ == -1) | |
254 size_ = data_.length(); | |
255 DCHECK(static_cast<size_t>(size_) == data_.length()); | |
256 | |
257 DoneInitialization_Locked(false); | |
258 } | |
259 } | |
260 | |
261 bool SimpleDataSource::HasSingleOrigin() { | |
262 DCHECK(MessageLoop::current() == render_loop_); | |
263 return single_origin_; | |
264 } | |
265 | |
266 void SimpleDataSource::Abort() { | |
267 DCHECK(MessageLoop::current() == render_loop_); | |
268 frame_ = NULL; | |
269 } | |
270 | |
271 void SimpleDataSource::StartTask() { | |
272 DCHECK(MessageLoop::current() == render_loop_); | |
273 // Reference to prevent destruction while inside the |initialize_cb_| | |
274 // call. This is a temporary fix to prevent crashes caused by holding the | |
275 // lock and running the destructor. | |
276 scoped_refptr<SimpleDataSource> destruction_guard(this); | |
277 { | |
278 base::AutoLock auto_lock(lock_); | |
279 | |
280 // We may have stopped. | |
281 if (state_ == STOPPED) | |
282 return; | |
283 | |
284 CHECK(frame_); | |
285 | |
286 DCHECK_EQ(state_, INITIALIZING); | |
287 | |
288 if (url_.SchemeIs(kDataScheme)) { | |
289 // If this using data protocol, we just need to decode it. | |
290 std::string mime_type, charset; | |
291 bool success = net::DataURL::Parse(url_, &mime_type, &charset, &data_); | |
292 | |
293 // Don't care about the mime-type just proceed if decoding was successful. | |
294 size_ = data_.length(); | |
295 DoneInitialization_Locked(success); | |
296 } else { | |
297 // Prepare the request. | |
298 WebKit::WebURLRequest request(url_); | |
299 request.setTargetType(WebKit::WebURLRequest::TargetIsMedia); | |
300 | |
301 frame_->setReferrerForRequest(request, WebKit::WebURL()); | |
302 | |
303 // Disable compression, compression for audio/video doesn't make sense... | |
304 request.setHTTPHeaderField( | |
305 WebString::fromUTF8(net::HttpRequestHeaders::kAcceptEncoding), | |
306 WebString::fromUTF8("identity;q=1, *;q=0")); | |
307 | |
308 // This flag is for unittests as we don't want to reset |url_loader| | |
309 if (!keep_test_loader_) { | |
310 WebURLLoaderOptions options; | |
311 options.allowCredentials = true; | |
312 options.crossOriginRequestPolicy = | |
313 WebURLLoaderOptions::CrossOriginRequestPolicyAllow; | |
314 url_loader_.reset(frame_->createAssociatedURLLoader(options)); | |
315 } | |
316 | |
317 // Start the resource loading. | |
318 url_loader_->loadAsynchronously(request, this); | |
319 } | |
320 } | |
321 } | |
322 | |
323 void SimpleDataSource::CancelTask() { | |
324 DCHECK(MessageLoop::current() == render_loop_); | |
325 base::AutoLock auto_lock(lock_); | |
326 DCHECK_EQ(state_, STOPPED); | |
327 | |
328 // Cancel any pending requests. | |
329 if (url_loader_.get()) { | |
330 url_loader_->cancel(); | |
331 url_loader_.reset(); | |
332 } | |
333 } | |
334 | |
335 void SimpleDataSource::DoneInitialization_Locked(bool success) { | |
336 lock_.AssertAcquired(); | |
337 media::PipelineStatus status = media::PIPELINE_ERROR_NETWORK; | |
338 if (success) { | |
339 state_ = INITIALIZED; | |
340 | |
341 UpdateHostState(); | |
342 status = media::PIPELINE_OK; | |
343 } else { | |
344 state_ = UNINITIALIZED; | |
345 url_loader_.reset(); | |
346 } | |
347 | |
348 initialize_cb_.Run(status); | |
349 initialize_cb_.Reset(); | |
350 } | |
351 | |
352 void SimpleDataSource::UpdateHostState() { | |
353 if (host()) { | |
354 host()->SetTotalBytes(size_); | |
355 host()->SetBufferedBytes(size_); | |
356 // If scheme is file or data, say we are loaded. | |
357 host()->SetLoaded(url_.SchemeIsFile() || url_.SchemeIs(kDataScheme)); | |
358 } | |
359 } | |
360 | |
361 } // namespace webkit_glue | |
OLD | NEW |