| 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 |