1 // Copyright 2013 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 "media/blink/buffered_resource_loader.h" 6 7 #include "base/bits.h" 8 #include "base/callback_helpers.h" 9 #include "base/metrics/histogram.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_util.h" 12 #include "media/base/media_log.h" 13 #include "media/blink/cache_util.h" 14 #include "net/http/http_byte_range.h" 15 #include "net/http/http_request_headers.h" 16 #include "third_party/WebKit/public/platform/WebString.h" 17 #include "third_party/WebKit/public/platform/WebURLError.h" 18 #include "third_party/WebKit/public/platform/WebURLResponse.h" 19 #include "third_party/WebKit/public/web/WebKit.h" 20 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h" 21 22 using blink::WebFrame; 23 using blink::WebString; 24 using blink::WebURLError; 25 using blink::WebURLLoader; 26 using blink::WebURLLoaderOptions; 27 using blink::WebURLRequest; 28 using blink::WebURLResponse; 29 30 namespace media { 31 32 static const int kHttpOK = 200; 33 static const int kHttpPartialContent = 206; 34 35 // Define the number of bytes in a megabyte. 36 static const int kMegabyte = 1024 * 1024; 37 38 // Minimum capacity of the buffer in forward or backward direction. 39 // 40 // 2MB is an arbitrary limit; it just seems to be "good enough" in practice. 41 static const int kMinBufferCapacity = 2 * kMegabyte; 42 43 // Maximum capacity of the buffer in forward or backward direction. This is 44 // effectively the largest single read the code path can handle. 45 // 20MB is an arbitrary limit; it just seems to be "good enough" in practice. 46 static const int kMaxBufferCapacity = 20 * kMegabyte; 47 48 // Maximum number of bytes outside the buffer we will wait for in order to 49 // fulfill a read. If a read starts more than 2MB away from the data we 50 // currently have in the buffer, we will not wait for buffer to reach the read's 51 // location and will instead reset the request. 52 static const int kForwardWaitThreshold = 2 * kMegabyte; 53 54 // Computes the suggested backward and forward capacity for the buffer 55 // if one wants to play at |playback_rate| * the natural playback speed. 56 // Use a value of 0 for |bitrate| if it is unknown. 57 static void ComputeTargetBufferWindow(float playback_rate, int bitrate, 58 int* out_backward_capacity, 59 int* out_forward_capacity) { 60 static const int kDefaultBitrate = 200 * 1024 * 8; // 200 Kbps. 61 static const int kMaxBitrate = 20 * kMegabyte * 8; // 20 Mbps. 62 static const float kMaxPlaybackRate = 25.0; 63 static const int kTargetSecondsBufferedAhead = 10; 64 static const int kTargetSecondsBufferedBehind = 2; 65 66 // Use a default bit rate if unknown and clamp to prevent overflow. 67 if (bitrate <= 0) 68 bitrate = kDefaultBitrate; 69 bitrate = std::min(bitrate, kMaxBitrate); 70 71 // Only scale the buffer window for playback rates greater than 1.0 in 72 // magnitude and clamp to prevent overflow. 73 bool backward_playback = false; 74 if (playback_rate < 0.0f) { 75 backward_playback = true; 76 playback_rate *= -1.0f; 77 } 78 79 playback_rate = std::max(playback_rate, 1.0f); 80 playback_rate = std::min(playback_rate, kMaxPlaybackRate); 81 82 int bytes_per_second = (bitrate / 8.0) * playback_rate; 83 84 // Clamp between kMinBufferCapacity and kMaxBufferCapacity. 85 *out_forward_capacity = std::max( 86 kTargetSecondsBufferedAhead * bytes_per_second, kMinBufferCapacity); 87 *out_backward_capacity = std::max( 88 kTargetSecondsBufferedBehind * bytes_per_second, kMinBufferCapacity); 89 90 *out_forward_capacity = std::min(*out_forward_capacity, kMaxBufferCapacity); 91 *out_backward_capacity = std::min(*out_backward_capacity, kMaxBufferCapacity); 92 93 if (backward_playback) 94 std::swap(*out_forward_capacity, *out_backward_capacity); 95 } 96 97 BufferedResourceLoader::BufferedResourceLoader( 98 const GURL& url, 99 CORSMode cors_mode, 100 int64 first_byte_position, 101 int64 last_byte_position, 102 DeferStrategy strategy, 103 int bitrate, 104 float playback_rate, 105 MediaLog* media_log) 106 : buffer_(kMinBufferCapacity, kMinBufferCapacity), 107 loader_failed_(false), 108 defer_strategy_(strategy), 109 might_be_reused_from_cache_in_future_(true), 110 range_supported_(false), 111 saved_forward_capacity_(0), 112 url_(url), 113 cors_mode_(cors_mode), 114 first_byte_position_(first_byte_position), 115 last_byte_position_(last_byte_position), 116 single_origin_(true), 117 offset_(0), 118 content_length_(kPositionNotSpecified), 119 instance_size_(kPositionNotSpecified), 120 read_position_(0), 121 read_size_(0), 122 read_buffer_(NULL), 123 first_offset_(0), 124 last_offset_(0), 125 bitrate_(bitrate), 126 playback_rate_(playback_rate), 127 media_log_(media_log) { 128 129 // Set the initial capacity of |buffer_| based on |bitrate_| and 130 // |playback_rate_|. 131 UpdateBufferWindow(); 132 } 133 134 BufferedResourceLoader::~BufferedResourceLoader() {} 135 136 void BufferedResourceLoader::Start( 137 const StartCB& start_cb, 138 const LoadingStateChangedCB& loading_cb, 139 const ProgressCB& progress_cb, 140 WebFrame* frame) { 141 // Make sure we have not started. 142 DCHECK(start_cb_.is_null()); 143 DCHECK(loading_cb_.is_null()); 144 DCHECK(progress_cb_.is_null()); 145 DCHECK(!start_cb.is_null()); 146 DCHECK(!loading_cb.is_null()); 147 DCHECK(!progress_cb.is_null()); 148 CHECK(frame); 149 150 start_cb_ = start_cb; 151 loading_cb_ = loading_cb; 152 progress_cb_ = progress_cb; 153 154 if (first_byte_position_ != kPositionNotSpecified) { 155 // TODO(hclam): server may not support range request so |offset_| may not 156 // equal to |first_byte_position_|. 157 offset_ = first_byte_position_; 158 } 159 160 // Prepare the request. 161 WebURLRequest request(url_); 162 // TODO(mkwst): Split this into video/audio. 163 request.setRequestContext(WebURLRequest::RequestContextVideo); 164 165 if (IsRangeRequest()) { 166 request.setHTTPHeaderField( 167 WebString::fromUTF8(net::HttpRequestHeaders::kRange), 168 WebString::fromUTF8(net::HttpByteRange::Bounded( 169 first_byte_position_, last_byte_position_).GetHeaderValue())); 170 } 171 172 frame->setReferrerForRequest(request, blink::WebURL()); 173 174 // Disable compression, compression for audio/video doesn't make sense... 175 request.setHTTPHeaderField( 176 WebString::fromUTF8(net::HttpRequestHeaders::kAcceptEncoding), 177 WebString::fromUTF8("identity;q=1, *;q=0")); 178 179 // Check for our test WebURLLoader. 180 scoped_ptr<WebURLLoader> loader; 181 if (test_loader_) { 182 loader = test_loader_.Pass(); 183 } else { 184 WebURLLoaderOptions options; 185 if (cors_mode_ == kUnspecified) { 186 options.allowCredentials = true; 187 options.crossOriginRequestPolicy = 188 WebURLLoaderOptions::CrossOriginRequestPolicyAllow; 189 } else { 190 options.exposeAllResponseHeaders = true; 191 // The author header set is empty, no preflight should go ahead. 192 options.preflightPolicy = WebURLLoaderOptions::PreventPreflight; 193 options.crossOriginRequestPolicy = 194 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; 195 if (cors_mode_ == kUseCredentials) 196 options.allowCredentials = true; 197 } 198 loader.reset(frame->createAssociatedURLLoader(options)); 199 } 200 201 // Start the resource loading. 202 loader->loadAsynchronously(request, this); 203 active_loader_.reset(new ActiveLoader(loader.Pass())); 204 loading_cb_.Run(kLoading); 205 } 206 207 void BufferedResourceLoader::Stop() { 208 // Reset callbacks. 209 start_cb_.Reset(); 210 loading_cb_.Reset(); 211 progress_cb_.Reset(); 212 read_cb_.Reset(); 213 214 // Cancel and reset any active loaders. 215 active_loader_.reset(); 216 } 217 218 void BufferedResourceLoader::Read( 219 int64 position, 220 int read_size, 221 uint8* buffer, 222 const ReadCB& read_cb) { 223 DCHECK(start_cb_.is_null()); 224 DCHECK(read_cb_.is_null()); 225 DCHECK(!read_cb.is_null()); 226 DCHECK(buffer); 227 DCHECK_GT(read_size, 0); 228 229 // Save the parameter of reading. 230 read_cb_ = read_cb; 231 read_position_ = position; 232 read_size_ = read_size; 233 read_buffer_ = buffer; 234 235 // Reads should immediately fail if the loader also failed. 236 if (loader_failed_) { 237 DoneRead(kFailed, 0); 238 return; 239 } 240 241 // If we're attempting to read past the end of the file, return a zero 242 // indicating EOF. 243 // 244 // This can happen with callees that read in fixed-sized amounts for parsing 245 // or at the end of chunked 200 responses when we discover the actual length 246 // of the file. 247 if (instance_size_ != kPositionNotSpecified && 248 instance_size_ <= read_position_) { 249 DVLOG(1) << "Appear to have seeked beyond EOS; returning 0."; 250 DoneRead(kOk, 0); 251 return; 252 } 253 254 // Make sure |offset_| and |read_position_| does not differ by a large 255 // amount. 256 if (read_position_ > offset_ + kint32max || 257 read_position_ < offset_ + kint32min) { 258 DoneRead(kCacheMiss, 0); 259 return; 260 } 261 262 // Make sure |read_size_| is not too large for the buffer to ever be able to 263 // fulfill the read request. 264 if (read_size_ > kMaxBufferCapacity) { 265 DoneRead(kFailed, 0); 266 return; 267 } 268 269 // Prepare the parameters. 270 first_offset_ = read_position_ - offset_; 271 last_offset_ = first_offset_ + read_size_; 272 273 // If we can serve the request now, do the actual read. 274 if (CanFulfillRead()) { 275 ReadInternal(); 276 UpdateDeferBehavior(); 277 return; 278 } 279 280 // If we expect the read request to be fulfilled later, expand capacity as 281 // necessary and disable deferring. 282 if (WillFulfillRead()) { 283 // Advance offset as much as possible to create additional capacity. 284 int advance = std::min(first_offset_, buffer_.forward_bytes()); 285 bool ret = buffer_.Seek(advance); 286 DCHECK(ret); 287 288 offset_ += advance; 289 first_offset_ -= advance; 290 last_offset_ -= advance; 291 292 // Expand capacity to accomodate a read that extends past the normal 293 // capacity. 294 // 295 // This can happen when reading in a large seek index or when the 296 // first byte of a read request falls within kForwardWaitThreshold. 297 if (last_offset_ > buffer_.forward_capacity()) { 298 saved_forward_capacity_ = buffer_.forward_capacity(); 299 buffer_.set_forward_capacity(last_offset_); 300 } 301 302 // Make sure we stop deferring now that there's additional capacity. 303 DCHECK(!ShouldDefer()) 304 << "Capacity was not adjusted properly to prevent deferring."; 305 UpdateDeferBehavior(); 306 307 return; 308 } 309 310 // Make a callback to report failure. 311 DoneRead(kCacheMiss, 0); 312 } 313 314 int64 BufferedResourceLoader::content_length() { 315 return content_length_; 316 } 317 318 int64 BufferedResourceLoader::instance_size() { 319 return instance_size_; 320 } 321 322 bool BufferedResourceLoader::range_supported() { 323 return range_supported_; 324 } 325 326 ///////////////////////////////////////////////////////////////////////////// 327 // blink::WebURLLoaderClient implementation. 328 void BufferedResourceLoader::willSendRequest( 329 WebURLLoader* loader, 330 WebURLRequest& newRequest, 331 const WebURLResponse& redirectResponse) { 332 333 // The load may have been stopped and |start_cb| is destroyed. 334 // In this case we shouldn't do anything. 335 if (start_cb_.is_null()) { 336 // Set the url in the request to an invalid value (empty url). 337 newRequest.setURL(blink::WebURL()); 338 return; 339 } 340 341 // Only allow |single_origin_| if we haven't seen a different origin yet. 342 if (single_origin_) 343 single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin(); 344 345 url_ = newRequest.url(); 346 } 347 348 void BufferedResourceLoader::didSendData( 349 WebURLLoader* loader, 350 unsigned long long bytes_sent, 351 unsigned long long total_bytes_to_be_sent) { 352 NOTIMPLEMENTED(); 353 } 354 355 void BufferedResourceLoader::didReceiveResponse( 356 WebURLLoader* loader, 357 const WebURLResponse& response) { 358 DVLOG(1) << "didReceiveResponse: HTTP/" 359 << (response.httpVersion() == WebURLResponse::HTTP_0_9 ? "0.9" : 360 response.httpVersion() == WebURLResponse::HTTP_1_0 ? "1.0" : 361 response.httpVersion() == WebURLResponse::HTTP_1_1 ? "1.1" : 362 "Unknown") 363 << " " << response.httpStatusCode(); 364 DCHECK(active_loader_.get()); 365 366 // The loader may have been stopped and |start_cb| is destroyed. 367 // In this case we shouldn't do anything. 368 if (start_cb_.is_null()) 369 return; 370 371 uint32 reasons = GetReasonsForUncacheability(response); 372 might_be_reused_from_cache_in_future_ = reasons == 0; 373 UMA_HISTOGRAM_BOOLEAN("Media.CacheUseful", reasons == 0); 374 int shift = 0; 375 int max_enum = base::bits::Log2Ceiling(kMaxReason); 376 while (reasons) { 377 DCHECK_LT(shift, max_enum); // Sanity check. 378 if (reasons & 0x1) { 379 UMA_HISTOGRAM_ENUMERATION("Media.UncacheableReason", 380 shift, 381 max_enum); // PRESUBMIT_IGNORE_UMA_MAX 382 } 383 384 reasons >>= 1; 385 ++shift; 386 } 387 388 // Expected content length can be |kPositionNotSpecified|, in that case 389 // |content_length_| is not specified and this is a streaming response. 390 content_length_ = response.expectedContentLength(); 391 392 // We make a strong assumption that when we reach here we have either 393 // received a response from HTTP/HTTPS protocol or the request was 394 // successful (in particular range request). So we only verify the partial 395 // response for HTTP and HTTPS protocol. 396 if (url_.SchemeIsHTTPOrHTTPS()) { 397 bool partial_response = (response.httpStatusCode() == kHttpPartialContent); 398 bool ok_response = (response.httpStatusCode() == kHttpOK); 399 400 if (IsRangeRequest()) { 401 // Check to see whether the server supports byte ranges. 402 std::string accept_ranges = 403 response.httpHeaderField("Accept-Ranges").utf8(); 404 range_supported_ = (accept_ranges.find("bytes") != std::string::npos); 405 406 // If we have verified the partial response and it is correct, we will 407 // return kOk. It's also possible for a server to support range requests 408 // without advertising "Accept-Ranges: bytes". 409 if (partial_response && VerifyPartialResponse(response)) { 410 range_supported_ = true; 411 } else if (ok_response && first_byte_position_ == 0 && 412 last_byte_position_ == kPositionNotSpecified) { 413 // We accept a 200 response for a Range:0- request, trusting the 414 // Accept-Ranges header, because Apache thinks that's a reasonable thing 415 // to return. 416 instance_size_ = content_length_; 417 } else { 418 DoneStart(kFailed); 419 return; 420 } 421 } else { 422 instance_size_ = content_length_; 423 if (response.httpStatusCode() != kHttpOK) { 424 // We didn't request a range but server didn't reply with "200 OK". 425 DoneStart(kFailed); 426 return; 427 } 428 } 429 430 } else { 431 CHECK_EQ(instance_size_, kPositionNotSpecified); 432 if (content_length_ != kPositionNotSpecified) { 433 if (first_byte_position_ == kPositionNotSpecified) 434 instance_size_ = content_length_; 435 else if (last_byte_position_ == kPositionNotSpecified) 436 instance_size_ = content_length_ + first_byte_position_; 437 } 438 } 439 440 // Calls with a successful response. 441 DoneStart(kOk); 442 } 443 444 void BufferedResourceLoader::didReceiveData( 445 WebURLLoader* loader, 446 const char* data, 447 int data_length, 448 int encoded_data_length) { 449 DVLOG(1) << "didReceiveData: " << data_length << " bytes"; 450 DCHECK(active_loader_.get()); 451 DCHECK_GT(data_length, 0); 452 453 buffer_.Append(reinterpret_cast<const uint8*>(data), data_length); 454 455 // If there is an active read request, try to fulfill the request. 456 if (HasPendingRead() && CanFulfillRead()) 457 ReadInternal(); 458 459 // At last see if the buffer is full and we need to defer the downloading. 460 UpdateDeferBehavior(); 461 462 // Consume excess bytes from our in-memory buffer if necessary. 463 if (buffer_.forward_bytes() > buffer_.forward_capacity()) { 464 int excess = buffer_.forward_bytes() - buffer_.forward_capacity(); 465 bool success = buffer_.Seek(excess); 466 DCHECK(success); 467 offset_ += first_offset_ + excess; 468 } 469 470 // Notify latest progress and buffered offset. 471 progress_cb_.Run(offset_ + buffer_.forward_bytes() - 1); 472 Log(); 473 } 474 475 void BufferedResourceLoader::didDownloadData( 476 blink::WebURLLoader* loader, 477 int dataLength, 478 int encoded_data_length) { 479 NOTIMPLEMENTED(); 480 } 481 482 void BufferedResourceLoader::didReceiveCachedMetadata( 483 WebURLLoader* loader, 484 const char* data, 485 int data_length) { 486 NOTIMPLEMENTED(); 487 } 488 489 void BufferedResourceLoader::didFinishLoading( 490 WebURLLoader* loader, 491 double finishTime, 492 int64_t total_encoded_data_length) { 493 DVLOG(1) << "didFinishLoading"; 494 DCHECK(active_loader_.get()); 495 496 // We're done with the loader. 497 active_loader_.reset(); 498 loading_cb_.Run(kLoadingFinished); 499 500 // If we didn't know the |instance_size_| we do now. 501 if (instance_size_ == kPositionNotSpecified) { 502 instance_size_ = offset_ + buffer_.forward_bytes(); 503 } 504 505 // If there is a start callback, run it. 506 if (!start_cb_.is_null()) { 507 DCHECK(read_cb_.is_null()) 508 << "Shouldn't have a read callback during start"; 509 DoneStart(kOk); 510 return; 511 } 512 513 // Don't leave read callbacks hanging around. 514 if (HasPendingRead()) { 515 // Try to fulfill with what is in the buffer. 516 if (CanFulfillRead()) 517 ReadInternal(); 518 else 519 DoneRead(kCacheMiss, 0); 520 } 521 } 522 523 void BufferedResourceLoader::didFail( 524 WebURLLoader* loader, 525 const WebURLError& error) { 526 DVLOG(1) << "didFail: reason=" << error.reason 527 << ", isCancellation=" << error.isCancellation 528 << ", domain=" << error.domain.utf8().data() 529 << ", localizedDescription=" 530 << error.localizedDescription.utf8().data(); 531 DCHECK(active_loader_.get()); 532 533 // We don't need to continue loading after failure. 534 // 535 // Keep it alive until we exit this method so that |error| remains valid. 536 scoped_ptr<ActiveLoader> active_loader = active_loader_.Pass(); 537 loader_failed_ = true; 538 loading_cb_.Run(kLoadingFailed); 539 540 // Don't leave start callbacks hanging around. 541 if (!start_cb_.is_null()) { 542 DCHECK(read_cb_.is_null()) 543 << "Shouldn't have a read callback during start"; 544 DoneStart(kFailed); 545 return; 546 } 547 548 // Don't leave read callbacks hanging around. 549 if (HasPendingRead()) { 550 DoneRead(kFailed, 0); 551 } 552 } 553 554 bool BufferedResourceLoader::HasSingleOrigin() const { 555 DCHECK(start_cb_.is_null()) 556 << "Start() must complete before calling HasSingleOrigin()"; 557 return single_origin_; 558 } 559 560 bool BufferedResourceLoader::DidPassCORSAccessCheck() const { 561 DCHECK(start_cb_.is_null()) 562 << "Start() must complete before calling DidPassCORSAccessCheck()"; 563 return !loader_failed_ && cors_mode_ != kUnspecified; 564 } 565 566 void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) { 567 if (!might_be_reused_from_cache_in_future_ && strategy == kNeverDefer) 568 strategy = kCapacityDefer; 569 defer_strategy_ = strategy; 570 UpdateDeferBehavior(); 571 } 572 573 void BufferedResourceLoader::SetPlaybackRate(float playback_rate) { 574 playback_rate_ = playback_rate; 575 576 // This is a pause so don't bother updating the buffer window as we'll likely 577 // get unpaused in the future. 578 if (playback_rate_ == 0.0) 579 return; 580 581 UpdateBufferWindow(); 582 } 583 584 void BufferedResourceLoader::SetBitrate(int bitrate) { 585 DCHECK(bitrate >= 0); 586 bitrate_ = bitrate; 587 UpdateBufferWindow(); 588 } 589 590 ///////////////////////////////////////////////////////////////////////////// 591 // Helper methods. 592 593 void BufferedResourceLoader::UpdateBufferWindow() { 594 int backward_capacity; 595 int forward_capacity; 596 ComputeTargetBufferWindow( 597 playback_rate_, bitrate_, &backward_capacity, &forward_capacity); 598 599 // This does not evict data from the buffer if the new capacities are less 600 // than the current capacities; the new limits will be enforced after the 601 // existing excess buffered data is consumed. 602 buffer_.set_backward_capacity(backward_capacity); 603 buffer_.set_forward_capacity(forward_capacity); 604 } 605 606 void BufferedResourceLoader::UpdateDeferBehavior() { 607 if (!active_loader_) 608 return; 609 610 SetDeferred(ShouldDefer()); 611 } 612 613 void BufferedResourceLoader::SetDeferred(bool deferred) { 614 if (active_loader_->deferred() == deferred) 615 return; 616 617 active_loader_->SetDeferred(deferred); 618 loading_cb_.Run(deferred ? kLoadingDeferred : kLoading); 619 } 620 621 bool BufferedResourceLoader::ShouldDefer() const { 622 switch(defer_strategy_) { 623 case kNeverDefer: 624 return false; 625 626 case kReadThenDefer: 627 DCHECK(read_cb_.is_null() || last_offset_ > buffer_.forward_bytes()) 628 << "We shouldn't stop deferring if we can fulfill the read"; 629 return read_cb_.is_null(); 630 631 case kCapacityDefer: 632 return buffer_.forward_bytes() >= buffer_.forward_capacity(); 633 } 634 NOTREACHED(); 635 return false; 636 } 637 638 bool BufferedResourceLoader::CanFulfillRead() const { 639 // If we are reading too far in the backward direction. 640 if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0) 641 return false; 642 643 // If the start offset is too far ahead. 644 if (first_offset_ >= buffer_.forward_bytes()) 645 return false; 646 647 // At the point, we verified that first byte requested is within the buffer. 648 // If the request has completed, then just returns with what we have now. 649 if (!active_loader_) 650 return true; 651 652 // If the resource request is still active, make sure the whole requested 653 // range is covered. 654 if (last_offset_ > buffer_.forward_bytes()) 655 return false; 656 657 return true; 658 } 659 660 bool BufferedResourceLoader::WillFulfillRead() const { 661 // Trying to read too far behind. 662 if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0) 663 return false; 664 665 // Trying to read too far ahead. 666 if ((first_offset_ - buffer_.forward_bytes()) >= kForwardWaitThreshold) 667 return false; 668 669 // The resource request has completed, there's no way we can fulfill the 670 // read request. 671 if (!active_loader_) 672 return false; 673 674 return true; 675 } 676 677 void BufferedResourceLoader::ReadInternal() { 678 // Seek to the first byte requested. 679 bool ret = buffer_.Seek(first_offset_); 680 DCHECK(ret); 681 682 // Then do the read. 683 int read = buffer_.Read(read_buffer_, read_size_); 684 offset_ += first_offset_ + read; 685 686 // And report with what we have read. 687 DoneRead(kOk, read); 688 } 689 690 int64 BufferedResourceLoader::first_byte_position() const { 691 return first_byte_position_; 692 } 693 694 // static 695 bool BufferedResourceLoader::ParseContentRange( 696 const std::string& content_range_str, int64* first_byte_position, 697 int64* last_byte_position, int64* instance_size) { 698 const std::string kUpThroughBytesUnit = "bytes "; 699 if (content_range_str.find(kUpThroughBytesUnit) != 0) 700 return false; 701 std::string range_spec = 702 content_range_str.substr(kUpThroughBytesUnit.length()); 703 size_t dash_offset = range_spec.find("-"); 704 size_t slash_offset = range_spec.find("/"); 705 706 if (dash_offset == std::string::npos || slash_offset == std::string::npos || 707 slash_offset < dash_offset || slash_offset + 1 == range_spec.length()) { 708 return false; 709 } 710 if (!base::StringToInt64(range_spec.substr(0, dash_offset), 711 first_byte_position) || 712 !base::StringToInt64(range_spec.substr(dash_offset + 1, 713 slash_offset - dash_offset - 1), 714 last_byte_position)) { 715 return false; 716 } 717 if (slash_offset == range_spec.length() - 2 && 718 range_spec[slash_offset + 1] == '*') { 719 *instance_size = kPositionNotSpecified; 720 } else { 721 if (!base::StringToInt64(range_spec.substr(slash_offset + 1), 722 instance_size)) { 723 return false; 724 } 725 } 726 if (*last_byte_position < *first_byte_position || 727 (*instance_size != kPositionNotSpecified && 728 *last_byte_position >= *instance_size)) { 729 return false; 730 } 731 732 return true; 733 } 734 735 bool BufferedResourceLoader::VerifyPartialResponse( 736 const WebURLResponse& response) { 737 int64 first_byte_position, last_byte_position, instance_size; 738 if (!ParseContentRange(response.httpHeaderField("Content-Range").utf8(), 739 &first_byte_position, &last_byte_position, 740 &instance_size)) { 741 return false; 742 } 743 744 if (instance_size != kPositionNotSpecified) { 745 instance_size_ = instance_size; 746 } 747 748 if (first_byte_position_ != kPositionNotSpecified && 749 first_byte_position_ != first_byte_position) { 750 return false; 751 } 752 753 // TODO(hclam): I should also check |last_byte_position|, but since 754 // we will never make such a request that it is ok to leave it unimplemented. 755 return true; 756 } 757 758 void BufferedResourceLoader::DoneRead(Status status, int bytes_read) { 759 if (saved_forward_capacity_) { 760 buffer_.set_forward_capacity(saved_forward_capacity_); 761 saved_forward_capacity_ = 0; 762 } 763 read_position_ = 0; 764 read_size_ = 0; 765 read_buffer_ = NULL; 766 first_offset_ = 0; 767 last_offset_ = 0; 768 Log(); 769 770 base::ResetAndReturn(&read_cb_).Run(status, bytes_read); 771 } 772 773 774 void BufferedResourceLoader::DoneStart(Status status) { 775 base::ResetAndReturn(&start_cb_).Run(status); 776 } 777 778 bool BufferedResourceLoader::IsRangeRequest() const { 779 return first_byte_position_ != kPositionNotSpecified; 780 } 781 782 void BufferedResourceLoader::Log() { 783 media_log_->AddEvent( 784 media_log_->CreateBufferedExtentsChangedEvent( 785 offset_ - buffer_.backward_bytes(), 786 offset_, 787 offset_ + buffer_.forward_bytes())); 788 } 789 790 } // namespace media 791