Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(515)

Side by Side Diff: webkit/glue/media/buffered_resource_loader.cc

Issue 5756004: Separate BufferedDataSource and BufferedResourceLoader into two files. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: removing the constants and methods I added to http_util.h Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/buffered_resource_loader.h"
6
7 #include "base/format_macros.h"
8 #include "base/string_util.h"
9 #include "net/base/net_errors.h"
10 #include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
11 #include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h"
12 #include "third_party/WebKit/WebKit/chromium/public/WebString.h"
13 #include "third_party/WebKit/WebKit/chromium/public/WebURLError.h"
14 #include "webkit/glue/multipart_response_delegate.h"
15 #include "webkit/glue/webkit_glue.h"
16
17 using WebKit::WebFrame;
18 using WebKit::WebString;
19 using WebKit::WebURLError;
20 using WebKit::WebURLLoader;
21 using WebKit::WebURLRequest;
22 using WebKit::WebURLResponse;
23 using webkit_glue::MultipartResponseDelegate;
24
25 namespace {
26
27 const char kHttpScheme[] = "http";
28 const char kHttpsScheme[] = "https";
29 const char kDataScheme[] = "data";
30
31 const int64 kPositionNotSpecified = -1;
32 const int kHttpOK = 200;
33 const int kHttpPartialContent = 206;
34
35 // Define the number of bytes in a megabyte.
36 const size_t kMegabyte = 1024 * 1024;
37
38 // Backward capacity of the buffer, by default 2MB.
39 const size_t kBackwardCapcity = 2 * kMegabyte;
40
41 // Forward capacity of the buffer, by default 10MB.
42 const size_t kForwardCapacity = 10 * kMegabyte;
43
44 // The threshold of bytes that we should wait until the data arrives in the
45 // future instead of restarting a new connection. This number is defined in the
46 // number of bytes, we should determine this value from typical connection speed
47 // and amount of time for a suitable wait. Now I just make a guess for this
48 // number to be 2MB.
49 // TODO(hclam): determine a better value for this.
50 const int kForwardWaitThreshold = 2 * kMegabyte;
51
52 // Returns true if |url| operates on HTTP protocol.
53 static bool IsHttpProtocol(const GURL& url) {
54 return url.SchemeIs(kHttpScheme) || url.SchemeIs(kHttpsScheme);
55 }
56
57 } // namespace
58
59 namespace webkit_glue {
60
61 BufferedResourceLoader::BufferedResourceLoader(
62 const GURL& url,
63 int64 first_byte_position,
64 int64 last_byte_position)
65 : buffer_(new media::SeekableBuffer(kBackwardCapcity, kForwardCapacity)),
66 deferred_(false),
67 defer_allowed_(true),
68 completed_(false),
69 range_requested_(false),
70 partial_response_(false),
71 url_(url),
72 first_byte_position_(first_byte_position),
73 last_byte_position_(last_byte_position),
74 start_callback_(NULL),
75 offset_(0),
76 content_length_(kPositionNotSpecified),
77 instance_size_(kPositionNotSpecified),
78 read_callback_(NULL),
79 read_position_(0),
80 read_size_(0),
81 read_buffer_(NULL),
82 first_offset_(0),
83 last_offset_(0),
84 keep_test_loader_(false) {
85 }
86
87 BufferedResourceLoader::~BufferedResourceLoader() {
88 if (!completed_ && url_loader_.get())
89 url_loader_->cancel();
90 }
91
92 void BufferedResourceLoader::Start(net::CompletionCallback* start_callback,
93 NetworkEventCallback* event_callback,
94 WebFrame* frame) {
95 // Make sure we have not started.
96 DCHECK(!start_callback_.get());
97 DCHECK(!event_callback_.get());
98 DCHECK(start_callback);
99 DCHECK(event_callback);
100 CHECK(frame);
101
102 start_callback_.reset(start_callback);
103 event_callback_.reset(event_callback);
104
105 if (first_byte_position_ != kPositionNotSpecified) {
106 range_requested_ = true;
107 // TODO(hclam): server may not support range request so |offset_| may not
108 // equal to |first_byte_position_|.
109 offset_ = first_byte_position_;
110 }
111
112 // Increment the reference count right before we start the request. This
113 // reference will be release when this request has ended.
114 AddRef();
115
116 // Prepare the request.
117 WebURLRequest request(url_);
118 request.setHTTPHeaderField(WebString::fromUTF8("Range"),
119 WebString::fromUTF8(GenerateHeaders(
120 first_byte_position_,
121 last_byte_position_)));
122 frame->setReferrerForRequest(request, WebKit::WebURL());
123
124 // This flag is for unittests as we don't want to reset |url_loader|
125 if (!keep_test_loader_)
126 url_loader_.reset(frame->createAssociatedURLLoader());
127
128 // Start the resource loading.
129 url_loader_->loadAsynchronously(request, this);
130 }
131
132 void BufferedResourceLoader::Stop() {
133 // Reset callbacks.
134 start_callback_.reset();
135 event_callback_.reset();
136 read_callback_.reset();
137
138 // Use the internal buffer to signal that we have been stopped.
139 // TODO(hclam): Not so pretty to do this.
140 if (!buffer_.get())
141 return;
142
143 // Destroy internal buffer.
144 buffer_.reset();
145
146 if (url_loader_.get()) {
147 if (deferred_)
148 url_loader_->setDefersLoading(false);
149 deferred_ = false;
150
151 if (!completed_) {
152 url_loader_->cancel();
153 completed_ = true;
154 }
155 }
156 }
157
158 void BufferedResourceLoader::Read(int64 position,
159 int read_size,
160 uint8* buffer,
161 net::CompletionCallback* read_callback) {
162 DCHECK(!read_callback_.get());
163 DCHECK(buffer_.get());
164 DCHECK(read_callback);
165 DCHECK(buffer);
166
167 // Save the parameter of reading.
168 read_callback_.reset(read_callback);
169 read_position_ = position;
170 read_size_ = read_size;
171 read_buffer_ = buffer;
172
173 // If read position is beyond the instance size, we cannot read there.
174 if (instance_size_ != kPositionNotSpecified &&
175 instance_size_ <= read_position_) {
176 DoneRead(0);
177 return;
178 }
179
180 // Make sure |offset_| and |read_position_| does not differ by a large
181 // amount.
182 if (read_position_ > offset_ + kint32max ||
183 read_position_ < offset_ + kint32min) {
184 DoneRead(net::ERR_CACHE_MISS);
185 return;
186 }
187
188 // Prepare the parameters.
189 first_offset_ = static_cast<int>(read_position_ - offset_);
190 last_offset_ = first_offset_ + read_size_;
191
192 // If we can serve the request now, do the actual read.
193 if (CanFulfillRead()) {
194 ReadInternal();
195 DisableDeferIfNeeded();
196 return;
197 }
198
199 // If we expected the read request to be fulfilled later, returns
200 // immediately and let more data to flow in.
201 if (WillFulfillRead())
202 return;
203
204 // Make a callback to report failure.
205 DoneRead(net::ERR_CACHE_MISS);
206 }
207
208 int64 BufferedResourceLoader::GetBufferedFirstBytePosition() {
209 if (buffer_.get())
210 return offset_ - static_cast<int>(buffer_->backward_bytes());
211 return kPositionNotSpecified;
212 }
213
214 int64 BufferedResourceLoader::GetBufferedLastBytePosition() {
215 if (buffer_.get())
216 return offset_ + static_cast<int>(buffer_->forward_bytes()) - 1;
217 return kPositionNotSpecified;
218 }
219
220 void BufferedResourceLoader::SetAllowDefer(bool is_allowed) {
221 defer_allowed_ = is_allowed;
222 DisableDeferIfNeeded();
223 }
224
225 int64 BufferedResourceLoader::content_length() {
226 return content_length_;
227 }
228
229 int64 BufferedResourceLoader::instance_size() {
230 return instance_size_;
231 }
232
233 bool BufferedResourceLoader::partial_response() {
234 return partial_response_;
235 }
236
237 bool BufferedResourceLoader::network_activity() {
238 return !completed_ && !deferred_;
239 }
240
241 const GURL& BufferedResourceLoader::url() {
242 return url_;
243 }
244
245 void BufferedResourceLoader::SetURLLoaderForTest(WebURLLoader* mock_loader) {
246 url_loader_.reset(mock_loader);
247 keep_test_loader_ = true;
248 }
249
250 // WebKit::WebURLLoaderClient implementations.
251 void BufferedResourceLoader::willSendRequest(
252 WebURLLoader* loader,
253 WebURLRequest& newRequest,
254 const WebURLResponse& redirectResponse) {
255
256 // The load may have been stopped and |start_callback| is destroyed.
257 // In this case we shouldn't do anything.
258 if (!start_callback_.get()) {
259 // Set the url in the request to an invalid value (empty url).
260 newRequest.setURL(WebKit::WebURL());
261 return;
262 }
263
264 if (!IsProtocolSupportedForMedia(newRequest.url())) {
265 // Set the url in the request to an invalid value (empty url).
266 newRequest.setURL(WebKit::WebURL());
267 DoneStart(net::ERR_ADDRESS_INVALID);
268 Stop();
269 return;
270 }
271
272 url_ = newRequest.url();
273 }
274
275 void BufferedResourceLoader::didSendData(
276 WebURLLoader* loader,
277 unsigned long long bytes_sent,
278 unsigned long long total_bytes_to_be_sent) {
279 NOTIMPLEMENTED();
280 }
281
282 void BufferedResourceLoader::didReceiveResponse(
283 WebURLLoader* loader,
284 const WebURLResponse& response) {
285
286 // The loader may have been stopped and |start_callback| is destroyed.
287 // In this case we shouldn't do anything.
288 if (!start_callback_.get())
289 return;
290
291 // We make a strong assumption that when we reach here we have either
292 // received a response from HTTP/HTTPS protocol or the request was
293 // successful (in particular range request). So we only verify the partial
294 // response for HTTP and HTTPS protocol.
295 if (IsHttpProtocol(url_)) {
296 int error = net::OK;
297
298 if (response.httpStatusCode() == kHttpPartialContent)
299 partial_response_ = true;
300
301 if (range_requested_ && partial_response_) {
302 // If we have verified the partial response and it is correct, we will
303 // return net::OK.
304 if (!VerifyPartialResponse(response))
305 error = net::ERR_INVALID_RESPONSE;
306 } else if (response.httpStatusCode() != kHttpOK) {
307 // We didn't request a range but server didn't reply with "200 OK".
308 error = net::ERR_FAILED;
309 }
310
311 if (error != net::OK) {
312 DoneStart(error);
313 Stop();
314 return;
315 }
316 } else {
317 // For any protocol other than HTTP and HTTPS, assume range request is
318 // always fulfilled.
319 partial_response_ = range_requested_;
320 }
321
322 // Expected content length can be -1, in that case |content_length_| is
323 // not specified and this is a streaming response.
324 content_length_ = response.expectedContentLength();
325
326 // If we have not requested a range, then the size of the instance is equal
327 // to the content length.
328 if (!partial_response_)
329 instance_size_ = content_length_;
330
331 // Calls with a successful response.
332 DoneStart(net::OK);
333 }
334
335 void BufferedResourceLoader::didReceiveData(
336 WebURLLoader* loader,
337 const char* data,
338 int data_length) {
339 DCHECK(!completed_);
340 DCHECK_GT(data_length, 0);
341
342 // If this loader has been stopped, |buffer_| would be destroyed.
343 // In this case we shouldn't do anything.
344 if (!buffer_.get())
345 return;
346
347 // Writes more data to |buffer_|.
348 buffer_->Append(reinterpret_cast<const uint8*>(data), data_length);
349
350 // If there is an active read request, try to fulfill the request.
351 if (HasPendingRead() && CanFulfillRead()) {
352 ReadInternal();
353 } else if (!defer_allowed_) {
354 // If we're not allowed to defer, slide the buffer window forward instead
355 // of deferring.
356 if (buffer_->forward_bytes() > buffer_->forward_capacity()) {
357 size_t excess = buffer_->forward_bytes() - buffer_->forward_capacity();
358 bool success = buffer_->Seek(excess);
359 DCHECK(success);
360 offset_ += first_offset_ + excess;
361 }
362 }
363
364 // At last see if the buffer is full and we need to defer the downloading.
365 EnableDeferIfNeeded();
366
367 // Notify that we have received some data.
368 NotifyNetworkEvent();
369 }
370
371 void BufferedResourceLoader::didDownloadData(
372 WebKit::WebURLLoader* loader,
373 int dataLength) {
374 NOTIMPLEMENTED();
375 }
376
377 void BufferedResourceLoader::didReceiveCachedMetadata(
378 WebURLLoader* loader,
379 const char* data,
380 int data_length) {
381 NOTIMPLEMENTED();
382 }
383
384 void BufferedResourceLoader::didFinishLoading(
385 WebURLLoader* loader,
386 double finishTime) {
387 DCHECK(!completed_);
388 completed_ = true;
389
390 // If there is a start callback, calls it.
391 if (start_callback_.get()) {
392 DoneStart(net::OK);
393 }
394
395 // If there is a pending read but the request has ended, returns with what
396 // we have.
397 if (HasPendingRead()) {
398 // Make sure we have a valid buffer before we satisfy a read request.
399 DCHECK(buffer_.get());
400
401 // Try to fulfill with what is in the buffer.
402 if (CanFulfillRead())
403 ReadInternal();
404 else
405 DoneRead(net::ERR_CACHE_MISS);
406 }
407
408 // There must not be any outstanding read request.
409 DCHECK(!HasPendingRead());
410
411 // Notify that network response is completed.
412 NotifyNetworkEvent();
413
414 url_loader_.reset();
415 Release();
416 }
417
418 void BufferedResourceLoader::didFail(
419 WebURLLoader* loader,
420 const WebURLError& error) {
421 DCHECK(!completed_);
422 completed_ = true;
423
424 // If there is a start callback, calls it.
425 if (start_callback_.get()) {
426 DoneStart(error.reason);
427 }
428
429 // If there is a pending read but the request failed, return with the
430 // reason for the error.
431 if (HasPendingRead()) {
432 DoneRead(error.reason);
433 }
434
435 // Notify that network response is completed.
436 NotifyNetworkEvent();
437
438 url_loader_.reset();
439 Release();
440 }
441
442 void BufferedResourceLoader::EnableDeferIfNeeded() {
443 if (!defer_allowed_)
444 return;
445
446 if (!deferred_ &&
447 buffer_->forward_bytes() >= buffer_->forward_capacity()) {
448 deferred_ = true;
449
450 if (url_loader_.get())
451 url_loader_->setDefersLoading(true);
452
453 NotifyNetworkEvent();
454 }
455 }
456
457 void BufferedResourceLoader::DisableDeferIfNeeded() {
458 if (deferred_ &&
459 (!defer_allowed_ ||
460 buffer_->forward_bytes() < buffer_->forward_capacity() / 2)) {
461 deferred_ = false;
462
463 if (url_loader_.get())
464 url_loader_->setDefersLoading(false);
465
466 NotifyNetworkEvent();
467 }
468 }
469
470 bool BufferedResourceLoader::CanFulfillRead() {
471 // If we are reading too far in the backward direction.
472 if (first_offset_ < 0 &&
473 first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0)
474 return false;
475
476 // If the start offset is too far ahead.
477 if (first_offset_ >= static_cast<int>(buffer_->forward_bytes()))
478 return false;
479
480 // At the point, we verified that first byte requested is within the buffer.
481 // If the request has completed, then just returns with what we have now.
482 if (completed_)
483 return true;
484
485 // If the resource request is still active, make sure the whole requested
486 // range is covered.
487 if (last_offset_ > static_cast<int>(buffer_->forward_bytes()))
488 return false;
489
490 return true;
491 }
492
493 bool BufferedResourceLoader::WillFulfillRead() {
494 // Reading too far in the backward direction.
495 if (first_offset_ < 0 &&
496 first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0)
497 return false;
498
499 // Try to read too far ahead.
500 if (last_offset_ > kForwardWaitThreshold)
501 return false;
502
503 // The resource request has completed, there's no way we can fulfill the
504 // read request.
505 if (completed_)
506 return false;
507
508 return true;
509 }
510
511 void BufferedResourceLoader::ReadInternal() {
512 // Seek to the first byte requested.
513 bool ret = buffer_->Seek(first_offset_);
514 DCHECK(ret);
515
516 // Then do the read.
517 int read = static_cast<int>(buffer_->Read(read_buffer_, read_size_));
518 offset_ += first_offset_ + read;
519
520 // And report with what we have read.
521 DoneRead(read);
522 }
523
524 bool BufferedResourceLoader::VerifyPartialResponse(
525 const WebURLResponse& response) {
526 int first_byte_position, last_byte_position, instance_size;
527
528 if (!MultipartResponseDelegate::ReadContentRanges(response,
529 &first_byte_position,
530 &last_byte_position,
531 &instance_size)) {
532 return false;
533 }
534
535 if (instance_size != kPositionNotSpecified) {
536 instance_size_ = instance_size;
537 }
538
539 if (first_byte_position_ != kPositionNotSpecified &&
540 first_byte_position_ != first_byte_position) {
541 return false;
542 }
543
544 // TODO(hclam): I should also check |last_byte_position|, but since
545 // we will never make such a request that it is ok to leave it unimplemented.
546 return true;
547 }
548
549 std::string BufferedResourceLoader::GenerateHeaders(
550 int64 first_byte_position,
551 int64 last_byte_position) {
552 // Construct the value for the range header.
553 std::string header;
554 if (first_byte_position > kPositionNotSpecified &&
555 last_byte_position > kPositionNotSpecified) {
556 if (first_byte_position <= last_byte_position) {
557 header = base::StringPrintf("bytes=%" PRId64 "-%" PRId64,
558 first_byte_position,
559 last_byte_position);
560 }
561 } else if (first_byte_position > kPositionNotSpecified) {
562 header = base::StringPrintf("bytes=%" PRId64 "-",
563 first_byte_position);
564 } else if (last_byte_position > kPositionNotSpecified) {
565 NOTIMPLEMENTED() << "Suffix range not implemented";
566 }
567 return header;
568 }
569
570 void BufferedResourceLoader::DoneRead(int error) {
571 read_callback_->RunWithParams(Tuple1<int>(error));
572 read_callback_.reset();
573 read_position_ = 0;
574 read_size_ = 0;
575 read_buffer_ = NULL;
576 first_offset_ = 0;
577 last_offset_ = 0;
578 }
579
580 void BufferedResourceLoader::DoneStart(int error) {
581 start_callback_->RunWithParams(Tuple1<int>(error));
582 start_callback_.reset();
583 }
584
585 void BufferedResourceLoader::NotifyNetworkEvent() {
586 if (event_callback_.get())
587 event_callback_->Run();
588 }
589
590 } // namespace webkit_glue
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698