http_vary_data.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
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