| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/blink/resource_multibuffer_data_provider.h" | 5 #include "media/blink/resource_multibuffer_data_provider.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bits.h" | 8 #include "base/bits.h" |
| 9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 using blink::WebURLLoader; | 25 using blink::WebURLLoader; |
| 26 using blink::WebURLLoaderOptions; | 26 using blink::WebURLLoaderOptions; |
| 27 using blink::WebURLRequest; | 27 using blink::WebURLRequest; |
| 28 using blink::WebURLResponse; | 28 using blink::WebURLResponse; |
| 29 | 29 |
| 30 namespace media { | 30 namespace media { |
| 31 | 31 |
| 32 // The number of milliseconds to wait before retrying a failed load. | 32 // The number of milliseconds to wait before retrying a failed load. |
| 33 const int kLoaderFailedRetryDelayMs = 250; | 33 const int kLoaderFailedRetryDelayMs = 250; |
| 34 | 34 |
| 35 // The number of milliseconds to wait before retrying when the server |
| 36 // decides to not give us all the data at once. |
| 37 const int kLoaderPartialRetryDelayMs = 25; |
| 38 |
| 35 const int kHttpOK = 200; | 39 const int kHttpOK = 200; |
| 36 const int kHttpPartialContent = 206; | 40 const int kHttpPartialContent = 206; |
| 37 const int kHttpRangeNotSatisfiable = 416; | 41 const int kHttpRangeNotSatisfiable = 416; |
| 38 const int kMaxRetries = 3; | 42 const int kMaxRetries = 3; |
| 39 | 43 |
| 40 ResourceMultiBufferDataProvider::ResourceMultiBufferDataProvider( | 44 ResourceMultiBufferDataProvider::ResourceMultiBufferDataProvider( |
| 41 UrlData* url_data, | 45 UrlData* url_data, |
| 42 MultiBufferBlockId pos) | 46 MultiBufferBlockId pos) |
| 43 : pos_(pos), | 47 : pos_(pos), |
| 44 url_data_(url_data), | 48 url_data_(url_data), |
| 45 retries_(0), | 49 retries_(0), |
| 46 cors_mode_(url_data->cors_mode()), | 50 cors_mode_(url_data->cors_mode()), |
| 47 origin_(url_data->url().GetOrigin()), | 51 origin_(url_data->url().GetOrigin()), |
| 48 weak_factory_(this) { | 52 weak_factory_(this) { |
| 49 DCHECK(url_data_) << " pos = " << pos; | 53 DCHECK(url_data_) << " pos = " << pos; |
| 50 DCHECK_GE(pos, 0); | 54 DCHECK_GE(pos, 0); |
| 51 } | 55 } |
| 52 | 56 |
| 53 void ResourceMultiBufferDataProvider::Start() { | 57 void ResourceMultiBufferDataProvider::Start() { |
| 54 // In the case of a re-start, throw away any half-finished blocks. | |
| 55 fifo_.clear(); | |
| 56 // Prepare the request. | 58 // Prepare the request. |
| 57 WebURLRequest request(url_data_->url()); | 59 WebURLRequest request(url_data_->url()); |
| 58 // TODO(mkwst): Split this into video/audio. | 60 // TODO(mkwst): Split this into video/audio. |
| 59 request.setRequestContext(WebURLRequest::RequestContextVideo); | 61 request.setRequestContext(WebURLRequest::RequestContextVideo); |
| 60 | 62 |
| 63 DVLOG(1) << __FUNCTION__ << " @ " << byte_pos(); |
| 64 if (url_data_->length() > 0) { |
| 65 DCHECK_LT(byte_pos(), url_data_->length()) << " " << url_data_->url(); |
| 66 } |
| 67 |
| 61 request.setHTTPHeaderField( | 68 request.setHTTPHeaderField( |
| 62 WebString::fromUTF8(net::HttpRequestHeaders::kRange), | 69 WebString::fromUTF8(net::HttpRequestHeaders::kRange), |
| 63 WebString::fromUTF8( | 70 WebString::fromUTF8( |
| 64 net::HttpByteRange::RightUnbounded(byte_pos()).GetHeaderValue())); | 71 net::HttpByteRange::RightUnbounded(byte_pos()).GetHeaderValue())); |
| 65 | 72 |
| 66 url_data_->frame()->setReferrerForRequest(request, blink::WebURL()); | 73 url_data_->frame()->setReferrerForRequest(request, blink::WebURL()); |
| 67 | 74 |
| 68 // Disable compression, compression for audio/video doesn't make sense... | 75 // Disable compression, compression for audio/video doesn't make sense... |
| 69 request.setHTTPHeaderField( | 76 request.setHTTPHeaderField( |
| 70 WebString::fromUTF8(net::HttpRequestHeaders::kAcceptEncoding), | 77 WebString::fromUTF8(net::HttpRequestHeaders::kAcceptEncoding), |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 void ResourceMultiBufferDataProvider::willFollowRedirect( | 142 void ResourceMultiBufferDataProvider::willFollowRedirect( |
| 136 WebURLLoader* loader, | 143 WebURLLoader* loader, |
| 137 WebURLRequest& newRequest, | 144 WebURLRequest& newRequest, |
| 138 const WebURLResponse& redirectResponse) { | 145 const WebURLResponse& redirectResponse) { |
| 139 redirects_to_ = newRequest.url(); | 146 redirects_to_ = newRequest.url(); |
| 140 url_data_->set_valid_until(base::Time::Now() + | 147 url_data_->set_valid_until(base::Time::Now() + |
| 141 GetCacheValidUntil(redirectResponse)); | 148 GetCacheValidUntil(redirectResponse)); |
| 142 | 149 |
| 143 // This test is vital for security! | 150 // This test is vital for security! |
| 144 if (cors_mode_ == UrlData::CORS_UNSPECIFIED) { | 151 if (cors_mode_ == UrlData::CORS_UNSPECIFIED) { |
| 152 // We allow the redirect if the origin is the same. |
| 145 if (origin_ != redirects_to_.GetOrigin()) { | 153 if (origin_ != redirects_to_.GetOrigin()) { |
| 154 // We also allow the redirect if we don't have any data in the |
| 155 // cache, as that means that no dangerous data mixing can occur. |
| 156 if (url_data_->multibuffer()->map().empty() && fifo_.empty()) |
| 157 return; |
| 158 |
| 146 url_data_->Fail(); | 159 url_data_->Fail(); |
| 147 } | 160 } |
| 148 } | 161 } |
| 149 } | 162 } |
| 150 | 163 |
| 151 void ResourceMultiBufferDataProvider::didSendData( | 164 void ResourceMultiBufferDataProvider::didSendData( |
| 152 WebURLLoader* loader, | 165 WebURLLoader* loader, |
| 153 unsigned long long bytes_sent, | 166 unsigned long long bytes_sent, |
| 154 unsigned long long total_bytes_to_be_sent) { | 167 unsigned long long total_bytes_to_be_sent) { |
| 155 NOTIMPLEMENTED(); | 168 NOTIMPLEMENTED(); |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 // If we didn't know the |instance_size_| we do now. | 364 // If we didn't know the |instance_size_| we do now. |
| 352 int64_t size = byte_pos(); | 365 int64_t size = byte_pos(); |
| 353 if (!fifo_.empty()) | 366 if (!fifo_.empty()) |
| 354 size += fifo_.back()->data_size(); | 367 size += fifo_.back()->data_size(); |
| 355 | 368 |
| 356 // This request reports something smaller than what we've seen in the past, | 369 // This request reports something smaller than what we've seen in the past, |
| 357 // Maybe it's transient error? | 370 // Maybe it's transient error? |
| 358 if (url_data_->length() != kPositionNotSpecified && | 371 if (url_data_->length() != kPositionNotSpecified && |
| 359 size < url_data_->length()) { | 372 size < url_data_->length()) { |
| 360 if (retries_ < kMaxRetries) { | 373 if (retries_ < kMaxRetries) { |
| 361 fifo_.clear(); | 374 DVLOG(1) << " Partial data received.... @ pos = " << size; |
| 362 retries_++; | 375 retries_++; |
| 363 base::MessageLoop::current()->PostDelayedTask( | 376 base::MessageLoop::current()->PostDelayedTask( |
| 364 FROM_HERE, base::Bind(&ResourceMultiBufferDataProvider::Start, | 377 FROM_HERE, base::Bind(&ResourceMultiBufferDataProvider::Start, |
| 365 weak_factory_.GetWeakPtr()), | 378 weak_factory_.GetWeakPtr()), |
| 366 base::TimeDelta::FromMilliseconds(kLoaderFailedRetryDelayMs)); | 379 base::TimeDelta::FromMilliseconds(kLoaderPartialRetryDelayMs)); |
| 367 return; | 380 return; |
| 368 } else { | 381 } else { |
| 369 scoped_ptr<ActiveLoader> active_loader = active_loader_.Pass(); | 382 scoped_ptr<ActiveLoader> active_loader = active_loader_.Pass(); |
| 370 url_data_->Fail(); | 383 url_data_->Fail(); |
| 371 return; | 384 return; |
| 372 } | 385 } |
| 373 } | 386 } |
| 374 | 387 |
| 375 url_data_->set_length(size); | 388 url_data_->set_length(size); |
| 376 fifo_.push_back(DataBuffer::CreateEOSBuffer()); | 389 fifo_.push_back(DataBuffer::CreateEOSBuffer()); |
| 377 | 390 |
| 378 DCHECK(Available()); | 391 DCHECK(Available()); |
| 379 url_data_->multibuffer()->OnDataProviderEvent(this); | 392 url_data_->multibuffer()->OnDataProviderEvent(this); |
| 380 | 393 |
| 381 // Beware, this object might be deleted here. | 394 // Beware, this object might be deleted here. |
| 382 } | 395 } |
| 383 | 396 |
| 384 void ResourceMultiBufferDataProvider::didFail(WebURLLoader* loader, | 397 void ResourceMultiBufferDataProvider::didFail(WebURLLoader* loader, |
| 385 const WebURLError& error) { | 398 const WebURLError& error) { |
| 386 DVLOG(1) << "didFail: reason=" << error.reason | 399 DVLOG(1) << "didFail: reason=" << error.reason |
| 387 << ", isCancellation=" << error.isCancellation | 400 << ", isCancellation=" << error.isCancellation |
| 388 << ", domain=" << error.domain.utf8().data() | 401 << ", domain=" << error.domain.utf8().data() |
| 389 << ", localizedDescription=" | 402 << ", localizedDescription=" |
| 390 << error.localizedDescription.utf8().data(); | 403 << error.localizedDescription.utf8().data(); |
| 391 DCHECK(active_loader_.get()); | 404 DCHECK(active_loader_.get()); |
| 392 | 405 |
| 393 if (retries_ < kMaxRetries) { | 406 if (retries_ < kMaxRetries && pos_ != 0) { |
| 394 retries_++; | 407 retries_++; |
| 395 base::MessageLoop::current()->PostDelayedTask( | 408 base::MessageLoop::current()->PostDelayedTask( |
| 396 FROM_HERE, base::Bind(&ResourceMultiBufferDataProvider::Start, | 409 FROM_HERE, base::Bind(&ResourceMultiBufferDataProvider::Start, |
| 397 weak_factory_.GetWeakPtr()), | 410 weak_factory_.GetWeakPtr()), |
| 398 base::TimeDelta::FromMilliseconds(kLoaderFailedRetryDelayMs)); | 411 base::TimeDelta::FromMilliseconds(kLoaderFailedRetryDelayMs)); |
| 399 } else { | 412 } else { |
| 400 // We don't need to continue loading after failure. | 413 // We don't need to continue loading after failure. |
| 401 // | 414 // |
| 402 // Keep it alive until we exit this method so that |error| remains valid. | 415 // Keep it alive until we exit this method so that |error| remains valid. |
| 403 scoped_ptr<ActiveLoader> active_loader = active_loader_.Pass(); | 416 scoped_ptr<ActiveLoader> active_loader = active_loader_.Pass(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 (*instance_size != kPositionNotSpecified && | 455 (*instance_size != kPositionNotSpecified && |
| 443 *last_byte_position >= *instance_size)) { | 456 *last_byte_position >= *instance_size)) { |
| 444 return false; | 457 return false; |
| 445 } | 458 } |
| 446 | 459 |
| 447 return true; | 460 return true; |
| 448 } | 461 } |
| 449 | 462 |
| 450 int64_t ResourceMultiBufferDataProvider::byte_pos() const { | 463 int64_t ResourceMultiBufferDataProvider::byte_pos() const { |
| 451 int64_t ret = pos_; | 464 int64_t ret = pos_; |
| 452 return ret << url_data_->multibuffer()->block_size_shift(); | 465 ret += fifo_.size(); |
| 466 ret = ret << url_data_->multibuffer()->block_size_shift(); |
| 467 if (!fifo_.empty()) { |
| 468 ret += fifo_.back()->data_size() - block_size(); |
| 469 } |
| 470 return ret; |
| 453 } | 471 } |
| 454 | 472 |
| 455 int64_t ResourceMultiBufferDataProvider::block_size() const { | 473 int64_t ResourceMultiBufferDataProvider::block_size() const { |
| 456 int64_t ret = 1; | 474 int64_t ret = 1; |
| 457 return ret << url_data_->multibuffer()->block_size_shift(); | 475 return ret << url_data_->multibuffer()->block_size_shift(); |
| 458 } | 476 } |
| 459 | 477 |
| 460 bool ResourceMultiBufferDataProvider::VerifyPartialResponse( | 478 bool ResourceMultiBufferDataProvider::VerifyPartialResponse( |
| 461 const WebURLResponse& response) { | 479 const WebURLResponse& response) { |
| 462 int64 first_byte_position, last_byte_position, instance_size; | 480 int64 first_byte_position, last_byte_position, instance_size; |
| 463 if (!ParseContentRange(response.httpHeaderField("Content-Range").utf8(), | 481 if (!ParseContentRange(response.httpHeaderField("Content-Range").utf8(), |
| 464 &first_byte_position, &last_byte_position, | 482 &first_byte_position, &last_byte_position, |
| 465 &instance_size)) { | 483 &instance_size)) { |
| 466 return false; | 484 return false; |
| 467 } | 485 } |
| 468 | 486 |
| 469 if (url_data_->length() == kPositionNotSpecified) { | 487 if (url_data_->length() == kPositionNotSpecified) { |
| 470 url_data_->set_length(instance_size); | 488 url_data_->set_length(instance_size); |
| 471 } | 489 } |
| 472 | 490 |
| 473 if (byte_pos() != first_byte_position) { | 491 if (byte_pos() != first_byte_position) { |
| 474 return false; | 492 return false; |
| 475 } | 493 } |
| 476 | 494 |
| 477 return true; | 495 return true; |
| 478 } | 496 } |
| 479 | 497 |
| 480 } // namespace media | 498 } // namespace media |
| OLD | NEW |