| Index: net/reporting/reporting_header_parser.cc
|
| diff --git a/net/reporting/reporting_header_parser.cc b/net/reporting/reporting_header_parser.cc
|
| index 8a0c7b2b9c11e4c273585d7475a603dfa13cc2cd..058b33548b2ca47a8c06d10178ab73ba4c995071 100644
|
| --- a/net/reporting/reporting_header_parser.cc
|
| +++ b/net/reporting/reporting_header_parser.cc
|
| @@ -8,6 +8,7 @@
|
|
|
| #include "base/json/json_reader.h"
|
| #include "base/logging.h"
|
| +#include "base/metrics/histogram_macros.h"
|
| #include "base/time/tick_clock.h"
|
| #include "base/time/time.h"
|
| #include "base/values.h"
|
| @@ -19,39 +20,82 @@ namespace net {
|
|
|
| namespace {
|
|
|
| +enum class HeaderOutcome {
|
| + DISCARDED_NO_REPORTING_SERVICE = 0,
|
| + DISCARDED_INVALID_SSL_INFO = 1,
|
| + DISCARDED_CERT_STATUS_ERROR = 2,
|
| + DISCARDED_INVALID_JSON = 3,
|
| + PARSED = 4,
|
| +
|
| + MAX
|
| +};
|
| +
|
| +void RecordHeaderOutcome(HeaderOutcome outcome) {
|
| + UMA_HISTOGRAM_ENUMERATION("Reporting.HeaderOutcome", outcome,
|
| + HeaderOutcome::MAX);
|
| +}
|
| +
|
| +enum class HeaderEndpointOutcome {
|
| + DISCARDED_NOT_DICTIONARY = 0,
|
| + DISCARDED_ENDPOINT_MISSING = 1,
|
| + DISCARDED_ENDPOINT_NOT_STRING = 2,
|
| + DISCARDED_ENDPOINT_INVALID = 3,
|
| + DISCARDED_ENDPOINT_INSECURE = 4,
|
| + DISCARDED_TTL_MISSING = 5,
|
| + DISCARDED_TTL_NOT_INTEGER = 6,
|
| + DISCARDED_TTL_NEGATIVE = 7,
|
| + DISCARDED_GROUP_NOT_STRING = 8,
|
| + REMOVED = 9,
|
| + SET_REJECTED_BY_DELEGATE = 10,
|
| + SET = 11,
|
| +
|
| + MAX
|
| +};
|
| +
|
| +void RecordHeaderEndpointOutcome(HeaderEndpointOutcome outcome) {
|
| + UMA_HISTOGRAM_ENUMERATION("Reporting.HeaderEndpointOutcome", outcome,
|
| + HeaderEndpointOutcome::MAX);
|
| +}
|
| +
|
| const char kUrlKey[] = "url";
|
| const char kIncludeSubdomainsKey[] = "includeSubdomains";
|
| const char kGroupKey[] = "group";
|
| const char kGroupDefaultValue[] = "default";
|
| const char kMaxAgeKey[] = "max-age";
|
|
|
| -void ProcessEndpoint(ReportingDelegate* delegate,
|
| - ReportingCache* cache,
|
| - base::TimeTicks now,
|
| - const GURL& url,
|
| - const base::Value& value) {
|
| +HeaderEndpointOutcome ProcessEndpoint(ReportingDelegate* delegate,
|
| + ReportingCache* cache,
|
| + base::TimeTicks now,
|
| + const GURL& url,
|
| + const base::Value& value) {
|
| const base::DictionaryValue* dict = nullptr;
|
| if (!value.GetAsDictionary(&dict))
|
| - return;
|
| + return HeaderEndpointOutcome::DISCARDED_NOT_DICTIONARY;
|
| DCHECK(dict);
|
|
|
| std::string endpoint_url_string;
|
| + if (!dict->HasKey(kUrlKey))
|
| + return HeaderEndpointOutcome::DISCARDED_ENDPOINT_MISSING;
|
| if (!dict->GetString(kUrlKey, &endpoint_url_string))
|
| - return;
|
| + return HeaderEndpointOutcome::DISCARDED_ENDPOINT_NOT_STRING;
|
|
|
| GURL endpoint_url(endpoint_url_string);
|
| if (!endpoint_url.is_valid())
|
| - return;
|
| + return HeaderEndpointOutcome::DISCARDED_ENDPOINT_INVALID;
|
| if (!endpoint_url.SchemeIsCryptographic())
|
| - return;
|
| + return HeaderEndpointOutcome::DISCARDED_ENDPOINT_INSECURE;
|
|
|
| int ttl_sec = -1;
|
| - if (!dict->GetInteger(kMaxAgeKey, &ttl_sec) || ttl_sec < 0)
|
| - return;
|
| + if (!dict->HasKey(kMaxAgeKey))
|
| + return HeaderEndpointOutcome::DISCARDED_TTL_MISSING;
|
| + if (!dict->GetInteger(kMaxAgeKey, &ttl_sec))
|
| + return HeaderEndpointOutcome::DISCARDED_TTL_NOT_INTEGER;
|
| + if (ttl_sec < 0)
|
| + return HeaderEndpointOutcome::DISCARDED_TTL_NEGATIVE;
|
|
|
| std::string group = kGroupDefaultValue;
|
| if (dict->HasKey(kGroupKey) && !dict->GetString(kGroupKey, &group))
|
| - return;
|
| + return HeaderEndpointOutcome::DISCARDED_GROUP_NOT_STRING;
|
|
|
| ReportingClient::Subdomains subdomains = ReportingClient::Subdomains::EXCLUDE;
|
| bool subdomains_bool = false;
|
| @@ -61,21 +105,37 @@ void ProcessEndpoint(ReportingDelegate* delegate,
|
| subdomains = ReportingClient::Subdomains::INCLUDE;
|
| }
|
|
|
| - url::Origin origin(url);
|
| + if (ttl_sec == 0) {
|
| + cache->RemoveClientForOriginAndEndpoint(url::Origin(url), endpoint_url);
|
| + return HeaderEndpointOutcome::REMOVED;
|
| + }
|
|
|
| + url::Origin origin(url);
|
| if (!delegate->CanSetClient(origin, endpoint_url))
|
| - return;
|
| + return HeaderEndpointOutcome::SET_REJECTED_BY_DELEGATE;
|
|
|
| - if (ttl_sec > 0) {
|
| - cache->SetClient(origin, endpoint_url, subdomains, group,
|
| - now + base::TimeDelta::FromSeconds(ttl_sec));
|
| - } else {
|
| - cache->RemoveClientForOriginAndEndpoint(origin, endpoint_url);
|
| - }
|
| + cache->SetClient(origin, endpoint_url, subdomains, group,
|
| + now + base::TimeDelta::FromSeconds(ttl_sec));
|
| + return HeaderEndpointOutcome::SET;
|
| }
|
|
|
| } // namespace
|
|
|
| +// static
|
| +void ReportingHeaderParser::RecordHeaderDiscardedForNoReportingService() {
|
| + RecordHeaderOutcome(HeaderOutcome::DISCARDED_NO_REPORTING_SERVICE);
|
| +}
|
| +
|
| +// static
|
| +void ReportingHeaderParser::RecordHeaderDiscardedForInvalidSSLInfo() {
|
| + RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_SSL_INFO);
|
| +}
|
| +
|
| +// static
|
| +void ReportingHeaderParser::RecordHeaderDiscardedForCertStatusError() {
|
| + RecordHeaderOutcome(HeaderOutcome::DISCARDED_CERT_STATUS_ERROR);
|
| +}
|
| +
|
| // static
|
| void ReportingHeaderParser::ParseHeader(ReportingContext* context,
|
| const GURL& url,
|
| @@ -84,8 +144,10 @@ void ReportingHeaderParser::ParseHeader(ReportingContext* context,
|
|
|
| std::unique_ptr<base::Value> value =
|
| base::JSONReader::Read("[" + json_value + "]");
|
| - if (!value)
|
| + if (!value) {
|
| + RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_JSON);
|
| return;
|
| + }
|
|
|
| const base::ListValue* list = nullptr;
|
| bool is_list = value->GetAsList(&list);
|
| @@ -98,7 +160,8 @@ void ReportingHeaderParser::ParseHeader(ReportingContext* context,
|
| const base::Value* endpoint = nullptr;
|
| bool got_endpoint = list->Get(i, &endpoint);
|
| DCHECK(got_endpoint);
|
| - ProcessEndpoint(delegate, cache, now, url, *endpoint);
|
| + RecordHeaderEndpointOutcome(
|
| + ProcessEndpoint(delegate, cache, now, url, *endpoint));
|
| }
|
| }
|
|
|
|
|