simple_data_source.cc revision 513209b27ff55e2841eac0e4120199c23acce758
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 "base/message_loop.h" 6#include "base/process_util.h" 7#include "media/base/filter_host.h" 8#include "net/base/load_flags.h" 9#include "net/base/data_url.h" 10#include "net/http/http_response_headers.h" 11#include "net/url_request/url_request_status.h" 12#include "webkit/glue/media/simple_data_source.h" 13#include "webkit/glue/resource_loader_bridge.h" 14#include "webkit/glue/webkit_glue.h" 15 16namespace { 17 18const char kHttpScheme[] = "http"; 19const char kHttpsScheme[] = "https"; 20const char kDataScheme[] = "data"; 21 22// A helper method that accepts only HTTP, HTTPS and FILE protocol. 23bool IsDataProtocol(const GURL& url) { 24 return url.SchemeIs(kDataScheme); 25} 26 27} // namespace 28 29namespace webkit_glue { 30 31SimpleDataSource::SimpleDataSource( 32 MessageLoop* render_loop, 33 webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory) 34 : render_loop_(render_loop), 35 bridge_factory_(bridge_factory), 36 size_(-1), 37 single_origin_(true), 38 state_(UNINITIALIZED) { 39 DCHECK(render_loop); 40} 41 42SimpleDataSource::~SimpleDataSource() { 43 AutoLock auto_lock(lock_); 44 DCHECK(state_ == UNINITIALIZED || state_ == STOPPED); 45} 46 47void SimpleDataSource::Stop(media::FilterCallback* callback) { 48 AutoLock auto_lock(lock_); 49 state_ = STOPPED; 50 if (callback) { 51 callback->Run(); 52 delete callback; 53 } 54 55 // Post a task to the render thread to cancel loading the resource. 56 render_loop_->PostTask(FROM_HERE, 57 NewRunnableMethod(this, &SimpleDataSource::CancelTask)); 58} 59 60void SimpleDataSource::Initialize(const std::string& url, 61 media::FilterCallback* callback) { 62 AutoLock auto_lock(lock_); 63 DCHECK_EQ(state_, UNINITIALIZED); 64 DCHECK(callback); 65 state_ = INITIALIZING; 66 initialize_callback_.reset(callback); 67 68 // Validate the URL. 69 SetURL(GURL(url)); 70 if (!url_.is_valid() || !IsProtocolSupportedForMedia(url_)) { 71 host()->SetError(media::PIPELINE_ERROR_NETWORK); 72 initialize_callback_->Run(); 73 initialize_callback_.reset(); 74 return; 75 } 76 77 // Post a task to the render thread to start loading the resource. 78 render_loop_->PostTask(FROM_HERE, 79 NewRunnableMethod(this, &SimpleDataSource::StartTask)); 80} 81 82const media::MediaFormat& SimpleDataSource::media_format() { 83 return media_format_; 84} 85 86void SimpleDataSource::Read(int64 position, 87 size_t size, 88 uint8* data, 89 ReadCallback* read_callback) { 90 DCHECK_GE(size_, 0); 91 if (position >= size_) { 92 read_callback->RunWithParams(Tuple1<size_t>(0)); 93 delete read_callback; 94 } else { 95 size_t copied = std::min(size, static_cast<size_t>(size_ - position)); 96 memcpy(data, data_.c_str() + position, copied); 97 read_callback->RunWithParams(Tuple1<size_t>(copied)); 98 delete read_callback; 99 } 100} 101 102bool SimpleDataSource::GetSize(int64* size_out) { 103 *size_out = size_; 104 return true; 105} 106 107bool SimpleDataSource::IsStreaming() { 108 return false; 109} 110 111bool SimpleDataSource::OnReceivedRedirect( 112 const GURL& new_url, 113 const webkit_glue::ResourceResponseInfo& info, 114 bool* has_new_first_party_for_cookies, 115 GURL* new_first_party_for_cookies) { 116 DCHECK(MessageLoop::current() == render_loop_); 117 single_origin_ = url_.GetOrigin() == new_url.GetOrigin(); 118 119 // TODO(wtc): should we return a new first party for cookies URL? 120 *has_new_first_party_for_cookies = false; 121 return true; 122} 123 124void SimpleDataSource::OnReceivedResponse( 125 const webkit_glue::ResourceResponseInfo& info, 126 bool content_filtered) { 127 DCHECK(MessageLoop::current() == render_loop_); 128 size_ = info.content_length; 129} 130 131void SimpleDataSource::OnReceivedData(const char* data, int len) { 132 DCHECK(MessageLoop::current() == render_loop_); 133 data_.append(data, len); 134} 135 136void SimpleDataSource::OnCompletedRequest(const URLRequestStatus& status, 137 const std::string& security_info, 138 const base::Time& completion_time) { 139 DCHECK(MessageLoop::current() == render_loop_); 140 AutoLock auto_lock(lock_); 141 // It's possible this gets called after Stop(), in which case |host_| is no 142 // longer valid. 143 if (state_ == STOPPED) 144 return; 145 146 // Otherwise we should be initializing and have created a bridge. 147 DCHECK_EQ(state_, INITIALIZING); 148 DCHECK(bridge_.get()); 149 bridge_.reset(); 150 151 // If we don't get a content length or the request has failed, report it 152 // as a network error. 153 if (size_ == -1) 154 size_ = data_.length(); 155 DCHECK(static_cast<size_t>(size_) == data_.length()); 156 157 DoneInitialization_Locked(status.is_success()); 158} 159 160bool SimpleDataSource::HasSingleOrigin() { 161 DCHECK(MessageLoop::current() == render_loop_); 162 return single_origin_; 163} 164 165void SimpleDataSource::Abort() { 166 DCHECK(MessageLoop::current() == render_loop_); 167 NOTIMPLEMENTED(); 168} 169 170void SimpleDataSource::SetURL(const GURL& url) { 171 url_ = url; 172 media_format_.Clear(); 173 media_format_.SetAsString(media::MediaFormat::kMimeType, 174 media::mime_type::kApplicationOctetStream); 175 media_format_.SetAsString(media::MediaFormat::kURL, url.spec()); 176} 177 178void SimpleDataSource::StartTask() { 179 DCHECK(MessageLoop::current() == render_loop_); 180 AutoLock auto_lock(lock_); 181 182 // We may have stopped. 183 if (state_ == STOPPED) 184 return; 185 186 DCHECK_EQ(state_, INITIALIZING); 187 188 if (IsDataProtocol(url_)) { 189 // If this using data protocol, we just need to decode it. 190 std::string mime_type, charset; 191 bool success = net::DataURL::Parse(url_, &mime_type, &charset, &data_); 192 193 // Don't care about the mime-type just proceed if decoding was successful. 194 size_ = data_.length(); 195 DoneInitialization_Locked(success); 196 } else { 197 // Create our bridge and start loading the resource. 198 bridge_.reset(bridge_factory_->CreateBridge( 199 url_, net::LOAD_BYPASS_CACHE, -1, -1)); 200 bridge_->Start(this); 201 } 202} 203 204void SimpleDataSource::CancelTask() { 205 DCHECK(MessageLoop::current() == render_loop_); 206 AutoLock auto_lock(lock_); 207 DCHECK_EQ(state_, STOPPED); 208 209 // Cancel any pending requests. 210 if (bridge_.get()) { 211 bridge_->Cancel(); 212 bridge_.reset(); 213 } 214} 215 216void SimpleDataSource::DoneInitialization_Locked(bool success) { 217 lock_.AssertAcquired(); 218 if (success) { 219 state_ = INITIALIZED; 220 host()->SetTotalBytes(size_); 221 host()->SetBufferedBytes(size_); 222 // If scheme is file or data, say we are loaded. 223 host()->SetLoaded(url_.SchemeIsFile() || IsDataProtocol(url_)); 224 } else { 225 host()->SetError(media::PIPELINE_ERROR_NETWORK); 226 } 227 initialize_callback_->Run(); 228 initialize_callback_.reset(); 229} 230 231} // namespace webkit_glue 232