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

Side by Side Diff: chrome/browser/webdata/autocomplete_syncable_service.cc

Issue 9585020: Cull autofill entries older than 60 days. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comment Created 8 years, 9 months 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/webdata/autocomplete_syncable_service.h" 5 #include "chrome/browser/webdata/autocomplete_syncable_service.h"
6 6
7 #include "base/location.h" 7 #include "base/location.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/utf_string_conversions.h" 9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/profiles/profile.h"
(...skipping 11 matching lines...) Expand all
22 22
23 using content::BrowserThread; 23 using content::BrowserThread;
24 24
25 namespace { 25 namespace {
26 26
27 const char kAutofillEntryNamespaceTag[] = "autofill_entry|"; 27 const char kAutofillEntryNamespaceTag[] = "autofill_entry|";
28 28
29 // Merges timestamps from the |autofill| entry and |timestamps|. Returns 29 // Merges timestamps from the |autofill| entry and |timestamps|. Returns
30 // true if they were different, false if they were the same. 30 // true if they were different, false if they were the same.
31 // All of the timestamp vectors are assummed to be sorted, resulting vector is 31 // All of the timestamp vectors are assummed to be sorted, resulting vector is
32 // sorted as well. 32 // sorted as well. Only two timestamps - the earliest and the latest are stored.
33 bool MergeTimestamps(const sync_pb::AutofillSpecifics& autofill, 33 bool MergeTimestamps(const sync_pb::AutofillSpecifics& autofill,
34 const std::vector<base::Time>& timestamps, 34 const std::vector<base::Time>& timestamps,
35 std::vector<base::Time>* new_timestamps) { 35 std::vector<base::Time>* new_timestamps) {
36 DCHECK(new_timestamps); 36 DCHECK(new_timestamps);
37 std::set<base::Time> timestamp_union(timestamps.begin(),
38 timestamps.end());
39 37
38 new_timestamps->clear();
40 size_t timestamps_count = autofill.usage_timestamp_size(); 39 size_t timestamps_count = autofill.usage_timestamp_size();
41 40 if (timestamps_count == 0 && timestamps.empty()) {
42 bool different = timestamps.size() != timestamps_count; 41 return false;
43 for (size_t i = 0; i < timestamps_count; ++i) { 42 } else if (timestamps_count == 0) {
44 if (timestamp_union.insert(base::Time::FromInternalValue( 43 new_timestamps->insert(new_timestamps->begin(),
45 autofill.usage_timestamp(i))).second) { 44 timestamps.begin(),
46 different = true; 45 timestamps.end());
46 return true;
47 } else if (timestamps.empty()) {
48 new_timestamps->reserve(2);
49 new_timestamps->push_back(base::Time::FromInternalValue(
50 autofill.usage_timestamp(0)));
51 if (timestamps_count > 1) {
52 new_timestamps->push_back(base::Time::FromInternalValue(
53 autofill.usage_timestamp(timestamps_count - 1)));
54 }
55 return true;
56 } else {
57 base::Time sync_time_begin = base::Time::FromInternalValue(
58 autofill.usage_timestamp(0));
59 base::Time sync_time_end = base::Time::FromInternalValue(
60 autofill.usage_timestamp(timestamps_count - 1));
61 if (timestamps.front() != sync_time_begin ||
62 timestamps.back() != sync_time_end) {
63 new_timestamps->push_back(
64 timestamps.front() < sync_time_begin ? timestamps.front() :
65 sync_time_begin);
66 if (new_timestamps->back() != timestamps.back() ||
67 new_timestamps->back() != sync_time_end) {
68 new_timestamps->push_back(
69 timestamps.back() > sync_time_end ? timestamps.back() :
70 sync_time_end);
71 }
72 return true;
73 } else {
74 new_timestamps->insert(new_timestamps->begin(),
75 timestamps.begin(),
76 timestamps.end());
77 return false;
47 } 78 }
48 } 79 }
49
50 if (different) {
51 new_timestamps->insert(new_timestamps->begin(),
52 timestamp_union.begin(),
53 timestamp_union.end());
54 }
55 return different;
56 } 80 }
57 81
58 } // namespace 82 } // namespace
59 83
60 AutocompleteSyncableService::AutocompleteSyncableService( 84 AutocompleteSyncableService::AutocompleteSyncableService(
61 WebDataService* web_data_service) 85 WebDataService* web_data_service)
62 : web_data_service_(web_data_service) { 86 : web_data_service_(web_data_service) {
63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
64 DCHECK(web_data_service_); 88 DCHECK(web_data_service_);
65 notification_registrar_.Add( 89 notification_registrar_.Add(
(...skipping 28 matching lines...) Expand all
94 118
95 AutocompleteEntryMap new_db_entries; 119 AutocompleteEntryMap new_db_entries;
96 for (std::vector<AutofillEntry>::iterator it = entries.begin(); 120 for (std::vector<AutofillEntry>::iterator it = entries.begin();
97 it != entries.end(); ++it) { 121 it != entries.end(); ++it) {
98 new_db_entries[it->key()] = std::make_pair(SyncChange::ACTION_ADD, it); 122 new_db_entries[it->key()] = std::make_pair(SyncChange::ACTION_ADD, it);
99 } 123 }
100 124
101 sync_processor_ = sync_processor.Pass(); 125 sync_processor_ = sync_processor.Pass();
102 126
103 std::vector<AutofillEntry> new_synced_entries; 127 std::vector<AutofillEntry> new_synced_entries;
128 std::vector<AutofillEntry> synced_expired_entries;
104 // Go through and check for all the entries that sync already knows about. 129 // Go through and check for all the entries that sync already knows about.
105 // CreateOrUpdateEntry() will remove entries that are same with the synced 130 // CreateOrUpdateEntry() will remove entries that are same with the synced
106 // ones from |new_db_entries|. 131 // ones from |new_db_entries|.
107 for (SyncDataList::const_iterator sync_iter = initial_sync_data.begin(); 132 for (SyncDataList::const_iterator sync_iter = initial_sync_data.begin();
108 sync_iter != initial_sync_data.end(); ++sync_iter) { 133 sync_iter != initial_sync_data.end(); ++sync_iter) {
109 CreateOrUpdateEntry(*sync_iter, &new_db_entries, &new_synced_entries); 134 CreateOrUpdateEntry(*sync_iter, &new_db_entries,
135 &new_synced_entries, &synced_expired_entries);
110 } 136 }
111 137
138 // Check if newly received items need culling.
139 bool need_to_cull_data = !synced_expired_entries.empty();
140
112 if (!SaveChangesToWebData(new_synced_entries)) 141 if (!SaveChangesToWebData(new_synced_entries))
113 return SyncError(FROM_HERE, "Failed to update webdata.", model_type()); 142 return SyncError(FROM_HERE, "Failed to update webdata.", model_type());
114 143
115 WebDataService::NotifyOfMultipleAutofillChanges(web_data_service_); 144 WebDataService::NotifyOfMultipleAutofillChanges(web_data_service_);
145 keys_to_ignore_.clear();
116 146
117 SyncChangeList new_changes; 147 SyncChangeList new_changes;
118 for (AutocompleteEntryMap::iterator i = new_db_entries.begin(); 148 for (AutocompleteEntryMap::iterator i = new_db_entries.begin();
119 i != new_db_entries.end(); ++i) { 149 i != new_db_entries.end(); ++i) {
120 new_changes.push_back( 150 // Sync back only the data that appeared after
121 SyncChange(i->second.first, CreateSyncData(*(i->second.second)))); 151 // |AutofillEntry::ExpirationTime()|.
152 if (!i->second.second->IsExpired()) {
153 new_changes.push_back(
154 SyncChange(i->second.first, CreateSyncData(*(i->second.second))));
155 } else {
156 need_to_cull_data = true;
157 // Key is not on the server and is too old, it will not ever be synced -
158 // delete it locally.
159 if (i->second.first == SyncChange::ACTION_ADD)
160 keys_to_ignore_.insert(i->first);
161 }
162 }
163
164 // Delete only the changes never synced to the db as they are too old.
165 for (size_t i = 0; i < synced_expired_entries.size(); ++i) {
166 // Key is on the server and not local and is too old, we need to notify
167 // sync that it has expired.
168 if (keys_to_ignore_.find(synced_expired_entries[i].key()) ==
169 keys_to_ignore_.end()) {
170 new_changes.push_back(SyncChange(SyncChange::ACTION_DELETE,
171 CreateSyncData(synced_expired_entries[i])));
172 }
173 }
174
175 if (need_to_cull_data) {
176 // This will schedule deletion operation later on DB thread and we will
177 // be notified on the results of the deletion and deletes will be synced to
178 // the sync.
179 web_data_service_->RemoveExpiredFormElements();
122 } 180 }
123 181
124 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes); 182 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
125 183
126 return error; 184 return error;
127 } 185 }
128 186
129 void AutocompleteSyncableService::StopSyncing(syncable::ModelType type) { 187 void AutocompleteSyncableService::StopSyncing(syncable::ModelType type) {
130 DCHECK(CalledOnValidThread()); 188 DCHECK(CalledOnValidThread());
131 DCHECK_EQ(syncable::AUTOFILL, type); 189 DCHECK_EQ(syncable::AUTOFILL, type);
(...skipping 30 matching lines...) Expand all
162 if (!sync_processor_.get()) { 220 if (!sync_processor_.get()) {
163 SyncError error(FROM_HERE, "Models not yet associated.", 221 SyncError error(FROM_HERE, "Models not yet associated.",
164 syncable::AUTOFILL); 222 syncable::AUTOFILL);
165 return error; 223 return error;
166 } 224 }
167 225
168 // Data is loaded only if we get new ADD/UPDATE change. 226 // Data is loaded only if we get new ADD/UPDATE change.
169 std::vector<AutofillEntry> entries; 227 std::vector<AutofillEntry> entries;
170 scoped_ptr<AutocompleteEntryMap> db_entries; 228 scoped_ptr<AutocompleteEntryMap> db_entries;
171 std::vector<AutofillEntry> new_entries; 229 std::vector<AutofillEntry> new_entries;
230 std::vector<AutofillEntry> ignored_entries;
172 231
173 SyncError list_processing_error; 232 SyncError list_processing_error;
174 233
175 for (SyncChangeList::const_iterator i = change_list.begin(); 234 for (SyncChangeList::const_iterator i = change_list.begin();
176 i != change_list.end() && !list_processing_error.IsSet(); ++i) { 235 i != change_list.end() && !list_processing_error.IsSet(); ++i) {
177 DCHECK(i->IsValid()); 236 DCHECK(i->IsValid());
178 switch (i->change_type()) { 237 switch (i->change_type()) {
179 case SyncChange::ACTION_ADD: 238 case SyncChange::ACTION_ADD:
180 case SyncChange::ACTION_UPDATE: 239 case SyncChange::ACTION_UPDATE:
181 if (!db_entries.get()) { 240 if (!db_entries.get()) {
182 if (!LoadAutofillData(&entries)) { 241 if (!LoadAutofillData(&entries)) {
183 return SyncError( 242 return SyncError(
184 FROM_HERE, 243 FROM_HERE,
185 "Could not get the autocomplete data from WebDatabase.", 244 "Could not get the autocomplete data from WebDatabase.",
186 model_type()); 245 model_type());
187 } 246 }
188 db_entries.reset(new AutocompleteEntryMap); 247 db_entries.reset(new AutocompleteEntryMap);
189 for (std::vector<AutofillEntry>::iterator it = entries.begin(); 248 for (std::vector<AutofillEntry>::iterator it = entries.begin();
190 it != entries.end(); ++it) { 249 it != entries.end(); ++it) {
191 (*db_entries)[it->key()] = 250 (*db_entries)[it->key()] =
192 std::make_pair(SyncChange::ACTION_ADD, it); 251 std::make_pair(SyncChange::ACTION_ADD, it);
193 } 252 }
194 } 253 }
195 CreateOrUpdateEntry(i->sync_data(), db_entries.get(), &new_entries); 254 CreateOrUpdateEntry(i->sync_data(), db_entries.get(),
255 &new_entries, &ignored_entries);
196 break; 256 break;
197 case SyncChange::ACTION_DELETE: { 257 case SyncChange::ACTION_DELETE: {
198 DCHECK(i->sync_data().GetSpecifics().has_autofill()) 258 DCHECK(i->sync_data().GetSpecifics().has_autofill())
199 << "Autofill specifics data not present on delete!"; 259 << "Autofill specifics data not present on delete!";
200 const sync_pb::AutofillSpecifics& autofill = 260 const sync_pb::AutofillSpecifics& autofill =
201 i->sync_data().GetSpecifics().autofill(); 261 i->sync_data().GetSpecifics().autofill();
202 if (autofill.has_value()) { 262 if (autofill.has_value()) {
203 list_processing_error = AutofillEntryDelete(autofill); 263 list_processing_error = AutofillEntryDelete(autofill);
204 } else { 264 } else {
205 DLOG(WARNING) 265 DLOG(WARNING)
206 << "Delete for old-style autofill profile being dropped!"; 266 << "Delete for old-style autofill profile being dropped!";
207 } 267 }
208 } break; 268 } break;
209 default: 269 default:
210 NOTREACHED() << "Unexpected sync change state."; 270 NOTREACHED() << "Unexpected sync change state.";
211 return SyncError(FROM_HERE, "ProcessSyncChanges failed on ChangeType " + 271 return SyncError(FROM_HERE, "ProcessSyncChanges failed on ChangeType " +
212 SyncChange::ChangeTypeToString(i->change_type()), 272 SyncChange::ChangeTypeToString(i->change_type()),
213 syncable::AUTOFILL); 273 syncable::AUTOFILL);
214 } 274 }
215 } 275 }
216 276
217 if (!SaveChangesToWebData(new_entries)) 277 if (!SaveChangesToWebData(new_entries))
218 return SyncError(FROM_HERE, "Failed to update webdata.", model_type()); 278 return SyncError(FROM_HERE, "Failed to update webdata.", model_type());
219 279
280 // Remove already expired data.
281 for (size_t i = 0; i < ignored_entries.size(); ++i) {
282 if (db_entries.get() &&
283 db_entries->find(ignored_entries[i].key()) != db_entries->end()) {
284 bool success = web_data_service_->GetDatabase()->GetAutofillTable()->
285 RemoveFormElement(ignored_entries[i].key().name(),
286 ignored_entries[i].key().value());
287 DCHECK(success);
288 }
289 }
290
220 WebDataService::NotifyOfMultipleAutofillChanges(web_data_service_); 291 WebDataService::NotifyOfMultipleAutofillChanges(web_data_service_);
221 292
222 return list_processing_error; 293 return list_processing_error;
223 } 294 }
224 295
225 void AutocompleteSyncableService::Observe(int type, 296 void AutocompleteSyncableService::Observe(int type,
226 const content::NotificationSource& source, 297 const content::NotificationSource& source,
227 const content::NotificationDetails& details) { 298 const content::NotificationDetails& details) {
228 DCHECK_EQ(chrome::NOTIFICATION_AUTOFILL_ENTRIES_CHANGED, type); 299 DCHECK_EQ(chrome::NOTIFICATION_AUTOFILL_ENTRIES_CHANGED, type);
229 300
(...skipping 27 matching lines...) Expand all
257 GetAutofillTable()->UpdateAutofillEntries(new_entries)) { 328 GetAutofillTable()->UpdateAutofillEntries(new_entries)) {
258 return false; 329 return false;
259 } 330 }
260 return true; 331 return true;
261 } 332 }
262 333
263 // Creates or updates an autocomplete entry based on |data|. 334 // Creates or updates an autocomplete entry based on |data|.
264 void AutocompleteSyncableService::CreateOrUpdateEntry( 335 void AutocompleteSyncableService::CreateOrUpdateEntry(
265 const SyncData& data, 336 const SyncData& data,
266 AutocompleteEntryMap* loaded_data, 337 AutocompleteEntryMap* loaded_data,
267 std::vector<AutofillEntry>* new_entries) { 338 std::vector<AutofillEntry>* new_entries,
339 std::vector<AutofillEntry>* ignored_entries) {
268 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics(); 340 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
269 const sync_pb::AutofillSpecifics& autofill_specifics( 341 const sync_pb::AutofillSpecifics& autofill_specifics(
270 specifics.autofill()); 342 specifics.autofill());
271 343
272 if (!autofill_specifics.has_value()) { 344 if (!autofill_specifics.has_value()) {
273 DLOG(WARNING) 345 DLOG(WARNING)
274 << "Add/Update for old-style autofill profile being dropped!"; 346 << "Add/Update for old-style autofill profile being dropped!";
275 return; 347 return;
276 } 348 }
277 349
278 AutofillKey key(autofill_specifics.name().c_str(), 350 AutofillKey key(autofill_specifics.name().c_str(),
279 autofill_specifics.value().c_str()); 351 autofill_specifics.value().c_str());
280 AutocompleteEntryMap::iterator it = loaded_data->find(key); 352 AutocompleteEntryMap::iterator it = loaded_data->find(key);
281 if (it == loaded_data->end()) { 353 if (it == loaded_data->end()) {
282 // New entry. 354 // New entry.
283 std::vector<base::Time> timestamps; 355 std::vector<base::Time> timestamps;
284 size_t timestamps_count = autofill_specifics.usage_timestamp_size(); 356 size_t timestamps_count = autofill_specifics.usage_timestamp_size();
285 timestamps.resize(timestamps_count); 357 timestamps.reserve(2);
286 for (size_t ts = 0; ts < timestamps_count; ++ts) { 358 if (timestamps_count) {
287 timestamps[ts] = base::Time::FromInternalValue( 359 timestamps.push_back(base::Time::FromInternalValue(
288 autofill_specifics.usage_timestamp(ts)); 360 autofill_specifics.usage_timestamp(0)));
289 } 361 }
290 new_entries->push_back(AutofillEntry(key, timestamps)); 362 if (timestamps_count > 1) {
363 timestamps.push_back(base::Time::FromInternalValue(
364 autofill_specifics.usage_timestamp(timestamps_count - 1)));
365 }
366 AutofillEntry new_entry(key, timestamps);
367 if (new_entry.IsExpired())
368 ignored_entries->push_back(new_entry);
369 else
370 new_entries->push_back(new_entry);
291 } else { 371 } else {
292 // Entry already present - merge if necessary. 372 // Entry already present - merge if necessary.
293 std::vector<base::Time> timestamps; 373 std::vector<base::Time> timestamps;
294 bool different = MergeTimestamps( 374 bool different = MergeTimestamps(
295 autofill_specifics, it->second.second->timestamps(), &timestamps); 375 autofill_specifics, it->second.second->timestamps(), &timestamps);
296 if (different) { 376 if (different) {
297 AutofillEntry new_entry(it->second.second->key(), timestamps); 377 AutofillEntry new_entry(it->second.second->key(), timestamps);
298 new_entries->push_back(new_entry); 378 if (new_entry.IsExpired()) {
299 379 ignored_entries->push_back(new_entry);
300 // Update the sync db if the list of timestamps have changed. 380 } else {
301 *(it->second.second) = new_entry; 381 new_entries->push_back(new_entry);
302 it->second.first = SyncChange::ACTION_UPDATE; 382 // Update the sync db if the list of timestamps have changed.
383 *(it->second.second) = new_entry;
384 it->second.first = SyncChange::ACTION_UPDATE;
385 }
303 } else { 386 } else {
304 loaded_data->erase(it); 387 loaded_data->erase(it);
305 } 388 }
306 } 389 }
307 } 390 }
308 391
309 // static 392 // static
310 void AutocompleteSyncableService::WriteAutofillEntry( 393 void AutocompleteSyncableService::WriteAutofillEntry(
311 const AutofillEntry& entry, sync_pb::EntitySpecifics* autofill_specifics) { 394 const AutofillEntry& entry, sync_pb::EntitySpecifics* autofill_specifics) {
312 sync_pb::AutofillSpecifics* autofill = 395 sync_pb::AutofillSpecifics* autofill =
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 } 434 }
352 AutofillEntry entry(change->key(), timestamps); 435 AutofillEntry entry(change->key(), timestamps);
353 SyncChange::SyncChangeType change_type = 436 SyncChange::SyncChangeType change_type =
354 (change->type() == AutofillChange::ADD) ? 437 (change->type() == AutofillChange::ADD) ?
355 SyncChange::ACTION_ADD : SyncChange::ACTION_UPDATE; 438 SyncChange::ACTION_ADD : SyncChange::ACTION_UPDATE;
356 new_changes.push_back(SyncChange(change_type, 439 new_changes.push_back(SyncChange(change_type,
357 CreateSyncData(entry))); 440 CreateSyncData(entry)));
358 break; 441 break;
359 } 442 }
360 case AutofillChange::REMOVE: { 443 case AutofillChange::REMOVE: {
361 std::vector<base::Time> timestamps; 444 if (keys_to_ignore_.find(change->key()) == keys_to_ignore_.end()) {
362 AutofillEntry entry(change->key(), timestamps); 445 std::vector<base::Time> timestamps;
363 new_changes.push_back(SyncChange(SyncChange::ACTION_DELETE, 446 AutofillEntry entry(change->key(), timestamps);
364 CreateSyncData(entry))); 447 new_changes.push_back(SyncChange(SyncChange::ACTION_DELETE,
448 CreateSyncData(entry)));
449 }
365 break; 450 break;
366 } 451 }
367 default: 452 default:
368 NOTREACHED(); 453 NOTREACHED();
369 break; 454 break;
370 } 455 }
371 } 456 }
372 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes); 457 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
373 if (error.IsSet()) { 458 if (error.IsSet()) {
374 DLOG(WARNING) << "[AUTOCOMPLETE SYNC]" 459 DLOG(WARNING) << "[AUTOCOMPLETE SYNC]"
375 << " Failed processing change:" 460 << " Failed processing change:"
376 << " Error:" << error.message(); 461 << " Error:" << error.message();
377 } 462 }
463 // |keys_to_ignore_| are only needed for the very first notification.
464 keys_to_ignore_.clear();
378 } 465 }
379 466
380 SyncData AutocompleteSyncableService::CreateSyncData( 467 SyncData AutocompleteSyncableService::CreateSyncData(
381 const AutofillEntry& entry) const { 468 const AutofillEntry& entry) const {
382 sync_pb::EntitySpecifics autofill_specifics; 469 sync_pb::EntitySpecifics autofill_specifics;
383 WriteAutofillEntry(entry, &autofill_specifics); 470 WriteAutofillEntry(entry, &autofill_specifics);
384 std::string tag(KeyToTag(UTF16ToUTF8(entry.key().name()), 471 std::string tag(KeyToTag(UTF16ToUTF8(entry.key().name()),
385 UTF16ToUTF8(entry.key().value()))); 472 UTF16ToUTF8(entry.key().value())));
386 return SyncData::CreateLocalData(tag, tag, autofill_specifics); 473 return SyncData::CreateLocalData(tag, tag, autofill_specifics);
387 } 474 }
388 475
389 // static 476 // static
390 std::string AutocompleteSyncableService::KeyToTag(const std::string& name, 477 std::string AutocompleteSyncableService::KeyToTag(const std::string& name,
391 const std::string& value) { 478 const std::string& value) {
392 std::string ns(kAutofillEntryNamespaceTag); 479 std::string ns(kAutofillEntryNamespaceTag);
393 return ns + net::EscapePath(name) + "|" + net::EscapePath(value); 480 return ns + net::EscapePath(name) + "|" + net::EscapePath(value);
394 } 481 }
OLDNEW
« no previous file with comments | « chrome/browser/webdata/autocomplete_syncable_service.h ('k') | chrome/browser/webdata/autofill_entry.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698