Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Side by Side Diff: components/variations/variations_http_header_provider.cc

Issue 2569973002: Revert of Restrict transmission of external exp ids to signed in users. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "components/variations/variations_http_header_provider.h" 5 #include "components/variations/variations_http_header_provider.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <set> 9 #include <set>
10 #include <string> 10 #include <string>
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/base64.h" 13 #include "base/base64.h"
14 #include "base/memory/singleton.h" 14 #include "base/memory/singleton.h"
15 #include "base/metrics/histogram_macros.h" 15 #include "base/metrics/histogram_macros.h"
16 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_split.h" 17 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h" 18 #include "base/strings/string_util.h"
19 #include "base/threading/thread_task_runner_handle.h" 19 #include "base/threading/thread_task_runner_handle.h"
20 #include "components/variations/proto/client_variations.pb.h" 20 #include "components/variations/proto/client_variations.pb.h"
21 21
22 namespace variations { 22 namespace variations {
23 23
24 // static 24 // static
25 VariationsHttpHeaderProvider* VariationsHttpHeaderProvider::GetInstance() { 25 VariationsHttpHeaderProvider* VariationsHttpHeaderProvider::GetInstance() {
26 return base::Singleton<VariationsHttpHeaderProvider>::get(); 26 return base::Singleton<VariationsHttpHeaderProvider>::get();
27 } 27 }
28 28
29 std::string VariationsHttpHeaderProvider::GetClientDataHeader( 29 std::string VariationsHttpHeaderProvider::GetClientDataHeader() {
30 bool is_signed_in) {
31 // Lazily initialize the header, if not already done, before attempting to 30 // Lazily initialize the header, if not already done, before attempting to
32 // transmit it. 31 // transmit it.
33 InitVariationIDsCacheIfNeeded(); 32 InitVariationIDsCacheIfNeeded();
34 33
35 std::string variation_ids_header_copy; 34 std::string variation_ids_header_copy;
36 { 35 {
37 base::AutoLock scoped_lock(lock_); 36 base::AutoLock scoped_lock(lock_);
38 variation_ids_header_copy = is_signed_in 37 variation_ids_header_copy = variation_ids_header_;
39 ? cached_variation_ids_header_signed_in_
40 : cached_variation_ids_header_;
41 } 38 }
42 return variation_ids_header_copy; 39 return variation_ids_header_copy;
43 } 40 }
44 41
45 std::string VariationsHttpHeaderProvider::GetVariationsString() { 42 std::string VariationsHttpHeaderProvider::GetVariationsString() {
46 InitVariationIDsCacheIfNeeded(); 43 InitVariationIDsCacheIfNeeded();
47 44
48 // Construct a space-separated string with leading and trailing spaces from 45 // Construct a space-separated string with leading and trailing spaces from
49 // the variations set. Note: The ids in it will be in sorted order per the 46 // the variations set. Note: The ids in it will be in sorted order per the
50 // std::set contract. 47 // std::set contract.
51 std::string ids_string = " "; 48 std::string ids_string = " ";
52 { 49 {
53 base::AutoLock scoped_lock(lock_); 50 base::AutoLock scoped_lock(lock_);
54 for (const VariationIDEntry& entry : GetAllVariationIds()) { 51 for (VariationID id : GetAllVariationIds()) {
55 if (entry.second == GOOGLE_WEB_PROPERTIES) { 52 ids_string.append(base::IntToString(id));
56 ids_string.append(base::IntToString(entry.first)); 53 ids_string.push_back(' ');
57 ids_string.push_back(' ');
58 }
59 } 54 }
60 } 55 }
61 return ids_string; 56 return ids_string;
62 } 57 }
63 58
64 bool VariationsHttpHeaderProvider::ForceVariationIds( 59 bool VariationsHttpHeaderProvider::ForceVariationIds(
65 const std::string& command_line_variation_ids, 60 const std::string& command_line_variation_ids,
66 std::vector<std::string>* variation_ids) { 61 std::vector<std::string>* variation_ids) {
67 if (!command_line_variation_ids.empty()) { 62 if (!command_line_variation_ids.empty()) {
68 // Combine |variation_ids| with |command_line_variation_ids|. 63 // Combine |variation_ids| with |command_line_variation_ids|.
69 std::vector<std::string> variation_ids_flags = 64 std::vector<std::string> variation_ids_flags =
70 base::SplitString(command_line_variation_ids, ",", 65 base::SplitString(command_line_variation_ids, ",",
71 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 66 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
72 variation_ids->insert(variation_ids->end(), variation_ids_flags.begin(), 67 variation_ids->insert(variation_ids->end(), variation_ids_flags.begin(),
73 variation_ids_flags.end()); 68 variation_ids_flags.end());
74 } 69 }
75 70
76 if (!variation_ids->empty()) { 71 if (!variation_ids->empty()) {
77 // Create default variation ids which will always be included in the 72 // Create default variation ids which will always be included in the
78 // X-Client-Data request header. 73 // X-Client-Data request header.
79 return SetDefaultVariationIds(*variation_ids); 74 return SetDefaultVariationIds(*variation_ids);
80 } 75 }
81 return true; 76 return true;
82 } 77 }
83 78
79
84 bool VariationsHttpHeaderProvider::SetDefaultVariationIds( 80 bool VariationsHttpHeaderProvider::SetDefaultVariationIds(
85 const std::vector<std::string>& variation_ids) { 81 const std::vector<std::string>& variation_ids) {
86 default_variation_ids_set_.clear(); 82 default_variation_ids_set_.clear();
83 default_trigger_id_set_.clear();
87 for (const std::string& entry : variation_ids) { 84 for (const std::string& entry : variation_ids) {
88 if (entry.empty()) { 85 if (entry.empty()) {
89 default_variation_ids_set_.clear(); 86 default_variation_ids_set_.clear();
87 default_trigger_id_set_.clear();
90 return false; 88 return false;
91 } 89 }
92 bool trigger_id = 90 bool trigger_id =
93 base::StartsWith(entry, "t", base::CompareCase::SENSITIVE); 91 base::StartsWith(entry, "t", base::CompareCase::SENSITIVE);
94 // Remove the "t" prefix if it's there. 92 // Remove the "t" prefix if it's there.
95 std::string trimmed_entry = trigger_id ? entry.substr(1) : entry; 93 std::string trimmed_entry = trigger_id ? entry.substr(1) : entry;
96 94
97 int variation_id = 0; 95 int variation_id = 0;
98 if (!base::StringToInt(trimmed_entry, &variation_id)) { 96 if (!base::StringToInt(trimmed_entry, &variation_id)) {
99 default_variation_ids_set_.clear(); 97 default_variation_ids_set_.clear();
98 default_trigger_id_set_.clear();
100 return false; 99 return false;
101 } 100 }
102 default_variation_ids_set_.insert(VariationIDEntry( 101 if (trigger_id)
103 variation_id, 102 default_trigger_id_set_.insert(variation_id);
104 trigger_id ? GOOGLE_WEB_PROPERTIES_TRIGGER : GOOGLE_WEB_PROPERTIES)); 103 else
104 default_variation_ids_set_.insert(variation_id);
105 } 105 }
106 return true; 106 return true;
107 } 107 }
108 108
109 void VariationsHttpHeaderProvider::ResetForTesting() { 109 void VariationsHttpHeaderProvider::ResetForTesting() {
110 base::AutoLock scoped_lock(lock_); 110 base::AutoLock scoped_lock(lock_);
111 111
112 // Stop observing field trials so that it can be restarted when this is 112 // Stop observing field trials so that it can be restarted when this is
113 // re-inited. Note: This is a no-op if this is not currently observing. 113 // re-inited. Note: This is a no-op if this is not currently observing.
114 base::FieldTrialList::RemoveObserver(this); 114 base::FieldTrialList::RemoveObserver(this);
115 variation_ids_cache_initialized_ = false; 115 variation_ids_cache_initialized_ = false;
116 } 116 }
117 117
118 VariationsHttpHeaderProvider::VariationsHttpHeaderProvider() 118 VariationsHttpHeaderProvider::VariationsHttpHeaderProvider()
119 : variation_ids_cache_initialized_(false) {} 119 : variation_ids_cache_initialized_(false) {}
120 120
121 VariationsHttpHeaderProvider::~VariationsHttpHeaderProvider() {} 121 VariationsHttpHeaderProvider::~VariationsHttpHeaderProvider() {}
122 122
123 void VariationsHttpHeaderProvider::OnFieldTrialGroupFinalized( 123 void VariationsHttpHeaderProvider::OnFieldTrialGroupFinalized(
124 const std::string& trial_name, 124 const std::string& trial_name,
125 const std::string& group_name) { 125 const std::string& group_name) {
126 VariationID new_id =
127 GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, trial_name, group_name);
128 VariationID new_trigger_id = GetGoogleVariationID(
129 GOOGLE_WEB_PROPERTIES_TRIGGER, trial_name, group_name);
130 if (new_id == EMPTY_ID && new_trigger_id == EMPTY_ID)
131 return;
132
126 base::AutoLock scoped_lock(lock_); 133 base::AutoLock scoped_lock(lock_);
127 const size_t old_size = variation_ids_set_.size(); 134 if (new_id != EMPTY_ID)
128 CacheVariationsId(trial_name, group_name, GOOGLE_WEB_PROPERTIES); 135 variation_ids_set_.insert(new_id);
129 CacheVariationsId(trial_name, group_name, GOOGLE_WEB_PROPERTIES_SIGNED_IN); 136 if (new_trigger_id != EMPTY_ID)
130 CacheVariationsId(trial_name, group_name, GOOGLE_WEB_PROPERTIES_TRIGGER); 137 variation_trigger_ids_set_.insert(new_trigger_id);
131 if (variation_ids_set_.size() != old_size) 138
132 UpdateVariationIDsHeaderValue(); 139 UpdateVariationIDsHeaderValue();
133 } 140 }
134 141
135 void VariationsHttpHeaderProvider::OnSyntheticTrialsChanged( 142 void VariationsHttpHeaderProvider::OnSyntheticTrialsChanged(
136 const std::vector<SyntheticTrialGroup>& groups) { 143 const std::vector<SyntheticTrialGroup>& groups) {
137 base::AutoLock scoped_lock(lock_); 144 base::AutoLock scoped_lock(lock_);
138 145
139 synthetic_variation_ids_set_.clear(); 146 synthetic_variation_ids_set_.clear();
140 for (const SyntheticTrialGroup& group : groups) { 147 for (const SyntheticTrialGroup& group : groups) {
141 VariationID id = 148 const VariationID id =
142 GetGoogleVariationIDFromHashes(GOOGLE_WEB_PROPERTIES, group.id); 149 GetGoogleVariationIDFromHashes(GOOGLE_WEB_PROPERTIES, group.id);
143 if (id != EMPTY_ID) { 150 if (id != EMPTY_ID)
144 synthetic_variation_ids_set_.insert( 151 synthetic_variation_ids_set_.insert(id);
145 VariationIDEntry(id, GOOGLE_WEB_PROPERTIES));
146 }
147 id = GetGoogleVariationIDFromHashes(GOOGLE_WEB_PROPERTIES_SIGNED_IN,
148 group.id);
149 if (id != EMPTY_ID) {
150 synthetic_variation_ids_set_.insert(
151 VariationIDEntry(id, GOOGLE_WEB_PROPERTIES_SIGNED_IN));
152 }
153 } 152 }
154 UpdateVariationIDsHeaderValue(); 153 UpdateVariationIDsHeaderValue();
155 } 154 }
156 155
157 void VariationsHttpHeaderProvider::InitVariationIDsCacheIfNeeded() { 156 void VariationsHttpHeaderProvider::InitVariationIDsCacheIfNeeded() {
158 base::AutoLock scoped_lock(lock_); 157 base::AutoLock scoped_lock(lock_);
159 if (variation_ids_cache_initialized_) 158 if (variation_ids_cache_initialized_)
160 return; 159 return;
161 160
162 // Register for additional cache updates. This is done first to avoid a race 161 // Register for additional cache updates. This is done first to avoid a race
163 // that could cause registered FieldTrials to be missed. 162 // that could cause registered FieldTrials to be missed.
164 DCHECK(base::ThreadTaskRunnerHandle::IsSet()); 163 DCHECK(base::ThreadTaskRunnerHandle::IsSet());
165 base::FieldTrialList::AddObserver(this); 164 base::FieldTrialList::AddObserver(this);
166 165
167 base::TimeTicks before_time = base::TimeTicks::Now(); 166 base::TimeTicks before_time = base::TimeTicks::Now();
168 167
169 base::FieldTrial::ActiveGroups initial_groups; 168 base::FieldTrial::ActiveGroups initial_groups;
170 base::FieldTrialList::GetActiveFieldTrialGroups(&initial_groups); 169 base::FieldTrialList::GetActiveFieldTrialGroups(&initial_groups);
171 170
172 for (const auto& entry : initial_groups) { 171 for (const auto& entry : initial_groups) {
173 CacheVariationsId(entry.trial_name, entry.group_name, 172 const VariationID id =
174 GOOGLE_WEB_PROPERTIES); 173 GetGoogleVariationID(GOOGLE_WEB_PROPERTIES, entry.trial_name,
175 CacheVariationsId(entry.trial_name, entry.group_name, 174 entry.group_name);
176 GOOGLE_WEB_PROPERTIES_SIGNED_IN); 175 if (id != EMPTY_ID)
177 CacheVariationsId(entry.trial_name, entry.group_name, 176 variation_ids_set_.insert(id);
178 GOOGLE_WEB_PROPERTIES_TRIGGER); 177
178 const VariationID trigger_id =
179 GetGoogleVariationID(GOOGLE_WEB_PROPERTIES_TRIGGER, entry.trial_name,
180 entry.group_name);
181
182 if (trigger_id != EMPTY_ID)
183 variation_trigger_ids_set_.insert(trigger_id);
179 } 184 }
180 UpdateVariationIDsHeaderValue(); 185 UpdateVariationIDsHeaderValue();
181 186
182 UMA_HISTOGRAM_CUSTOM_COUNTS( 187 UMA_HISTOGRAM_CUSTOM_COUNTS(
183 "Variations.HeaderConstructionTime", 188 "Variations.HeaderConstructionTime",
184 (base::TimeTicks::Now() - before_time).InMicroseconds(), 1, 189 (base::TimeTicks::Now() - before_time).InMicroseconds(), 1,
185 base::TimeDelta::FromSeconds(1).InMicroseconds(), 50); 190 base::TimeDelta::FromSeconds(1).InMicroseconds(), 50);
186 191
187 variation_ids_cache_initialized_ = true; 192 variation_ids_cache_initialized_ = true;
188 } 193 }
189 194
190 void VariationsHttpHeaderProvider::CacheVariationsId(
191 const std::string& trial_name,
192 const std::string& group_name,
193 IDCollectionKey key) {
194 const VariationID id = GetGoogleVariationID(key, trial_name, group_name);
195 if (id != EMPTY_ID)
196 variation_ids_set_.insert(VariationIDEntry(id, key));
197 }
198
199 void VariationsHttpHeaderProvider::UpdateVariationIDsHeaderValue() { 195 void VariationsHttpHeaderProvider::UpdateVariationIDsHeaderValue() {
200 lock_.AssertAcquired(); 196 lock_.AssertAcquired();
201 197
202 // The header value is a serialized protobuffer of Variation IDs which is 198 // The header value is a serialized protobuffer of Variation IDs which is
203 // base64 encoded before transmitting as a string. 199 // base64 encoded before transmitting as a string.
204 cached_variation_ids_header_.clear(); 200 variation_ids_header_.clear();
205 cached_variation_ids_header_signed_in_.clear();
206 201
207 // If successful, swap the header value with the new one. 202 if (variation_ids_set_.empty() && default_variation_ids_set_.empty() &&
208 // Note that the list of IDs and the header could be temporarily out of sync 203 variation_trigger_ids_set_.empty() && default_trigger_id_set_.empty() &&
209 // if IDs are added as the header is recreated. The receiving servers are OK 204 synthetic_variation_ids_set_.empty()) {
210 // with such discrepancies. 205 return;
211 cached_variation_ids_header_ = GenerateBase64EncodedProto(false);
212 cached_variation_ids_header_signed_in_ = GenerateBase64EncodedProto(true);
213 }
214
215 std::string VariationsHttpHeaderProvider::GenerateBase64EncodedProto(
216 bool is_signed_in) {
217 std::set<VariationIDEntry> all_variation_ids_set = GetAllVariationIds();
218
219 ClientVariations proto;
220 for (const VariationIDEntry& entry : all_variation_ids_set) {
221 switch (entry.second) {
222 case GOOGLE_WEB_PROPERTIES_SIGNED_IN:
223 if (is_signed_in)
224 proto.add_variation_id(entry.first);
225 break;
226 case GOOGLE_WEB_PROPERTIES:
227 proto.add_variation_id(entry.first);
228 break;
229 case GOOGLE_WEB_PROPERTIES_TRIGGER:
230 proto.add_trigger_variation_id(entry.first);
231 break;
232 case CHROME_SYNC_SERVICE:
233 case ID_COLLECTION_COUNT:
234 // These cases included to get full enum coverage for switch, so that
235 // new enums introduce compiler warnings. Nothing to do for these.
236 break;
237 }
238 } 206 }
239 207
240 const size_t total_id_count =
241 proto.variation_id_size() + proto.trigger_variation_id_size();
242
243 if (total_id_count == 0)
244 return std::string();
245
246 // This is the bottleneck for the creation of the header, so validate the size 208 // This is the bottleneck for the creation of the header, so validate the size
247 // here. Force a hard maximum on the ID count in case the Variations server 209 // here. Force a hard maximum on the ID count in case the Variations server
248 // returns too many IDs and DOSs receiving servers with large requests. 210 // returns too many IDs and DOSs receiving servers with large requests.
211 const size_t total_id_count =
212 variation_ids_set_.size() + variation_trigger_ids_set_.size();
249 DCHECK_LE(total_id_count, 10U); 213 DCHECK_LE(total_id_count, 10U);
250 UMA_HISTOGRAM_COUNTS_100("Variations.Headers.ExperimentCount", 214 UMA_HISTOGRAM_COUNTS_100("Variations.Headers.ExperimentCount",
251 total_id_count); 215 total_id_count);
252 if (total_id_count > 20) 216 if (total_id_count > 20)
253 return std::string(); 217 return;
218
219 std::set<VariationID> all_variation_ids_set = GetAllVariationIds();
220 std::set<VariationID> all_trigger_ids_set = default_trigger_id_set_;
221 for (VariationID id : variation_trigger_ids_set_)
222 all_trigger_ids_set.insert(id);
223
224 ClientVariations proto;
225 for (VariationID id : all_variation_ids_set)
226 proto.add_variation_id(id);
227 for (VariationID id : all_trigger_ids_set)
228 proto.add_trigger_variation_id(id);
254 229
255 std::string serialized; 230 std::string serialized;
256 proto.SerializeToString(&serialized); 231 proto.SerializeToString(&serialized);
257 232
258 std::string hashed; 233 std::string hashed;
259 base::Base64Encode(serialized, &hashed); 234 base::Base64Encode(serialized, &hashed);
260 return hashed; 235 // If successful, swap the header value with the new one.
236 // Note that the list of IDs and the header could be temporarily out of sync
237 // if IDs are added as the header is recreated. The receiving servers are OK
238 // with such discrepancies.
239 variation_ids_header_ = hashed;
261 } 240 }
262 241
263 std::set<VariationsHttpHeaderProvider::VariationIDEntry> 242 std::set<VariationID> VariationsHttpHeaderProvider::GetAllVariationIds() {
264 VariationsHttpHeaderProvider::GetAllVariationIds() {
265 lock_.AssertAcquired(); 243 lock_.AssertAcquired();
266 244
267 std::set<VariationIDEntry> all_variation_ids_set = default_variation_ids_set_; 245 std::set<VariationID> all_variation_ids_set = default_variation_ids_set_;
268 for (const VariationIDEntry& entry : variation_ids_set_) { 246 for (VariationID id : variation_ids_set_)
269 all_variation_ids_set.insert(entry); 247 all_variation_ids_set.insert(id);
270 } 248 for (VariationID id : synthetic_variation_ids_set_)
271 for (const VariationIDEntry& entry : synthetic_variation_ids_set_) { 249 all_variation_ids_set.insert(id);
272 all_variation_ids_set.insert(entry);
273 }
274 return all_variation_ids_set; 250 return all_variation_ids_set;
275 } 251 }
276 252
277 } // namespace variations 253 } // namespace variations
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698