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