1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_vary_data.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <stdlib.h>
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/pickle.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_request_headers.h"
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_request_info.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_response_headers.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_util.h"
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHttpVaryData::HttpVaryData() : is_valid_(false) {
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpVaryData::Init(const HttpRequestInfo& request_info,
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                        const HttpResponseHeaders& response_headers) {
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MD5Context ctx;
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MD5Init(&ctx);
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  is_valid_ = false;
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool processed_header = false;
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Feed the MD5 context in the order of the Vary header enumeration.  If the
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Vary header repeats a header name, then that's OK.
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  //
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If the Vary header contains '*' then we should not construct any vary data
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // since it is all usurped by a '*'.  See section 13.6 of RFC 2616.
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  //
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void* iter = NULL;
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string name = "vary", request_header;
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (response_headers.EnumerateHeader(&iter, name, &request_header)) {
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (request_header == "*")
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return false;
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    AddField(request_info, request_header, &ctx);
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    processed_header = true;
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Add an implicit 'Vary: cookie' header to any redirect to avoid redirect
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // loops which may result from redirects that are incorrectly marked as
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // cachable by the server.  Unfortunately, other browsers do not cache
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // redirects that result from requests containing a cookie header.  We are
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // treading on untested waters here, so we want to be extra careful to make
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // sure we do not end up with a redirect loop served from cache.
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  //
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If there is an explicit 'Vary: cookie' header, then we will just end up
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // digesting the cookie header twice.  Not a problem.
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  //
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string location;
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (response_headers.IsRedirect(&location)) {
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    AddField(request_info, "cookie", &ctx);
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    processed_header = true;
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!processed_header)
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MD5Final(&request_digest_, &ctx);
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return is_valid_ = true;
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpVaryData::InitFromPickle(const Pickle& pickle, void** iter) {
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  is_valid_ = false;
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const char* data;
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (pickle.ReadBytes(iter, &data, sizeof(request_digest_))) {
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memcpy(&request_digest_, data, sizeof(request_digest_));
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return is_valid_ = true;
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return false;
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpVaryData::Persist(Pickle* pickle) const {
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(is_valid());
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pickle->WriteBytes(&request_digest_, sizeof(request_digest_));
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpVaryData::MatchesRequest(
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const HttpRequestInfo& request_info,
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const HttpResponseHeaders& cached_response_headers) const {
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HttpVaryData new_vary_data;
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!new_vary_data.Init(request_info, cached_response_headers)) {
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // This shouldn't happen provided the same response headers passed here
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // were also used when initializing |this|.
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED();
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return memcmp(&new_vary_data.request_digest_, &request_digest_,
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                sizeof(request_digest_)) == 0;
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpVaryData::GetRequestValue(
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const HttpRequestInfo& request_info,
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const std::string& request_header) {
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Some special cases:
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!base::strcasecmp(request_header.c_str(), HttpRequestHeaders::kReferer))
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return request_info.referrer.spec();
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Unfortunately, we do not have access to all of the request headers at this
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // point.  Most notably, we do not have access to an Authorization header if
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // one will be added to the request.
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string result;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (request_info.extra_headers.GetHeader(request_header, &result))
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return "";
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpVaryData::AddField(const HttpRequestInfo& request_info,
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            const std::string& request_header,
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            MD5Context* ctx) {
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string request_value = GetRequestValue(request_info, request_header);
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Append a character that cannot appear in the request header line so that we
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // protect against case where the concatenation of two request headers could
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // look the same for a variety of values for the individual request headers.
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // For example, "foo: 12\nbar: 3" looks like "foo: 1\nbar: 23" otherwise.
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  request_value.append(1, '\n');
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MD5Update(ctx, request_value.data(), request_value.size());
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
131