summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ssl/common_name_mismatch_handler.cc
blob: 941127b7d95d4fda27dbc828fdcc54eb8cd93cd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ssl/common_name_mismatch_handler.h"

#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/ssl/ssl_error_classification.h"
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request_status.h"

CommonNameMismatchHandler::CommonNameMismatchHandler(
    const GURL& request_url,
    const scoped_refptr<net::URLRequestContextGetter>& request_context)
    : request_url_(request_url), request_context_(request_context) {}

CommonNameMismatchHandler::~CommonNameMismatchHandler() {}

// static
CommonNameMismatchHandler::TestingState
    CommonNameMismatchHandler::testing_state_ = NOT_TESTING;

void CommonNameMismatchHandler::CheckSuggestedUrl(
    const GURL& url,
    const CheckUrlCallback& callback) {
  // Should be used only in tests.
  if (testing_state_ == IGNORE_REQUESTS_FOR_TESTING)
    return;

  DCHECK(CalledOnValidThread());
  DCHECK(!IsCheckingSuggestedUrl());
  DCHECK(check_url_callback_.is_null());

  check_url_callback_ = callback;

  url_fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::HEAD, this);
  url_fetcher_->SetAutomaticallyRetryOn5xx(false);
  url_fetcher_->SetRequestContext(request_context_.get());

  // Can't safely use net::LOAD_DISABLE_CERT_REVOCATION_CHECKING here,
  // since then the connection may be reused without checking the cert.
  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
                             net::LOAD_DO_NOT_SEND_COOKIES |
                             net::LOAD_DO_NOT_SEND_AUTH_DATA);
  url_fetcher_->Start();
}

// static
bool CommonNameMismatchHandler::GetSuggestedUrl(
    const GURL& request_url,
    const std::vector<std::string>& dns_names,
    GURL* suggested_url) {
  std::string host_name = request_url.host();
  std::string www_mismatch_hostname;
  if (!SSLErrorClassification::GetWWWSubDomainMatch(host_name, dns_names,
                                                    &www_mismatch_hostname)) {
    return false;
  }
  // The full URL should be pinged, not just the new hostname. So, get the
  // |suggested_url| with the |request_url|'s hostname replaced with
  // new hostname. Keep resource path, query params the same.
  GURL::Replacements replacements;
  replacements.SetHostStr(www_mismatch_hostname);
  *suggested_url = request_url.ReplaceComponents(replacements);
  return true;
}

void CommonNameMismatchHandler::Cancel() {
  url_fetcher_.reset();
  check_url_callback_.Reset();
}

void CommonNameMismatchHandler::OnURLFetchComplete(
    const net::URLFetcher* source) {
  DCHECK(CalledOnValidThread());
  DCHECK(IsCheckingSuggestedUrl());
  DCHECK_EQ(url_fetcher_.get(), source);
  DCHECK(!check_url_callback_.is_null());
  DCHECK(!url_fetcher_.get()->GetStatus().is_io_pending());

  SuggestedUrlCheckResult result = SUGGESTED_URL_NOT_AVAILABLE;
  // Save a copy of |suggested_url| so it can be used after |url_fetcher_|
  // is destroyed.
  const GURL suggested_url = url_fetcher_->GetOriginalURL();
  const GURL& landing_url = url_fetcher_->GetURL();

  // Make sure the |landing_url| is a HTTPS page and returns a proper response
  // code.
  if (url_fetcher_.get()->GetResponseCode() == 200 &&
      landing_url.SchemeIsCryptographic() &&
      landing_url.host() != request_url_.host()) {
    result = SUGGESTED_URL_AVAILABLE;
  }
  url_fetcher_.reset();
  base::ResetAndReturn(&check_url_callback_).Run(result, suggested_url);
}

bool CommonNameMismatchHandler::IsCheckingSuggestedUrl() const {
  return url_fetcher_;
}