15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_vary_data.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/pickle.h" 107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_request_headers.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_request_info.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_response_headers.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_util.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpVaryData::HttpVaryData() : is_valid_(false) { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpVaryData::Init(const HttpRequestInfo& request_info, 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HttpResponseHeaders& response_headers) { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MD5Context ctx; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MD5Init(&ctx); 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_valid_ = false; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool processed_header = false; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Feed the MD5 context in the order of the Vary header enumeration. If the 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Vary header repeats a header name, then that's OK. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the Vary header contains '*' then we should not construct any vary data 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // since it is all usurped by a '*'. See section 13.6 of RFC 2616. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* iter = NULL; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string name = "vary", request_header; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (response_headers.EnumerateHeader(&iter, name, &request_header)) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (request_header == "*") 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddField(request_info, request_header, &ctx); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) processed_header = true; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add an implicit 'Vary: cookie' header to any redirect to avoid redirect 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // loops which may result from redirects that are incorrectly marked as 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cachable by the server. Unfortunately, other browsers do not cache 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // redirects that result from requests containing a cookie header. We are 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // treading on untested waters here, so we want to be extra careful to make 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sure we do not end up with a redirect loop served from cache. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is an explicit 'Vary: cookie' header, then we will just end up 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // digesting the cookie header twice. Not a problem. 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string location; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response_headers.IsRedirect(&location)) { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddField(request_info, "cookie", &ctx); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) processed_header = true; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!processed_header) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MD5Final(&request_digest_, &ctx); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return is_valid_ = true; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpVaryData::InitFromPickle(const Pickle& pickle, PickleIterator* iter) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_valid_ = false; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* data; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pickle.ReadBytes(iter, &data, sizeof(request_digest_))) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&request_digest_, data, sizeof(request_digest_)); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return is_valid_ = true; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpVaryData::Persist(Pickle* pickle) const { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(is_valid()); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pickle->WriteBytes(&request_digest_, sizeof(request_digest_)); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpVaryData::MatchesRequest( 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HttpRequestInfo& request_info, 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HttpResponseHeaders& cached_response_headers) const { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpVaryData new_vary_data; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!new_vary_data.Init(request_info, cached_response_headers)) { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This shouldn't happen provided the same response headers passed here 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // were also used when initializing |this|. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return memcmp(&new_vary_data.request_digest_, &request_digest_, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(request_digest_)) == 0; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpVaryData::GetRequestValue( 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HttpRequestInfo& request_info, 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& request_header) { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unfortunately, we do not have access to all of the request headers at this 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // point. Most notably, we do not have access to an Authorization header if 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // one will be added to the request. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string result; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (request_info.extra_headers.GetHeader(request_header, &result)) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpVaryData::AddField(const HttpRequestInfo& request_info, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& request_header, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MD5Context* ctx) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string request_value = GetRequestValue(request_info, request_header); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Append a character that cannot appear in the request header line so that we 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // protect against case where the concatenation of two request headers could 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // look the same for a variety of values for the individual request headers. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For example, "foo: 12\nbar: 3" looks like "foo: 1\nbar: 23" otherwise. 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_value.append(1, '\n'); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MD5Update(ctx, request_value); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 127