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