| // Copyright 2018 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 "components/optimization_guide/hints_component_util.h" |
| |
| #include <string> |
| #include <utility> |
| |
| #include "base/files/file.h" |
| #include "base/files/file_util.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/stringprintf.h" |
| #include "components/optimization_guide/bloom_filter.h" |
| #include "components/optimization_guide/hints_component_info.h" |
| #include "components/optimization_guide/hints_processing_util.h" |
| #include "components/optimization_guide/optimization_filter.h" |
| #include "components/optimization_guide/optimization_guide_features.h" |
| |
| namespace optimization_guide { |
| |
| namespace { |
| |
| const char kProcessHintsComponentResultHistogramString[] = |
| "OptimizationGuide.ProcessHintsResult"; |
| |
| // Populates |out_result| with |result| if |out_result| is provided. |
| void PopulateProcessHintsComponentResultIfSet( |
| ProcessHintsComponentResult result, |
| ProcessHintsComponentResult* out_result) { |
| if (out_result) |
| *out_result = result; |
| } |
| |
| // Populates |out_status| with |status| if |out_status| is provided. |
| void PopulateOptimizationFilterStatusIfSet( |
| OptimizationFilterStatus status, |
| OptimizationFilterStatus* out_status) { |
| if (out_status) |
| *out_status = status; |
| } |
| |
| // Attempts to construct a valid bloom filter from the given |
| // |optimization_filter|. If given, |out_status| will be populated with the |
| // status of the operation. If a valid bloom filter cannot be constructed, |
| // nullptr is returned. |
| std::unique_ptr<BloomFilter> ProcessBloomFilter( |
| const proto::OptimizationFilter& optimization_filter, |
| OptimizationFilterStatus* out_status) { |
| const auto& bloom_filter_proto = optimization_filter.bloom_filter(); |
| DCHECK_GT(bloom_filter_proto.num_hash_functions(), 0u); |
| DCHECK_GT(bloom_filter_proto.num_bits(), 0u); |
| DCHECK(bloom_filter_proto.has_data()); |
| |
| if (!bloom_filter_proto.has_data() || bloom_filter_proto.num_bits() <= 0 || |
| bloom_filter_proto.num_bits() > bloom_filter_proto.data().size() * 8) { |
| DLOG(ERROR) << "Bloom filter config issue"; |
| PopulateOptimizationFilterStatusIfSet( |
| OptimizationFilterStatus::kFailedServerBlacklistBadConfig, out_status); |
| return nullptr; |
| } |
| |
| if (static_cast<int>(bloom_filter_proto.num_bits()) > |
| features::MaxServerBloomFilterByteSize() * 8) { |
| DLOG(ERROR) << "Bloom filter data exceeds maximum size of " |
| << optimization_guide::features::MaxServerBloomFilterByteSize() |
| << " bytes"; |
| PopulateOptimizationFilterStatusIfSet( |
| OptimizationFilterStatus::kFailedServerBlacklistTooBig, out_status); |
| return nullptr; |
| } |
| |
| std::unique_ptr<BloomFilter> bloom_filter = std::make_unique<BloomFilter>( |
| bloom_filter_proto.num_hash_functions(), bloom_filter_proto.num_bits(), |
| bloom_filter_proto.data()); |
| PopulateOptimizationFilterStatusIfSet( |
| OptimizationFilterStatus::kCreatedServerBlacklist, out_status); |
| return bloom_filter; |
| } |
| |
| // Attempts to construct a valid RegexpList from the given |
| // |optimization_filter|. If given, |out_status| will be populated with the |
| // status of the operation. If a valid RegexpList cannot be constructed, nullptr |
| // is returned. |
| std::unique_ptr<RegexpList> ProcessRegexps( |
| const proto::OptimizationFilter& optimization_filter, |
| OptimizationFilterStatus* out_status) { |
| std::unique_ptr<RegexpList> regexps = std::make_unique<RegexpList>(); |
| for (int i = 0; i < optimization_filter.regexps_size(); ++i) { |
| regexps->emplace_back( |
| std::make_unique<re2::RE2>(optimization_filter.regexps(i))); |
| if (!regexps->at(i)->ok()) { |
| PopulateOptimizationFilterStatusIfSet( |
| OptimizationFilterStatus::kInvalidRegexp, out_status); |
| return nullptr; |
| } |
| } |
| |
| PopulateOptimizationFilterStatusIfSet( |
| OptimizationFilterStatus::kCreatedServerBlacklist, out_status); |
| return regexps; |
| } |
| |
| } // namespace |
| |
| const char kComponentHintsUpdatedResultHistogramString[] = |
| "OptimizationGuide.UpdateComponentHints.Result"; |
| |
| void RecordProcessHintsComponentResult(ProcessHintsComponentResult result) { |
| UMA_HISTOGRAM_ENUMERATION(kProcessHintsComponentResultHistogramString, |
| result); |
| } |
| |
| std::unique_ptr<proto::Configuration> ProcessHintsComponent( |
| const HintsComponentInfo& component_info, |
| ProcessHintsComponentResult* out_result) { |
| if (!component_info.version.IsValid() || component_info.path.empty()) { |
| PopulateProcessHintsComponentResultIfSet( |
| ProcessHintsComponentResult::kFailedInvalidParameters, out_result); |
| return nullptr; |
| } |
| |
| std::string binary_pb; |
| if (!base::ReadFileToString(component_info.path, &binary_pb)) { |
| PopulateProcessHintsComponentResultIfSet( |
| ProcessHintsComponentResult::kFailedReadingFile, out_result); |
| return nullptr; |
| } |
| |
| std::unique_ptr<proto::Configuration> proto_configuration = |
| std::make_unique<proto::Configuration>(); |
| if (!proto_configuration->ParseFromString(binary_pb)) { |
| PopulateProcessHintsComponentResultIfSet( |
| ProcessHintsComponentResult::kFailedInvalidConfiguration, out_result); |
| return nullptr; |
| } |
| |
| PopulateProcessHintsComponentResultIfSet( |
| ProcessHintsComponentResult::kSuccess, out_result); |
| return proto_configuration; |
| } |
| |
| void RecordOptimizationFilterStatus(proto::OptimizationType optimization_type, |
| OptimizationFilterStatus status) { |
| base::UmaHistogramExactLinear( |
| base::StringPrintf( |
| "OptimizationGuide.OptimizationFilterStatus.%s", |
| GetStringNameForOptimizationType(optimization_type).c_str()), |
| static_cast<int>(status), |
| static_cast<int>(OptimizationFilterStatus::kMaxValue)); |
| } |
| |
| std::unique_ptr<OptimizationFilter> ProcessOptimizationFilter( |
| const proto::OptimizationFilter& optimization_filter, |
| OptimizationFilterStatus* out_status) { |
| std::unique_ptr<BloomFilter> bloom_filter; |
| if (optimization_filter.has_bloom_filter()) { |
| bloom_filter = ProcessBloomFilter(optimization_filter, out_status); |
| if (!bloom_filter) |
| return nullptr; |
| } |
| |
| std::unique_ptr<RegexpList> regexps; |
| if (optimization_filter.regexps_size() > 0) { |
| regexps = ProcessRegexps(optimization_filter, out_status); |
| if (!regexps) |
| return nullptr; |
| } |
| |
| return std::make_unique<OptimizationFilter>(std::move(bloom_filter), |
| std::move(regexps)); |
| } |
| |
| } // namespace optimization_guide |