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/cache_util.h"
6
7#include <string>
8
9#include "base/strings/string_number_conversions.h"
10#include "base/strings/string_util.h"
11#include "base/time/time.h"
12#include "net/http/http_util.h"
13#include "net/http/http_version.h"
14#include "third_party/WebKit/public/platform/WebCString.h"
15#include "third_party/WebKit/public/platform/WebString.h"
16#include "third_party/WebKit/public/platform/WebURLResponse.h"
17
18using base::Time;
19using base::TimeDelta;
20using net::HttpVersion;
21using blink::WebURLResponse;
22
23namespace media {
24
25enum { kHttpOK = 200, kHttpPartialContent = 206 };
26
27uint32 GetReasonsForUncacheability(const WebURLResponse& response) {
28  uint32 reasons = 0;
29  const int code = response.httpStatusCode();
30  const int version = response.httpVersion();
31  const HttpVersion http_version =
32      version == WebURLResponse::HTTP_1_1 ? HttpVersion(1, 1) :
33      version == WebURLResponse::HTTP_1_0 ? HttpVersion(1, 0) :
34      version == WebURLResponse::HTTP_0_9 ? HttpVersion(0, 9) :
35      HttpVersion();
36  if (code != kHttpOK && code != kHttpPartialContent)
37    reasons |= kNoData;
38  if (http_version < HttpVersion(1, 1) && code == kHttpPartialContent)
39    reasons |= kPre11PartialResponse;
40  if (code == kHttpPartialContent &&
41      !net::HttpUtil::HasStrongValidators(
42          http_version,
43          response.httpHeaderField("etag").utf8(),
44          response.httpHeaderField("Last-Modified").utf8(),
45          response.httpHeaderField("Date").utf8())) {
46    reasons |= kNoStrongValidatorOnPartialResponse;
47  }
48
49  std::string cache_control_header =
50      response.httpHeaderField("cache-control").utf8();
51  base::StringToLowerASCII(&cache_control_header);
52  if (cache_control_header.find("no-cache") != std::string::npos)
53    reasons |= kNoCache;
54  if (cache_control_header.find("no-store") != std::string::npos)
55    reasons |= kNoStore;
56  if (cache_control_header.find("must-revalidate") != std::string::npos)
57    reasons |= kHasMustRevalidate;
58
59  const TimeDelta kMinimumAgeForUsefulness =
60      TimeDelta::FromSeconds(3600);  // Arbitrary value.
61
62  const char kMaxAgePrefix[] = "max-age=";
63  const size_t kMaxAgePrefixLen = arraysize(kMaxAgePrefix) - 1;
64  if (cache_control_header.substr(0, kMaxAgePrefixLen) == kMaxAgePrefix) {
65    int64 max_age_seconds;
66    base::StringToInt64(
67        base::StringPiece(cache_control_header.begin() + kMaxAgePrefixLen,
68                          cache_control_header.end()),
69        &max_age_seconds);
70    if (TimeDelta::FromSeconds(max_age_seconds) < kMinimumAgeForUsefulness)
71      reasons |= kShortMaxAge;
72  }
73
74  Time date;
75  Time expires;
76  if (Time::FromString(response.httpHeaderField("Date").utf8().data(), &date) &&
77      Time::FromString(response.httpHeaderField("Expires").utf8().data(),
78                       &expires) &&
79      date > Time() && expires > Time() &&
80      (expires - date) < kMinimumAgeForUsefulness) {
81    reasons |= kExpiresTooSoon;
82  }
83
84  return reasons;
85}
86
87}  // namespace media
88