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