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

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

Issue 10387200: Suppress pause-and-buffer behavior when the HTTP response won't satisfy future requests via cache. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Alternative implementation requiring no further WebKit changes Created 8 years, 7 months 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
« no previous file with comments | « webkit/media/buffered_resource_loader.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "webkit/media/buffered_resource_loader.h" 5 #include "webkit/media/buffered_resource_loader.h"
6 6
7 #include <math.h>
8
7 #include "base/callback_helpers.h" 9 #include "base/callback_helpers.h"
8 #include "base/format_macros.h" 10 #include "base/format_macros.h"
11 #include "base/metrics/histogram.h"
9 #include "base/string_number_conversions.h" 12 #include "base/string_number_conversions.h"
10 #include "base/string_util.h" 13 #include "base/string_util.h"
11 #include "base/stringprintf.h" 14 #include "base/stringprintf.h"
12 #include "media/base/media_log.h" 15 #include "media/base/media_log.h"
13 #include "net/http/http_request_headers.h" 16 #include "net/http/http_request_headers.h"
17 #include "net/http/http_util.h"
18 #include "net/http/http_version.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderOptions.h " 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderOptions.h "
16 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebKitPlatfo rmSupport.h" 21 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebKitPlatfo rmSupport.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" 22 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLError. h" 23 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLError. h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRespon se.h" 24 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRespon se.h"
20 25
26 using base::Time;
27 using base::TimeDelta;
21 using WebKit::WebFrame; 28 using WebKit::WebFrame;
22 using WebKit::WebString; 29 using WebKit::WebString;
23 using WebKit::WebURLError; 30 using WebKit::WebURLError;
24 using WebKit::WebURLLoader; 31 using WebKit::WebURLLoader;
25 using WebKit::WebURLLoaderOptions; 32 using WebKit::WebURLLoaderOptions;
26 using WebKit::WebURLRequest; 33 using WebKit::WebURLRequest;
27 using WebKit::WebURLResponse; 34 using WebKit::WebURLResponse;
28 35
29 namespace webkit_media { 36 namespace webkit_media {
30 37
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 const GURL& url, 111 const GURL& url,
105 int64 first_byte_position, 112 int64 first_byte_position,
106 int64 last_byte_position, 113 int64 last_byte_position,
107 DeferStrategy strategy, 114 DeferStrategy strategy,
108 int bitrate, 115 int bitrate,
109 float playback_rate, 116 float playback_rate,
110 media::MediaLog* media_log) 117 media::MediaLog* media_log)
111 : buffer_(kMinBufferCapacity, kMinBufferCapacity), 118 : buffer_(kMinBufferCapacity, kMinBufferCapacity),
112 loader_failed_(false), 119 loader_failed_(false),
113 defer_strategy_(strategy), 120 defer_strategy_(strategy),
121 might_be_reused_from_cache_in_future_(true),
114 range_supported_(false), 122 range_supported_(false),
115 saved_forward_capacity_(0), 123 saved_forward_capacity_(0),
116 url_(url), 124 url_(url),
117 first_byte_position_(first_byte_position), 125 first_byte_position_(first_byte_position),
118 last_byte_position_(last_byte_position), 126 last_byte_position_(last_byte_position),
119 single_origin_(true), 127 single_origin_(true),
120 offset_(0), 128 offset_(0),
121 content_length_(kPositionNotSpecified), 129 content_length_(kPositionNotSpecified),
122 instance_size_(kPositionNotSpecified), 130 instance_size_(kPositionNotSpecified),
123 read_position_(0), 131 read_position_(0),
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 url_ = newRequest.url(); 353 url_ = newRequest.url();
346 } 354 }
347 355
348 void BufferedResourceLoader::didSendData( 356 void BufferedResourceLoader::didSendData(
349 WebURLLoader* loader, 357 WebURLLoader* loader,
350 unsigned long long bytes_sent, 358 unsigned long long bytes_sent,
351 unsigned long long total_bytes_to_be_sent) { 359 unsigned long long total_bytes_to_be_sent) {
352 NOTIMPLEMENTED(); 360 NOTIMPLEMENTED();
353 } 361 }
354 362
363 // Reasons that a cached WebURLResponse will *not* prevent a future request to
364 // the server.
365 enum UncacheableReason {
366 kNoData = 1, // Not 200 or 206.
367 kPre11PartialResponse = 2, // 206 but HTTP version < 1.1.
368 kNoStrongValidatorOnPartialResponse = 3, // 206, no strong validator.
369 kNoValidatorOnFullResponse = 4, // 200, no strong or weak validator.
370 kShortMaxAge = 5, // Max age less than 1h (arbitrary value).
371 kExpiresTooSoon = 6, // Expires in less than 1h (arbitrary value).
372 kHasMustRevalidate = 7, // Response asks for revalidation.
373 kNoCache = 8, // Response included a no-cache header.
374 kNoStore = 9, // Response included a no-store header.
375 kMaxReason // Needs to be one more than max legitimate reason.
376 };
377
378 // Return true if "response" might be used for a future request (using the disk
379 // cache). This is basically a laundry list of reasons we *know* the response
380 // won't be useful in the future.
381 static bool MightBeReusedFromCacheInFuture(const WebURLResponse& response) {
darin (slow to review) 2012/05/22 05:30:59 style nit: usually best not to interrupt the defin
382 std::vector<UncacheableReason> reasons;
darin (slow to review) 2012/05/22 05:30:59 what's the point of building up this vector? why
383 const int code = response.httpStatusCode();
384 const int version = response.httpVersion();
385 const net::HttpVersion http_version =
386 version == WebURLResponse::HTTP_1_1 ? net::HttpVersion(1, 1) :
387 version == WebURLResponse::HTTP_1_0 ? net::HttpVersion(1, 0) :
388 version == WebURLResponse::HTTP_0_9 ? net::HttpVersion(0, 9) :
389 net::HttpVersion();
390 if (code != kHttpOK && code != kHttpPartialContent)
391 reasons.push_back(kNoData);
392 if (http_version < net::HttpVersion(1, 1) && code == kHttpPartialContent)
393 reasons.push_back(kPre11PartialResponse);
394 if (!net::HttpUtil::HasStrongValidators(
395 http_version,
396 response.httpHeaderField("etag").utf8(),
397 response.httpHeaderField("Last-Modified").utf8(),
398 response.httpHeaderField("Date").utf8())) {
399 if (code == kHttpPartialContent)
400 reasons.push_back(kNoStrongValidatorOnPartialResponse);
401 else if (code == kHttpOK)
402 reasons.push_back(kNoValidatorOnFullResponse);
403 }
404
405 std::string cache_control_header =
406 response.httpHeaderField("cache-control").utf8();
407 StringToLowerASCII(&cache_control_header);
408 if (cache_control_header.find("no-cache") != std::string::npos)
409 reasons.push_back(kNoCache);
410 if (cache_control_header.find("no-store") != std::string::npos)
411 reasons.push_back(kNoStore);
412 if (cache_control_header.find("must-revalidate") != std::string::npos)
413 reasons.push_back(kHasMustRevalidate);
414
415 const TimeDelta kMinimumAgeForUsefulness =
416 TimeDelta::FromSeconds(3600); // Arbitrary value.
417
418 const char kMaxAgePrefix[] = "max-age=";
419 const size_t kMaxAgePrefixLen = arraysize(kMaxAgePrefix) - 1;
420 if (LowerCaseEqualsASCII(
421 cache_control_header.begin(),
422 cache_control_header.begin() + kMaxAgePrefixLen,
423 kMaxAgePrefix)) {
424 int64 max_age_seconds;
425 base::StringToInt64(
426 base::StringPiece(
427 cache_control_header.begin() + kMaxAgePrefixLen,
428 cache_control_header.end()),
429 &max_age_seconds);
430 if (TimeDelta::FromSeconds(max_age_seconds) < kMinimumAgeForUsefulness)
431 reasons.push_back(kShortMaxAge);
432 }
433
434 Time date;
435 Time expires;
436 if (Time::FromString(response.httpHeaderField("Date").utf8().data(), &date) &&
437 Time::FromString(
438 response.httpHeaderField("Expires").utf8().data(), &expires) &&
439 date > Time() && expires > Time() &&
440 (expires - date) < kMinimumAgeForUsefulness) {
441 reasons.push_back(kExpiresTooSoon);
442 }
443
444 UMA_HISTOGRAM_BOOLEAN("Media.CacheUseful", reasons.empty());
445 for (size_t i = 0; i < reasons.size(); ++i) {
446 UMA_HISTOGRAM_ENUMERATION(
447 "Media.UncacheableReason", reasons[i], kMaxReason);
448 }
449
450 return reasons.empty();
451 }
452
355 void BufferedResourceLoader::didReceiveResponse( 453 void BufferedResourceLoader::didReceiveResponse(
356 WebURLLoader* loader, 454 WebURLLoader* loader,
357 const WebURLResponse& response) { 455 const WebURLResponse& response) {
358 DVLOG(1) << "didReceiveResponse: HTTP/" 456 DVLOG(1) << "didReceiveResponse: HTTP/"
359 << (response.httpVersion() == WebURLResponse::HTTP_0_9 ? "0.9" : 457 << (response.httpVersion() == WebURLResponse::HTTP_0_9 ? "0.9" :
360 response.httpVersion() == WebURLResponse::HTTP_1_0 ? "1.0" : 458 response.httpVersion() == WebURLResponse::HTTP_1_0 ? "1.0" :
361 response.httpVersion() == WebURLResponse::HTTP_1_1 ? "1.1" : 459 response.httpVersion() == WebURLResponse::HTTP_1_1 ? "1.1" :
362 "Unknown") 460 "Unknown")
363 << " " << response.httpStatusCode(); 461 << " " << response.httpStatusCode();
364 DCHECK(active_loader_.get()); 462 DCHECK(active_loader_.get());
365 463
366 // The loader may have been stopped and |start_cb| is destroyed. 464 // The loader may have been stopped and |start_cb| is destroyed.
367 // In this case we shouldn't do anything. 465 // In this case we shouldn't do anything.
368 if (start_cb_.is_null()) 466 if (start_cb_.is_null())
369 return; 467 return;
370 468
469 might_be_reused_from_cache_in_future_ =
470 MightBeReusedFromCacheInFuture(response);
471
371 // Expected content length can be |kPositionNotSpecified|, in that case 472 // Expected content length can be |kPositionNotSpecified|, in that case
372 // |content_length_| is not specified and this is a streaming response. 473 // |content_length_| is not specified and this is a streaming response.
373 content_length_ = response.expectedContentLength(); 474 content_length_ = response.expectedContentLength();
374 475
375 // We make a strong assumption that when we reach here we have either 476 // We make a strong assumption that when we reach here we have either
376 // received a response from HTTP/HTTPS protocol or the request was 477 // received a response from HTTP/HTTPS protocol or the request was
377 // successful (in particular range request). So we only verify the partial 478 // successful (in particular range request). So we only verify the partial
378 // response for HTTP and HTTPS protocol. 479 // response for HTTP and HTTPS protocol.
379 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { 480 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) {
380 bool partial_response = (response.httpStatusCode() == kHttpPartialContent); 481 bool partial_response = (response.httpStatusCode() == kHttpPartialContent);
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 } 634 }
534 } 635 }
535 636
536 bool BufferedResourceLoader::HasSingleOrigin() const { 637 bool BufferedResourceLoader::HasSingleOrigin() const {
537 DCHECK(start_cb_.is_null()) 638 DCHECK(start_cb_.is_null())
538 << "Start() must complete before calling HasSingleOrigin()"; 639 << "Start() must complete before calling HasSingleOrigin()";
539 return single_origin_; 640 return single_origin_;
540 } 641 }
541 642
542 void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) { 643 void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) {
644 if (!might_be_reused_from_cache_in_future_ && strategy == kNeverDefer)
645 strategy = kThresholdDefer;
543 defer_strategy_ = strategy; 646 defer_strategy_ = strategy;
544 UpdateDeferBehavior(); 647 UpdateDeferBehavior();
545 } 648 }
546 649
547 void BufferedResourceLoader::SetPlaybackRate(float playback_rate) { 650 void BufferedResourceLoader::SetPlaybackRate(float playback_rate) {
548 playback_rate_ = playback_rate; 651 playback_rate_ = playback_rate;
549 652
550 // This is a pause so don't bother updating the buffer window as we'll likely 653 // This is a pause so don't bother updating the buffer window as we'll likely
551 // get unpaused in the future. 654 // get unpaused in the future.
552 if (playback_rate_ == 0.0) 655 if (playback_rate_ == 0.0)
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
813 916
814 void BufferedResourceLoader::Log() { 917 void BufferedResourceLoader::Log() {
815 media_log_->AddEvent( 918 media_log_->AddEvent(
816 media_log_->CreateBufferedExtentsChangedEvent( 919 media_log_->CreateBufferedExtentsChangedEvent(
817 offset_ - buffer_.backward_bytes(), 920 offset_ - buffer_.backward_bytes(),
818 offset_, 921 offset_,
819 offset_ + buffer_.forward_bytes())); 922 offset_ + buffer_.forward_bytes()));
820 } 923 }
821 924
822 } // namespace webkit_media 925 } // namespace webkit_media
OLDNEW
« no previous file with comments | « webkit/media/buffered_resource_loader.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698