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