16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
26e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
36e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// found in the LICENSE file.
46e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/data_reduction_proxy/browser/data_reduction_proxy_tamper_detection.h"
66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include <algorithm>
86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include <cstring>
96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/base64.h"
116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/md5.h"
126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/metrics/histogram.h"
136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/metrics/sparse_histogram.h"
146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/strings/string_util.h"
166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "net/http/http_response_headers.h"
186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "net/http/http_util.h"
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#if defined(OS_ANDROID)
216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "net/android/network_library.h"
226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#endif
236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Macro for UMA reporting. HTTP response first reports to histogram events
256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// |http_histogram| by |carrier_id|; then reports the total counts to
266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// |http_histogram|_Total. HTTPS response reports to histograms
276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// |https_histogram| and |https_histogram|_Total similarly.
286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#define REPORT_TAMPER_DETECTION_UMA( \
296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    scheme_is_https, https_histogram, http_histogram, carrier_id) \
306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  do { \
316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (scheme_is_https) { \
326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      UMA_HISTOGRAM_SPARSE_SLOWLY(https_histogram, carrier_id); \
336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      UMA_HISTOGRAM_COUNTS(https_histogram "_Total", 1); \
346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    } else { \
356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      UMA_HISTOGRAM_SPARSE_SLOWLY(http_histogram, carrier_id); \
366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      UMA_HISTOGRAM_COUNTS(http_histogram "_Total", 1); \
376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }\
386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } while (0)
396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace data_reduction_proxy {
416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// static
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool DataReductionProxyTamperDetection::DetectAndReport(
446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const net::HttpResponseHeaders* headers,
456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const bool scheme_is_https) {
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK(headers);
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Abort tamper detection, if the fingerprint of the Chrome-Proxy header is
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // absent.
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string chrome_proxy_fingerprint;
506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!GetDataReductionProxyActionFingerprintChromeProxy(
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      headers, &chrome_proxy_fingerprint)) {
526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return false;
536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Get carrier ID.
566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  unsigned carrier_id = 0;
576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#if defined(OS_ANDROID)
586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  base::StringToUint(net::android::GetTelephonyNetworkOperator(), &carrier_id);
596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#endif
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DataReductionProxyTamperDetection tamper_detection(
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      headers, scheme_is_https, carrier_id);
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Checks if the Chrome-Proxy header has been tampered with.
656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (tamper_detection.ValidateChromeProxyHeader(chrome_proxy_fingerprint)) {
666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    tamper_detection.ReportUMAforChromeProxyHeaderValidation();
676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return true;
686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Chrome-Proxy header has not been tampered with, and thus other
716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // fingerprints are valid. Reports the number of responses that other
726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // fingerprints will be checked.
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  REPORT_TAMPER_DETECTION_UMA(
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      scheme_is_https,
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      "DataReductionProxy.HeaderTamperDetectionHTTPS",
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      "DataReductionProxy.HeaderTamperDetectionHTTP",
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      carrier_id);
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  bool tampered = false;
806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string fingerprint;
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (GetDataReductionProxyActionFingerprintVia(headers, &fingerprint)) {
836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    bool has_chrome_proxy_via_header;
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (tamper_detection.ValidateViaHeader(
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        fingerprint, &has_chrome_proxy_via_header)) {
866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      tamper_detection.ReportUMAforViaHeaderValidation(
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          has_chrome_proxy_via_header);
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      tampered = true;
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (GetDataReductionProxyActionFingerprintOtherHeaders(
936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      headers, &fingerprint)) {
946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (tamper_detection.ValidateOtherHeaders(fingerprint)) {
956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      tamper_detection.ReportUMAforOtherHeadersValidation();
966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      tampered = true;
976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (GetDataReductionProxyActionFingerprintContentLength(
1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      headers, &fingerprint)) {
1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (tamper_detection.ValidateContentLengthHeader(fingerprint)) {
1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      tamper_detection.ReportUMAforContentLengthHeaderValidation();
1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      tampered = true;
1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!tampered) {
1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    REPORT_TAMPER_DETECTION_UMA(
1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        scheme_is_https,
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperDetectionPassHTTPS",
1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperDetectionPassHTTP",
1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        carrier_id);
1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return tampered;
1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Constructor initializes the map of fingerprint names to codes.
1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)DataReductionProxyTamperDetection::DataReductionProxyTamperDetection(
1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const net::HttpResponseHeaders* headers,
1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const bool is_secure,
1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const unsigned carrier_id)
1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : response_headers_(headers),
1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      scheme_is_https_(is_secure),
1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      carrier_id_(carrier_id) {
1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK(headers);
1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)DataReductionProxyTamperDetection::~DataReductionProxyTamperDetection() {};
1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// |fingerprint| is Base64 encoded. Decodes it first. Then calculates the
1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// fingerprint of received Chrome-Proxy header, and compares the two to see
1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// whether they are equal or not.
1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool DataReductionProxyTamperDetection::ValidateChromeProxyHeader(
1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const std::string& fingerprint) const {
1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string received_fingerprint;
1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!base::Base64Decode(fingerprint, &received_fingerprint))
1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return true;
1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Gets the Chrome-Proxy header values with its fingerprint removed.
1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::vector<std::string> chrome_proxy_header_values;
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  GetDataReductionProxyHeaderWithFingerprintRemoved(
1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      response_headers_, &chrome_proxy_header_values);
1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Calculates the MD5 hash value of Chrome-Proxy.
1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string actual_fingerprint;
1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  GetMD5(ValuesToSortedString(&chrome_proxy_header_values),
1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)         &actual_fingerprint);
1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return received_fingerprint != actual_fingerprint;
1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void DataReductionProxyTamperDetection::
1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ReportUMAforChromeProxyHeaderValidation() const {
1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  REPORT_TAMPER_DETECTION_UMA(
1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      scheme_is_https_,
1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      "DataReductionProxy.HeaderTamperedHTTPS_ChromeProxy",
1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      "DataReductionProxy.HeaderTamperedHTTP_ChromeProxy",
1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      carrier_id_);
1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Checks whether there are other proxies/middleboxes' named after the data
1646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// reduction proxy's name in Via header. |has_chrome_proxy_via_header| marks
1656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// that whether the data reduction proxy's Via header occurs or not.
1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool DataReductionProxyTamperDetection::ValidateViaHeader(
1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const std::string& fingerprint,
1686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    bool* has_chrome_proxy_via_header) const {
1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  bool has_intermediary;
1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  *has_chrome_proxy_via_header = HasDataReductionProxyViaHeader(
1716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      response_headers_,
1726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      &has_intermediary);
1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (*has_chrome_proxy_via_header)
1756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return !has_intermediary;
1766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return true;
1776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void DataReductionProxyTamperDetection::ReportUMAforViaHeaderValidation(
1806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    bool has_chrome_proxy) const {
1816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // The Via header of the data reduction proxy is missing.
1826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!has_chrome_proxy) {
1836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    REPORT_TAMPER_DETECTION_UMA(
1846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        scheme_is_https_,
1856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperedHTTPS_Via_Missing",
1866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperedHTTP_Via_Missing",
1876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        carrier_id_);
1886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  REPORT_TAMPER_DETECTION_UMA(
1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      scheme_is_https_,
1936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      "DataReductionProxy.HeaderTamperedHTTPS_Via",
1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      "DataReductionProxy.HeaderTamperedHTTP_Via",
1956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      carrier_id_);
1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// The data reduction proxy constructs a canonical representation of values of
1996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// a list of headers. The fingerprint is constructed as follows:
2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// 1) for each header, gets the string representation of its values (same as
2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)//    ValuesToSortedString);
2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// 2) concatenates all header's string representations using ";" as a delimiter;
2036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// 3) calculates the MD5 hash value of above concatenated string;
2046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// 4) appends the header names to the fingerprint, with a delimiter "|".
2056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// The constructed fingerprint looks like:
2066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)//     [hashed_fingerprint]|header_name1|header_namer2:...
2076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)//
2086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// To check whether such a fingerprint matches the response that the Chromium
2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// client receives, the client firstly extracts the header names. For
2106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// each header, gets its string representation (by ValuesToSortedString),
2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// concatenates them and calculates the MD5 hash value. Compares the hash
2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// value to the fingerprint received from the data reduction proxy.
2136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool DataReductionProxyTamperDetection::ValidateOtherHeaders(
2146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const std::string& fingerprint) const {
2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK(!fingerprint.empty());
2166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // According to RFC 2616, "|" is not a valid character in a header name; and
2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // it is not a valid base64 encoding character, so there is no ambituity in
2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  //using it as a delimiter.
2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  net::HttpUtil::ValuesIterator it(
2216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      fingerprint.begin(), fingerprint.end(), '|');
2226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // The first value is the base64 encoded fingerprint.
2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string received_fingerprint;
2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!it.GetNext() ||
2266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      !base::Base64Decode(it.value(), &received_fingerprint)) {
2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    NOTREACHED();
2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return true;
2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string header_values;
2326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // The following values are the header names included in the fingerprint
2336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // calculation.
2346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  while (it.GetNext()) {
2356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Gets values of one header.
2366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    std::vector<std::string> response_header_values =
2376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        GetHeaderValues(response_headers_, it.value());
2386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Sorts the values and concatenate them, with delimiter ";". ";" can occur
2396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // in a header value and thus two different sets of header values could map
2406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // to the same string representation. This should be very rare.
2416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // TODO(xingx): find an unambiguous representation.
2426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    header_values += ValuesToSortedString(&response_header_values)  + ";";
2436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Calculates the MD5 hash of the concatenated string.
2466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string actual_fingerprint;
2476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  GetMD5(header_values, &actual_fingerprint);
2486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return received_fingerprint != actual_fingerprint;
2506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
2516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void DataReductionProxyTamperDetection::
2536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ReportUMAforOtherHeadersValidation() const {
2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  REPORT_TAMPER_DETECTION_UMA(
2556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      scheme_is_https_,
2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      "DataReductionProxy.HeaderTamperedHTTPS_OtherHeaders",
2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      "DataReductionProxy.HeaderTamperedHTTP_OtherHeaders",
2586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      carrier_id_);
2596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
2606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// The Content-Length value will not be reported as different if at either side
2626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// (the data reduction proxy side and the client side), the Content-Length is
2636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// missing or it cannot be decoded as a valid integer.
2646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool DataReductionProxyTamperDetection::ValidateContentLengthHeader(
2656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const std::string& fingerprint) const {
2666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  int received_content_length_fingerprint, actual_content_length;
2676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Abort, if Content-Length value from the data reduction proxy does not
2686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // exist or it cannot be converted to an integer.
2696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!base::StringToInt(fingerprint, &received_content_length_fingerprint))
2706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return false;
2716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string actual_content_length_string;
2736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Abort, if there is no Content-Length header received.
2746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!response_headers_->GetNormalizedHeader("Content-Length",
2756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      &actual_content_length_string)) {
2766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return false;
2776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Abort, if the Content-Length value cannot be converted to integer.
2806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!base::StringToInt(actual_content_length_string,
2816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                         &actual_content_length)) {
2826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return false;
2836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return received_content_length_fingerprint != actual_content_length;
2866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
2876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void DataReductionProxyTamperDetection::
2896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ReportUMAforContentLengthHeaderValidation() const {
2906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Gets MIME type of the response and reports to UMA histograms separately.
2916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Divides MIME types into 4 groups: JavaScript, CSS, Images, and others.
2926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  REPORT_TAMPER_DETECTION_UMA(
2936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      scheme_is_https_,
2946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      "DataReductionProxy.HeaderTamperedHTTPS_ContentLength",
2956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      "DataReductionProxy.HeaderTamperedHTTP_ContentLength",
2966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      carrier_id_);
2976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Gets MIME type.
2996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string mime_type;
3006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  response_headers_->GetMimeType(&mime_type);
3016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string JS1   = "text/javascript";
3036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string JS2   = "application/x-javascript";
3046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string JS3   = "application/javascript";
3056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string CSS   = "text/css";
3066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string IMAGE = "image/";
3076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  size_t mime_type_size = mime_type.size();
3096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if ((mime_type_size >= JS1.size() && LowerCaseEqualsASCII(mime_type.begin(),
3106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      mime_type.begin() + JS1.size(), JS1.c_str())) ||
3116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      (mime_type_size >= JS2.size() && LowerCaseEqualsASCII(mime_type.begin(),
3126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      mime_type.begin() + JS2.size(), JS2.c_str())) ||
3136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      (mime_type_size >= JS3.size() && LowerCaseEqualsASCII(mime_type.begin(),
3146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      mime_type.begin() + JS3.size(), JS3.c_str()))) {
3156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    REPORT_TAMPER_DETECTION_UMA(
3166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        scheme_is_https_,
3176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperedHTTPS_ContentLength_JS",
3186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperedHTTP_ContentLength_JS",
3196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        carrier_id_);
3206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else if (mime_type_size >= CSS.size() &&
3216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      LowerCaseEqualsASCII(mime_type.begin(),
3226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      mime_type.begin() + CSS.size(), CSS.c_str())) {
3236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    REPORT_TAMPER_DETECTION_UMA(
3246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        scheme_is_https_,
3256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperedHTTPS_ContentLength_CSS",
3266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperedHTTP_ContentLength_CSS",
3276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        carrier_id_);
3286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else if (mime_type_size >= IMAGE.size() &&
3296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      LowerCaseEqualsASCII(mime_type.begin(),
3306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      mime_type.begin() + IMAGE.size(), IMAGE.c_str())) {
3316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    REPORT_TAMPER_DETECTION_UMA(
3326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        scheme_is_https_,
3336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperedHTTPS_ContentLength_Image",
3346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperedHTTP_ContentLength_Image",
3356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        carrier_id_);
3366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else {
3376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    REPORT_TAMPER_DETECTION_UMA(
3386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        scheme_is_https_,
3396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperedHTTPS_ContentLength_Other",
3406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        "DataReductionProxy.HeaderTamperedHTTP_ContentLength_Other",
3416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        carrier_id_);
3426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
3436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
3446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// We construct a canonical representation of the header so that reordered
3466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// header values will produce the same fingerprint. The fingerprint is
3476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// constructed as follows:
3486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// 1) sort the values;
3496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// 2) concatenate sorted values with a "," delimiter.
3506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)std::string DataReductionProxyTamperDetection::ValuesToSortedString(
3516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    std::vector<std::string>* values) {
3526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string concatenated_values;
3536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK(values);
3546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!values) return "";
3556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::sort(values->begin(), values->end());
3576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (size_t i = 0; i < values->size(); ++i) {
3586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Concatenates with delimiter ",".
3596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    concatenated_values += (*values)[i] + ",";
3606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
3616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return concatenated_values;
3626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
3636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void DataReductionProxyTamperDetection::GetMD5(
3656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const std::string& input, std::string* output) {
3666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  base::MD5Digest digest;
3676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  base::MD5Sum(input.c_str(), input.size(), &digest);
3686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  *output = std::string(
3696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      reinterpret_cast<char*>(digest.a), ARRAYSIZE_UNSAFE(digest.a));
3706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
3716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)std::vector<std::string> DataReductionProxyTamperDetection::GetHeaderValues(
3736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const net::HttpResponseHeaders* headers,
3746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const std::string& header_name) {
3756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::vector<std::string> values;
3766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::string value;
3776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  void* iter = NULL;
3786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  while (headers->EnumerateHeader(&iter, header_name, &value)) {
3796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    values.push_back(value);
3806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
3816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return values;
3826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
3836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}  // namespace data_reduction_proxy
385