OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/reporting/reporting_header_parser.h" | 5 #include "net/reporting/reporting_header_parser.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/metrics/histogram_macros.h" |
11 #include "base/time/tick_clock.h" | 12 #include "base/time/tick_clock.h" |
12 #include "base/time/time.h" | 13 #include "base/time/time.h" |
13 #include "base/values.h" | 14 #include "base/values.h" |
14 #include "net/reporting/reporting_cache.h" | 15 #include "net/reporting/reporting_cache.h" |
15 #include "net/reporting/reporting_context.h" | 16 #include "net/reporting/reporting_context.h" |
16 #include "net/reporting/reporting_delegate.h" | 17 #include "net/reporting/reporting_delegate.h" |
17 | 18 |
18 namespace net { | 19 namespace net { |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
| 23 enum class HeaderOutcome { |
| 24 DISCARDED_NO_REPORTING_SERVICE = 0, |
| 25 DISCARDED_INVALID_SSL_INFO = 1, |
| 26 DISCARDED_CERT_STATUS_ERROR = 2, |
| 27 DISCARDED_INVALID_JSON = 3, |
| 28 PARSED = 4, |
| 29 |
| 30 MAX |
| 31 }; |
| 32 |
| 33 void RecordHeaderOutcome(HeaderOutcome outcome) { |
| 34 UMA_HISTOGRAM_ENUMERATION("Reporting.HeaderOutcome", outcome, |
| 35 HeaderOutcome::MAX); |
| 36 } |
| 37 |
| 38 enum class HeaderEndpointOutcome { |
| 39 DISCARDED_NOT_DICTIONARY = 0, |
| 40 DISCARDED_ENDPOINT_MISSING = 1, |
| 41 DISCARDED_ENDPOINT_NOT_STRING = 2, |
| 42 DISCARDED_ENDPOINT_INVALID = 3, |
| 43 DISCARDED_ENDPOINT_INSECURE = 4, |
| 44 DISCARDED_TTL_MISSING = 5, |
| 45 DISCARDED_TTL_NOT_INTEGER = 6, |
| 46 DISCARDED_TTL_NEGATIVE = 7, |
| 47 DISCARDED_GROUP_NOT_STRING = 8, |
| 48 REMOVED = 9, |
| 49 SET_REJECTED_BY_DELEGATE = 10, |
| 50 SET = 11, |
| 51 |
| 52 MAX |
| 53 }; |
| 54 |
| 55 void RecordHeaderEndpointOutcome(HeaderEndpointOutcome outcome) { |
| 56 UMA_HISTOGRAM_ENUMERATION("Reporting.HeaderEndpointOutcome", outcome, |
| 57 HeaderEndpointOutcome::MAX); |
| 58 } |
| 59 |
22 const char kUrlKey[] = "url"; | 60 const char kUrlKey[] = "url"; |
23 const char kIncludeSubdomainsKey[] = "includeSubdomains"; | 61 const char kIncludeSubdomainsKey[] = "includeSubdomains"; |
24 const char kGroupKey[] = "group"; | 62 const char kGroupKey[] = "group"; |
25 const char kGroupDefaultValue[] = "default"; | 63 const char kGroupDefaultValue[] = "default"; |
26 const char kMaxAgeKey[] = "max-age"; | 64 const char kMaxAgeKey[] = "max-age"; |
27 | 65 |
28 void ProcessEndpoint(ReportingDelegate* delegate, | 66 HeaderEndpointOutcome ProcessEndpoint(ReportingDelegate* delegate, |
29 ReportingCache* cache, | 67 ReportingCache* cache, |
30 base::TimeTicks now, | 68 base::TimeTicks now, |
31 const GURL& url, | 69 const GURL& url, |
32 const base::Value& value) { | 70 const base::Value& value) { |
33 const base::DictionaryValue* dict = nullptr; | 71 const base::DictionaryValue* dict = nullptr; |
34 if (!value.GetAsDictionary(&dict)) | 72 if (!value.GetAsDictionary(&dict)) |
35 return; | 73 return HeaderEndpointOutcome::DISCARDED_NOT_DICTIONARY; |
36 DCHECK(dict); | 74 DCHECK(dict); |
37 | 75 |
38 std::string endpoint_url_string; | 76 std::string endpoint_url_string; |
| 77 if (!dict->HasKey(kUrlKey)) |
| 78 return HeaderEndpointOutcome::DISCARDED_ENDPOINT_MISSING; |
39 if (!dict->GetString(kUrlKey, &endpoint_url_string)) | 79 if (!dict->GetString(kUrlKey, &endpoint_url_string)) |
40 return; | 80 return HeaderEndpointOutcome::DISCARDED_ENDPOINT_NOT_STRING; |
41 | 81 |
42 GURL endpoint_url(endpoint_url_string); | 82 GURL endpoint_url(endpoint_url_string); |
43 if (!endpoint_url.is_valid()) | 83 if (!endpoint_url.is_valid()) |
44 return; | 84 return HeaderEndpointOutcome::DISCARDED_ENDPOINT_INVALID; |
45 if (!endpoint_url.SchemeIsCryptographic()) | 85 if (!endpoint_url.SchemeIsCryptographic()) |
46 return; | 86 return HeaderEndpointOutcome::DISCARDED_ENDPOINT_INSECURE; |
47 | 87 |
48 int ttl_sec = -1; | 88 int ttl_sec = -1; |
49 if (!dict->GetInteger(kMaxAgeKey, &ttl_sec) || ttl_sec < 0) | 89 if (!dict->HasKey(kMaxAgeKey)) |
50 return; | 90 return HeaderEndpointOutcome::DISCARDED_TTL_MISSING; |
| 91 if (!dict->GetInteger(kMaxAgeKey, &ttl_sec)) |
| 92 return HeaderEndpointOutcome::DISCARDED_TTL_NOT_INTEGER; |
| 93 if (ttl_sec < 0) |
| 94 return HeaderEndpointOutcome::DISCARDED_TTL_NEGATIVE; |
51 | 95 |
52 std::string group = kGroupDefaultValue; | 96 std::string group = kGroupDefaultValue; |
53 if (dict->HasKey(kGroupKey) && !dict->GetString(kGroupKey, &group)) | 97 if (dict->HasKey(kGroupKey) && !dict->GetString(kGroupKey, &group)) |
54 return; | 98 return HeaderEndpointOutcome::DISCARDED_GROUP_NOT_STRING; |
55 | 99 |
56 ReportingClient::Subdomains subdomains = ReportingClient::Subdomains::EXCLUDE; | 100 ReportingClient::Subdomains subdomains = ReportingClient::Subdomains::EXCLUDE; |
57 bool subdomains_bool = false; | 101 bool subdomains_bool = false; |
58 if (dict->HasKey(kIncludeSubdomainsKey) && | 102 if (dict->HasKey(kIncludeSubdomainsKey) && |
59 dict->GetBoolean(kIncludeSubdomainsKey, &subdomains_bool) && | 103 dict->GetBoolean(kIncludeSubdomainsKey, &subdomains_bool) && |
60 subdomains_bool == true) { | 104 subdomains_bool == true) { |
61 subdomains = ReportingClient::Subdomains::INCLUDE; | 105 subdomains = ReportingClient::Subdomains::INCLUDE; |
62 } | 106 } |
63 | 107 |
| 108 if (ttl_sec == 0) { |
| 109 cache->RemoveClientForOriginAndEndpoint(url::Origin(url), endpoint_url); |
| 110 return HeaderEndpointOutcome::REMOVED; |
| 111 } |
| 112 |
64 url::Origin origin(url); | 113 url::Origin origin(url); |
| 114 if (!delegate->CanSetClient(origin, endpoint_url)) |
| 115 return HeaderEndpointOutcome::SET_REJECTED_BY_DELEGATE; |
65 | 116 |
66 if (!delegate->CanSetClient(origin, endpoint_url)) | 117 cache->SetClient(origin, endpoint_url, subdomains, group, |
67 return; | 118 now + base::TimeDelta::FromSeconds(ttl_sec)); |
68 | 119 return HeaderEndpointOutcome::SET; |
69 if (ttl_sec > 0) { | |
70 cache->SetClient(origin, endpoint_url, subdomains, group, | |
71 now + base::TimeDelta::FromSeconds(ttl_sec)); | |
72 } else { | |
73 cache->RemoveClientForOriginAndEndpoint(origin, endpoint_url); | |
74 } | |
75 } | 120 } |
76 | 121 |
77 } // namespace | 122 } // namespace |
78 | 123 |
79 // static | 124 // static |
| 125 void ReportingHeaderParser::RecordHeaderDiscardedForNoReportingService() { |
| 126 RecordHeaderOutcome(HeaderOutcome::DISCARDED_NO_REPORTING_SERVICE); |
| 127 } |
| 128 |
| 129 // static |
| 130 void ReportingHeaderParser::RecordHeaderDiscardedForInvalidSSLInfo() { |
| 131 RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_SSL_INFO); |
| 132 } |
| 133 |
| 134 // static |
| 135 void ReportingHeaderParser::RecordHeaderDiscardedForCertStatusError() { |
| 136 RecordHeaderOutcome(HeaderOutcome::DISCARDED_CERT_STATUS_ERROR); |
| 137 } |
| 138 |
| 139 // static |
80 void ReportingHeaderParser::ParseHeader(ReportingContext* context, | 140 void ReportingHeaderParser::ParseHeader(ReportingContext* context, |
81 const GURL& url, | 141 const GURL& url, |
82 const std::string& json_value) { | 142 const std::string& json_value) { |
83 DCHECK(url.SchemeIsCryptographic()); | 143 DCHECK(url.SchemeIsCryptographic()); |
84 | 144 |
85 std::unique_ptr<base::Value> value = | 145 std::unique_ptr<base::Value> value = |
86 base::JSONReader::Read("[" + json_value + "]"); | 146 base::JSONReader::Read("[" + json_value + "]"); |
87 if (!value) | 147 if (!value) { |
| 148 RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_JSON); |
88 return; | 149 return; |
| 150 } |
89 | 151 |
90 const base::ListValue* list = nullptr; | 152 const base::ListValue* list = nullptr; |
91 bool is_list = value->GetAsList(&list); | 153 bool is_list = value->GetAsList(&list); |
92 DCHECK(is_list); | 154 DCHECK(is_list); |
93 | 155 |
94 ReportingDelegate* delegate = context->delegate(); | 156 ReportingDelegate* delegate = context->delegate(); |
95 ReportingCache* cache = context->cache(); | 157 ReportingCache* cache = context->cache(); |
96 base::TimeTicks now = context->tick_clock()->NowTicks(); | 158 base::TimeTicks now = context->tick_clock()->NowTicks(); |
97 for (size_t i = 0; i < list->GetSize(); i++) { | 159 for (size_t i = 0; i < list->GetSize(); i++) { |
98 const base::Value* endpoint = nullptr; | 160 const base::Value* endpoint = nullptr; |
99 bool got_endpoint = list->Get(i, &endpoint); | 161 bool got_endpoint = list->Get(i, &endpoint); |
100 DCHECK(got_endpoint); | 162 DCHECK(got_endpoint); |
101 ProcessEndpoint(delegate, cache, now, url, *endpoint); | 163 RecordHeaderEndpointOutcome( |
| 164 ProcessEndpoint(delegate, cache, now, url, *endpoint)); |
102 } | 165 } |
103 } | 166 } |
104 | 167 |
105 } // namespace net | 168 } // namespace net |
OLD | NEW |