1// Copyright 2014 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.
4
5#include "net/http/http_log_util.h"
6
7#include "base/strings/string_util.h"
8#include "base/strings/stringprintf.h"
9#include "net/http/http_auth_challenge_tokenizer.h"
10#include "net/http/http_util.h"
11
12namespace net {
13
14namespace {
15
16bool ShouldRedactChallenge(HttpAuthChallengeTokenizer* challenge) {
17  // Ignore lines with commas, as they may contain lists of schemes, and
18  // the information we want to hide is Base64 encoded, so has no commas.
19  if (challenge->challenge_text().find(',') != std::string::npos)
20    return false;
21
22  std::string scheme = base::StringToLowerASCII(challenge->scheme());
23  // Invalid input.
24  if (scheme.empty())
25    return false;
26
27  // Ignore Basic and Digest authentication challenges, as they contain
28  // public information.
29  if (scheme == "basic" || scheme == "digest")
30    return false;
31
32  return true;
33}
34
35}  // namespace
36
37std::string ElideHeaderValueForNetLog(NetLog::LogLevel log_level,
38                                      const std::string& header,
39                                      const std::string& value) {
40  std::string::const_iterator redact_begin = value.begin();
41  std::string::const_iterator redact_end = value.begin();
42
43  if (redact_begin == redact_end &&
44      log_level >= NetLog::LOG_STRIP_PRIVATE_DATA) {
45
46    // Note: this logic should be kept in sync with stripCookiesAndLoginInfo in
47    // chrome/browser/resources/net_internals/log_view_painter.js.
48
49    if (!base::strcasecmp(header.c_str(), "set-cookie") ||
50        !base::strcasecmp(header.c_str(), "set-cookie2") ||
51        !base::strcasecmp(header.c_str(), "cookie") ||
52        !base::strcasecmp(header.c_str(), "authorization") ||
53        !base::strcasecmp(header.c_str(), "proxy-authorization")) {
54      redact_begin = value.begin();
55      redact_end = value.end();
56    } else if (!base::strcasecmp(header.c_str(), "www-authenticate") ||
57               !base::strcasecmp(header.c_str(), "proxy-authenticate")) {
58      // Look for authentication information from data received from the server
59      // in multi-round Negotiate authentication.
60      HttpAuthChallengeTokenizer challenge(value.begin(), value.end());
61      if (ShouldRedactChallenge(&challenge)) {
62        redact_begin = challenge.params_begin();
63        redact_end = challenge.params_end();
64      }
65    }
66  }
67
68  if (redact_begin == redact_end)
69    return value;
70
71  return std::string(value.begin(), redact_begin) +
72      base::StringPrintf("[%ld bytes were stripped]",
73                         static_cast<long>(redact_end - redact_begin)) +
74      std::string(redact_end, value.end());
75}
76
77}  // namespace net
78