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