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