Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / http / http_vary_data.cc
blob9938d290a31ce4808fe8e1036618ce99bd6b7343
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
3 // found in the LICENSE file.
5 #include "net/http/http_vary_data.h"
7 #include <stdlib.h>
9 #include "base/pickle.h"
10 #include "base/strings/string_util.h"
11 #include "net/http/http_request_headers.h"
12 #include "net/http/http_request_info.h"
13 #include "net/http/http_response_headers.h"
14 #include "net/http/http_util.h"
16 namespace net {
18 HttpVaryData::HttpVaryData() : is_valid_(false) {
21 bool HttpVaryData::Init(const HttpRequestInfo& request_info,
22 const HttpResponseHeaders& response_headers) {
23 base::MD5Context ctx;
24 base::MD5Init(&ctx);
26 is_valid_ = false;
27 bool processed_header = false;
29 // Feed the MD5 context in the order of the Vary header enumeration. If the
30 // Vary header repeats a header name, then that's OK.
32 // If the Vary header contains '*' then we should not construct any vary data
33 // since it is all usurped by a '*'. See section 13.6 of RFC 2616.
35 void* iter = NULL;
36 std::string name = "vary", request_header;
37 while (response_headers.EnumerateHeader(&iter, name, &request_header)) {
38 if (request_header == "*")
39 return false;
40 AddField(request_info, request_header, &ctx);
41 processed_header = true;
44 // Add an implicit 'Vary: cookie' header to any redirect to avoid redirect
45 // loops which may result from redirects that are incorrectly marked as
46 // cachable by the server. Unfortunately, other browsers do not cache
47 // redirects that result from requests containing a cookie header. We are
48 // treading on untested waters here, so we want to be extra careful to make
49 // sure we do not end up with a redirect loop served from cache.
51 // If there is an explicit 'Vary: cookie' header, then we will just end up
52 // digesting the cookie header twice. Not a problem.
54 std::string location;
55 if (response_headers.IsRedirect(&location)) {
56 AddField(request_info, "cookie", &ctx);
57 processed_header = true;
60 if (!processed_header)
61 return false;
63 base::MD5Final(&request_digest_, &ctx);
64 return is_valid_ = true;
67 bool HttpVaryData::InitFromPickle(base::PickleIterator* iter) {
68 is_valid_ = false;
69 const char* data;
70 if (iter->ReadBytes(&data, sizeof(request_digest_))) {
71 memcpy(&request_digest_, data, sizeof(request_digest_));
72 return is_valid_ = true;
74 return false;
77 void HttpVaryData::Persist(base::Pickle* pickle) const {
78 DCHECK(is_valid());
79 pickle->WriteBytes(&request_digest_, sizeof(request_digest_));
82 bool HttpVaryData::MatchesRequest(
83 const HttpRequestInfo& request_info,
84 const HttpResponseHeaders& cached_response_headers) const {
85 HttpVaryData new_vary_data;
86 if (!new_vary_data.Init(request_info, cached_response_headers)) {
87 // This shouldn't happen provided the same response headers passed here
88 // were also used when initializing |this|.
89 NOTREACHED();
90 return false;
92 return memcmp(&new_vary_data.request_digest_, &request_digest_,
93 sizeof(request_digest_)) == 0;
96 // static
97 std::string HttpVaryData::GetRequestValue(
98 const HttpRequestInfo& request_info,
99 const std::string& request_header) {
100 // Unfortunately, we do not have access to all of the request headers at this
101 // point. Most notably, we do not have access to an Authorization header if
102 // one will be added to the request.
104 std::string result;
105 if (request_info.extra_headers.GetHeader(request_header, &result))
106 return result;
108 return std::string();
111 // static
112 void HttpVaryData::AddField(const HttpRequestInfo& request_info,
113 const std::string& request_header,
114 base::MD5Context* ctx) {
115 std::string request_value = GetRequestValue(request_info, request_header);
117 // Append a character that cannot appear in the request header line so that we
118 // protect against case where the concatenation of two request headers could
119 // look the same for a variety of values for the individual request headers.
120 // For example, "foo: 12\nbar: 3" looks like "foo: 1\nbar: 23" otherwise.
121 request_value.append(1, '\n');
123 base::MD5Update(ctx, request_value);
126 } // namespace net