simple_data_source.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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/WebKit/chromium/public/WebKit.h" 14#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h" 15#include "webkit/glue/webkit_glue.h" 16 17namespace { 18 19const char kDataScheme[] = "data"; 20 21} // namespace 22 23namespace webkit_glue { 24 25SimpleDataSource::SimpleDataSource( 26 MessageLoop* render_loop, 27 WebKit::WebFrame* frame) 28 : render_loop_(render_loop), 29 frame_(frame), 30 size_(-1), 31 single_origin_(true), 32 state_(UNINITIALIZED), 33 keep_test_loader_(false) { 34 DCHECK(render_loop); 35} 36 37SimpleDataSource::~SimpleDataSource() { 38 AutoLock auto_lock(lock_); 39 DCHECK(state_ == UNINITIALIZED || state_ == STOPPED); 40} 41 42void SimpleDataSource::Stop(media::FilterCallback* callback) { 43 AutoLock auto_lock(lock_); 44 state_ = STOPPED; 45 if (callback) { 46 callback->Run(); 47 delete callback; 48 } 49 50 // Post a task to the render thread to cancel loading the resource. 51 render_loop_->PostTask(FROM_HERE, 52 NewRunnableMethod(this, &SimpleDataSource::CancelTask)); 53} 54 55void SimpleDataSource::Initialize(const std::string& url, 56 media::FilterCallback* callback) { 57 AutoLock auto_lock(lock_); 58 DCHECK_EQ(state_, UNINITIALIZED); 59 DCHECK(callback); 60 state_ = INITIALIZING; 61 initialize_callback_.reset(callback); 62 63 // Validate the URL. 64 SetURL(GURL(url)); 65 if (!url_.is_valid() || !IsProtocolSupportedForMedia(url_)) { 66 host()->SetError(media::PIPELINE_ERROR_NETWORK); 67 initialize_callback_->Run(); 68 initialize_callback_.reset(); 69 return; 70 } 71 72 // Post a task to the render thread to start loading the resource. 73 render_loop_->PostTask(FROM_HERE, 74 NewRunnableMethod(this, &SimpleDataSource::StartTask)); 75} 76 77const media::MediaFormat& SimpleDataSource::media_format() { 78 return media_format_; 79} 80 81void SimpleDataSource::Read(int64 position, 82 size_t size, 83 uint8* data, 84 ReadCallback* read_callback) { 85 DCHECK_GE(size_, 0); 86 if (position >= size_) { 87 read_callback->RunWithParams(Tuple1<size_t>(0)); 88 delete read_callback; 89 } else { 90 size_t copied = std::min(size, static_cast<size_t>(size_ - position)); 91 memcpy(data, data_.c_str() + position, copied); 92 read_callback->RunWithParams(Tuple1<size_t>(copied)); 93 delete read_callback; 94 } 95} 96 97bool SimpleDataSource::GetSize(int64* size_out) { 98 *size_out = size_; 99 return true; 100} 101 102bool SimpleDataSource::IsStreaming() { 103 return false; 104} 105 106void SimpleDataSource::SetURLLoaderForTest(WebKit::WebURLLoader* mock_loader) { 107 url_loader_.reset(mock_loader); 108 keep_test_loader_ = true; 109} 110 111void SimpleDataSource::willSendRequest( 112 WebKit::WebURLLoader* loader, 113 WebKit::WebURLRequest& newRequest, 114 const WebKit::WebURLResponse& redirectResponse) { 115 DCHECK(MessageLoop::current() == render_loop_); 116 single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin(); 117 118 url_ = newRequest.url(); 119} 120 121void SimpleDataSource::didSendData( 122 WebKit::WebURLLoader* loader, 123 unsigned long long bytesSent, 124 unsigned long long totalBytesToBeSent) { 125 NOTIMPLEMENTED(); 126} 127 128void SimpleDataSource::didReceiveResponse( 129 WebKit::WebURLLoader* loader, 130 const WebKit::WebURLResponse& response) { 131 DCHECK(MessageLoop::current() == render_loop_); 132 size_ = response.expectedContentLength(); 133} 134 135void SimpleDataSource::didDownloadData( 136 WebKit::WebURLLoader* loader, 137 int dataLength) { 138 NOTIMPLEMENTED(); 139} 140 141void SimpleDataSource::didReceiveData( 142 WebKit::WebURLLoader* loader, 143 const char* data, 144 int data_length) { 145 DCHECK(MessageLoop::current() == render_loop_); 146 data_.append(data, data_length); 147} 148 149void SimpleDataSource::didReceiveCachedMetadata( 150 WebKit::WebURLLoader* loader, 151 const char* data, 152 int dataLength) { 153 NOTIMPLEMENTED(); 154} 155 156void SimpleDataSource::didFinishLoading( 157 WebKit::WebURLLoader* loader, 158 double finishTime) { 159 DCHECK(MessageLoop::current() == render_loop_); 160 AutoLock auto_lock(lock_); 161 // It's possible this gets called after Stop(), in which case |host_| is no 162 // longer valid. 163 if (state_ == STOPPED) 164 return; 165 166 // Otherwise we should be initializing and have created a WebURLLoader. 167 DCHECK_EQ(state_, INITIALIZING); 168 169 // If we don't get a content length or the request has failed, report it 170 // as a network error. 171 if (size_ == -1) 172 size_ = data_.length(); 173 DCHECK(static_cast<size_t>(size_) == data_.length()); 174 175 DoneInitialization_Locked(true); 176} 177 178void SimpleDataSource::didFail( 179 WebKit::WebURLLoader* loader, 180 const WebKit::WebURLError& error) { 181 DCHECK(MessageLoop::current() == render_loop_); 182 AutoLock auto_lock(lock_); 183 // It's possible this gets called after Stop(), in which case |host_| is no 184 // longer valid. 185 if (state_ == STOPPED) 186 return; 187 188 // Otherwise we should be initializing and have created a WebURLLoader. 189 DCHECK_EQ(state_, INITIALIZING); 190 191 // If we don't get a content length or the request has failed, report it 192 // as a network error. 193 if (size_ == -1) 194 size_ = data_.length(); 195 DCHECK(static_cast<size_t>(size_) == data_.length()); 196 197 DoneInitialization_Locked(false); 198} 199 200bool SimpleDataSource::HasSingleOrigin() { 201 DCHECK(MessageLoop::current() == render_loop_); 202 return single_origin_; 203} 204 205void SimpleDataSource::Abort() { 206 DCHECK(MessageLoop::current() == render_loop_); 207 frame_ = NULL; 208} 209 210void SimpleDataSource::SetURL(const GURL& url) { 211 url_ = url; 212 media_format_.Clear(); 213 media_format_.SetAsString(media::MediaFormat::kMimeType, 214 media::mime_type::kApplicationOctetStream); 215 media_format_.SetAsString(media::MediaFormat::kURL, url.spec()); 216} 217 218void SimpleDataSource::StartTask() { 219 DCHECK(MessageLoop::current() == render_loop_); 220 AutoLock auto_lock(lock_); 221 222 // We may have stopped. 223 if (state_ == STOPPED) 224 return; 225 226 CHECK(frame_); 227 228 DCHECK_EQ(state_, INITIALIZING); 229 230 if (url_.SchemeIs(kDataScheme)) { 231 // If this using data protocol, we just need to decode it. 232 std::string mime_type, charset; 233 bool success = net::DataURL::Parse(url_, &mime_type, &charset, &data_); 234 235 // Don't care about the mime-type just proceed if decoding was successful. 236 size_ = data_.length(); 237 DoneInitialization_Locked(success); 238 } else { 239 // Prepare the request. 240 WebKit::WebURLRequest request(url_); 241 request.setTargetType(WebKit::WebURLRequest::TargetIsMedia); 242 243 frame_->setReferrerForRequest(request, WebKit::WebURL()); 244 245 // This flag is for unittests as we don't want to reset |url_loader| 246 if (!keep_test_loader_) 247 url_loader_.reset(frame_->createAssociatedURLLoader()); 248 249 // Start the resource loading. 250 url_loader_->loadAsynchronously(request, this); 251 } 252} 253 254void SimpleDataSource::CancelTask() { 255 DCHECK(MessageLoop::current() == render_loop_); 256 AutoLock auto_lock(lock_); 257 DCHECK_EQ(state_, STOPPED); 258 259 // Cancel any pending requests. 260 if (url_loader_.get()) { 261 url_loader_->cancel(); 262 url_loader_.reset(); 263 } 264} 265 266void SimpleDataSource::DoneInitialization_Locked(bool success) { 267 lock_.AssertAcquired(); 268 if (success) { 269 state_ = INITIALIZED; 270 host()->SetTotalBytes(size_); 271 host()->SetBufferedBytes(size_); 272 // If scheme is file or data, say we are loaded. 273 host()->SetLoaded(url_.SchemeIsFile() || url_.SchemeIs(kDataScheme)); 274 } else { 275 host()->SetError(media::PIPELINE_ERROR_NETWORK); 276 } 277 initialize_callback_->Run(); 278 initialize_callback_.reset(); 279} 280 281} // namespace webkit_glue 282