File: url_checker.cc

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (114 lines) | stat: -rw-r--r-- 3,760 bytes parent folder | download
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
105
106
107
108
109
110
111
112
113
114
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/safe_search_api/url_checker.h"

#include <utility>
#include <vector>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "base/values.h"

namespace safe_search_api {

namespace {
const size_t kDefaultCacheSize = 1000;
const size_t kDefaultCacheTimeoutSeconds = 3600;
}  // namespace

struct URLChecker::Check {
  Check(const GURL& url, CheckCallback callback);
  ~Check();

  GURL url;
  std::vector<CheckCallback> callbacks;
};

URLChecker::Check::Check(const GURL& url, CheckCallback callback) : url(url) {
  callbacks.push_back(std::move(callback));
}

URLChecker::Check::~Check() = default;

URLChecker::CheckResult::CheckResult(Classification classification,
                                     bool uncertain)
    : classification(classification),
      uncertain(uncertain),
      timestamp(base::TimeTicks::Now()) {}

URLChecker::URLChecker(std::unique_ptr<URLCheckerClient> async_checker)
    : URLChecker(std::move(async_checker), kDefaultCacheSize) {}

URLChecker::URLChecker(std::unique_ptr<URLCheckerClient> async_checker,
                       size_t cache_size)
    : async_checker_(std::move(async_checker)),
      cache_(cache_size),
      cache_timeout_(base::Seconds(kDefaultCacheTimeoutSeconds)) {}

URLChecker::~URLChecker() = default;

bool URLChecker::CheckURL(const GURL& url, CheckCallback callback) {
  auto cache_it = cache_.Get(url);
  if (cache_it != cache_.end()) {
    const CheckResult& result = cache_it->second;
    base::TimeDelta age = base::TimeTicks::Now() - result.timestamp;
    if (age < cache_timeout_) {
      DVLOG(1) << "Cache hit! " << url.spec() << " is "
               << (result.classification == Classification::UNSAFE ? "NOT" : "")
               << " safe; certain: " << !result.uncertain;
      std::move(callback).Run(url, result.classification, result.uncertain);
      return true;
    }
    DVLOG(1) << "Outdated cache entry for " << url.spec() << ", purging";
    cache_.Erase(cache_it);
  }

  // See if we already have a check in progress for this URL.
  for (const auto& check : checks_in_progress_) {
    if (check->url == url) {
      DVLOG(1) << "Adding to pending check for " << url.spec();
      check->callbacks.push_back(std::move(callback));
      return false;
    }
  }

  auto it = checks_in_progress_.insert(
      checks_in_progress_.begin(),
      std::make_unique<Check>(url, std::move(callback)));
  async_checker_->CheckURL(url,
                           base::BindOnce(&URLChecker::OnAsyncCheckComplete,
                                          weak_factory_.GetWeakPtr(), it));

  return false;
}

void URLChecker::OnAsyncCheckComplete(CheckList::iterator it,
                                      const GURL& url,
                                      ClientClassification api_classification) {
  bool uncertain = api_classification == ClientClassification::kUnknown;

  // Fallback to a |SAFE| classification when the result is not explicitly
  // marked as restricted.
  Classification classification = Classification::SAFE;
  if (api_classification == ClientClassification::kRestricted) {
    classification = Classification::UNSAFE;
  }

  std::vector<CheckCallback> callbacks = std::move(it->get()->callbacks);
  checks_in_progress_.erase(it);

  if (!uncertain) {
    cache_.Put(url, CheckResult(classification, uncertain));
  }

  for (CheckCallback& callback : callbacks) {
    std::move(callback).Run(url, classification, uncertain);
  }
}

}  // namespace safe_search_api