opt_out_blocklist_data.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Copyright 2018 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. #include "components/blocklist/opt_out_blocklist/opt_out_blocklist_data.h"
  5. #include "base/memory/ptr_util.h"
  6. namespace blocklist {
  7. BlocklistData::BlocklistData(std::unique_ptr<Policy> session_policy,
  8. std::unique_ptr<Policy> persistent_policy,
  9. std::unique_ptr<Policy> host_policy,
  10. std::unique_ptr<Policy> type_policy,
  11. size_t max_hosts,
  12. AllowedTypesAndVersions allowed_types)
  13. : session_policy_(std::move(session_policy)),
  14. persistent_policy_(std::move(persistent_policy)),
  15. host_policy_(std::move(host_policy)),
  16. max_hosts_(max_hosts),
  17. type_policy_(std::move(type_policy)),
  18. allowed_types_(std::move(allowed_types)) {
  19. DCHECK_GE(100u, max_hosts);
  20. }
  21. BlocklistData::~BlocklistData() = default;
  22. void BlocklistData::ClearData() {
  23. session_block_list_item_.reset();
  24. persistent_block_list_item_.reset();
  25. block_list_item_host_map_.clear();
  26. block_list_item_type_map_.clear();
  27. }
  28. void BlocklistData::AddEntry(const std::string& host_name,
  29. bool opt_out,
  30. int type,
  31. base::Time time,
  32. bool is_from_persistent_storage) {
  33. // Add to the session based rule if it is enabled.
  34. if (session_policy_ && !is_from_persistent_storage) {
  35. if (!session_block_list_item_) {
  36. session_block_list_item_ = std::make_unique<OptOutBlocklistItem>(
  37. session_policy_->history, session_policy_->threshold,
  38. session_policy_->duration);
  39. }
  40. session_block_list_item_->AddEntry(opt_out, time);
  41. }
  42. // Add to the persistent rule if it is enabled.
  43. if (persistent_policy_) {
  44. if (!persistent_block_list_item_) {
  45. persistent_block_list_item_ = std::make_unique<OptOutBlocklistItem>(
  46. persistent_policy_->history, persistent_policy_->threshold,
  47. persistent_policy_->duration);
  48. }
  49. persistent_block_list_item_->AddEntry(opt_out, time);
  50. }
  51. // Add to the host rule if it is enabled. Remove hosts if there are more than
  52. // |max_hosts_| in the map.
  53. if (host_policy_) {
  54. auto item = block_list_item_host_map_.find(host_name);
  55. if (item == block_list_item_host_map_.end()) {
  56. auto value = block_list_item_host_map_.emplace(
  57. std::piecewise_construct, std::forward_as_tuple(host_name),
  58. std::forward_as_tuple(host_policy_->history, host_policy_->threshold,
  59. host_policy_->duration));
  60. DCHECK(value.second);
  61. item = value.first;
  62. }
  63. item->second.AddEntry(opt_out, time);
  64. if (max_hosts_ > 0 && block_list_item_host_map_.size() > max_hosts_)
  65. EvictOldestHost();
  66. }
  67. if (type_policy_) {
  68. auto item = block_list_item_type_map_.find(type);
  69. if (item == block_list_item_type_map_.end()) {
  70. auto value = block_list_item_type_map_.emplace(
  71. std::piecewise_construct, std::forward_as_tuple(type),
  72. std::forward_as_tuple(type_policy_->history, type_policy_->threshold,
  73. type_policy_->duration));
  74. DCHECK(value.second);
  75. item = value.first;
  76. }
  77. item->second.AddEntry(opt_out, time);
  78. }
  79. }
  80. BlocklistReason BlocklistData::IsAllowed(
  81. const std::string& host_name,
  82. int type,
  83. bool ignore_long_term_block_list_rules,
  84. base::Time time,
  85. std::vector<BlocklistReason>* passed_reasons) const {
  86. // Check the session rule.
  87. if (session_policy_) {
  88. if (session_block_list_item_ &&
  89. session_block_list_item_->IsBlockListed(time)) {
  90. return BlocklistReason::kUserOptedOutInSession;
  91. }
  92. passed_reasons->push_back(BlocklistReason::kUserOptedOutInSession);
  93. }
  94. // Check whether the persistent rules should be checked this time.
  95. if (ignore_long_term_block_list_rules)
  96. return BlocklistReason::kAllowed;
  97. // Check the persistent rule.
  98. if (persistent_policy_) {
  99. if (IsUserOptedOutInGeneral(time)) {
  100. return BlocklistReason::kUserOptedOutInGeneral;
  101. }
  102. passed_reasons->push_back(BlocklistReason::kUserOptedOutInGeneral);
  103. }
  104. // Check the host rule.
  105. if (host_policy_) {
  106. if (IsHostBlocklisted(host_name, time))
  107. return BlocklistReason::kUserOptedOutOfHost;
  108. passed_reasons->push_back(BlocklistReason::kUserOptedOutOfHost);
  109. }
  110. // Only allowed types should be recorded.
  111. DCHECK(allowed_types_.find(type) != allowed_types_.end());
  112. // Check the type rule.
  113. if (type_policy_) {
  114. auto item = block_list_item_type_map_.find(type);
  115. if (item != block_list_item_type_map_.end() &&
  116. item->second.IsBlockListed(time)) {
  117. return BlocklistReason::kUserOptedOutOfType;
  118. }
  119. passed_reasons->push_back(BlocklistReason::kUserOptedOutOfType);
  120. }
  121. return BlocklistReason::kAllowed;
  122. }
  123. void BlocklistData::EvictOldestHost() {
  124. DCHECK_LT(max_hosts_, block_list_item_host_map_.size());
  125. absl::optional<base::Time> oldest_opt_out;
  126. std::string key_to_delete;
  127. for (auto& item : block_list_item_host_map_) {
  128. absl::optional<base::Time> most_recent_opt_out =
  129. item.second.most_recent_opt_out_time();
  130. if (!most_recent_opt_out) {
  131. // If there is no opt out time, this is a good choice to evict.
  132. key_to_delete = item.first;
  133. break;
  134. }
  135. if (!oldest_opt_out ||
  136. most_recent_opt_out.value() < oldest_opt_out.value()) {
  137. oldest_opt_out = most_recent_opt_out.value();
  138. key_to_delete = item.first;
  139. }
  140. }
  141. block_list_item_host_map_.erase(key_to_delete);
  142. }
  143. bool BlocklistData::IsHostBlocklisted(const std::string& host_name,
  144. base::Time time) const {
  145. auto item = block_list_item_host_map_.find(host_name);
  146. return item != block_list_item_host_map_.end() &&
  147. item->second.IsBlockListed(time);
  148. }
  149. bool BlocklistData::IsUserOptedOutInGeneral(base::Time time) const {
  150. return persistent_block_list_item_ &&
  151. persistent_block_list_item_->IsBlockListed(time);
  152. }
  153. } // namespace blocklist