Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / webdata / autocomplete_syncable_service.cc
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/webdata/autocomplete_syncable_service.h"
6
7 #include "base/location.h"
8 #include "base/logging.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "components/autofill/core/browser/webdata/autofill_table.h"
11 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
12 #include "components/webdata/common/web_database.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "net/base/escape.h"
15 #include "sync/api/sync_error.h"
16 #include "sync/api/sync_error_factory.h"
17 #include "sync/protocol/autofill_specifics.pb.h"
18 #include "sync/protocol/sync.pb.h"
19
20 using autofill::AutofillChange;
21 using autofill::AutofillChangeList;
22 using autofill::AutofillEntry;
23 using autofill::AutofillKey;
24 using autofill::AutofillTable;
25 using autofill::AutofillWebDataService;
26 using autofill::AutofillWebDataBackend;
27 using content::BrowserThread;
28
29 namespace {
30
31 const char kAutofillEntryNamespaceTag[] = "autofill_entry|";
32
33 // Merges timestamps from the |sync_timestamps| and the |local_entry|.
34 // Returns true if they were different, false if they were the same.  If the
35 // timestamps were different, fills |date_created| and |date_last_used| with the
36 // merged timestamps.  The |sync_timestamps| vector is assumed to be sorted.
37 bool MergeTimestamps(
38     const google::protobuf::RepeatedField<int64_t>& sync_timestamps,
39     const AutofillEntry& local_entry,
40     base::Time* date_created,
41     base::Time* date_last_used) {
42   if (sync_timestamps.size() == 0) {
43     *date_created = local_entry.date_created();
44     *date_last_used = local_entry.date_last_used();
45     return true;
46   }
47
48   base::Time sync_date_created =
49       base::Time::FromInternalValue(*sync_timestamps.begin());
50   base::Time sync_date_last_used =
51       base::Time::FromInternalValue(*sync_timestamps.rbegin());
52
53   if (sync_date_created == local_entry.date_created() &&
54       sync_date_last_used == local_entry.date_last_used())
55     return false;
56
57   *date_created = std::min(local_entry.date_created(), sync_date_created);
58   *date_last_used = std::max(local_entry.date_last_used(), sync_date_last_used);
59   return true;
60 }
61
62 void* UserDataKey() {
63   // Use the address of a static that COMDAT folding won't ever fold
64   // with something else.
65   static int user_data_key = 0;
66   return reinterpret_cast<void*>(&user_data_key);
67 }
68
69 }  // namespace
70
71 AutocompleteSyncableService::AutocompleteSyncableService(
72     AutofillWebDataBackend* web_data_backend)
73     : web_data_backend_(web_data_backend),
74       scoped_observer_(this) {
75   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
76   DCHECK(web_data_backend_);
77
78   scoped_observer_.Add(web_data_backend_);
79 }
80
81 AutocompleteSyncableService::~AutocompleteSyncableService() {
82   DCHECK(CalledOnValidThread());
83 }
84
85 // static
86 void AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
87     AutofillWebDataService* web_data_service,
88     AutofillWebDataBackend* web_data_backend) {
89   web_data_service->GetDBUserData()->SetUserData(
90       UserDataKey(), new AutocompleteSyncableService(web_data_backend));
91 }
92
93 // static
94 AutocompleteSyncableService* AutocompleteSyncableService::FromWebDataService(
95     AutofillWebDataService* web_data_service) {
96   return static_cast<AutocompleteSyncableService*>(
97       web_data_service->GetDBUserData()->GetUserData(UserDataKey()));
98 }
99
100 AutocompleteSyncableService::AutocompleteSyncableService()
101     : web_data_backend_(NULL),
102       scoped_observer_(this) {
103   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
104 }
105
106 void AutocompleteSyncableService::InjectStartSyncFlare(
107     const syncer::SyncableService::StartSyncFlare& flare) {
108   flare_ = flare;
109 }
110
111 syncer::SyncMergeResult AutocompleteSyncableService::MergeDataAndStartSyncing(
112     syncer::ModelType type,
113     const syncer::SyncDataList& initial_sync_data,
114     scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
115     scoped_ptr<syncer::SyncErrorFactory> error_handler) {
116   DCHECK(CalledOnValidThread());
117   DCHECK(!sync_processor_);
118   DCHECK(sync_processor);
119   DCHECK(error_handler);
120
121   syncer::SyncMergeResult merge_result(type);
122   error_handler_ = error_handler.Pass();
123   std::vector<AutofillEntry> entries;
124   if (!LoadAutofillData(&entries)) {
125     merge_result.set_error(error_handler_->CreateAndUploadError(
126         FROM_HERE,
127         "Could not load autocomplete data from the WebDatabase."));
128     return merge_result;
129   }
130
131   AutocompleteEntryMap new_db_entries;
132   for (std::vector<AutofillEntry>::iterator it = entries.begin();
133        it != entries.end(); ++it) {
134     new_db_entries[it->key()] =
135         std::make_pair(syncer::SyncChange::ACTION_ADD, it);
136   }
137
138   sync_processor_ = sync_processor.Pass();
139
140   std::vector<AutofillEntry> new_synced_entries;
141   // Go through and check for all the entries that sync already knows about.
142   // CreateOrUpdateEntry() will remove entries that are same with the synced
143   // ones from |new_db_entries|.
144   for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
145        it != initial_sync_data.end(); ++it) {
146     CreateOrUpdateEntry(*it, &new_db_entries, &new_synced_entries);
147   }
148
149   if (!SaveChangesToWebData(new_synced_entries)) {
150     merge_result.set_error(error_handler_->CreateAndUploadError(
151         FROM_HERE,
152         "Failed to update webdata."));
153     return merge_result;
154   }
155
156   syncer::SyncChangeList new_changes;
157   for (AutocompleteEntryMap::iterator it = new_db_entries.begin();
158        it != new_db_entries.end(); ++it) {
159     new_changes.push_back(
160         syncer::SyncChange(FROM_HERE,
161                            it->second.first,
162                            CreateSyncData(*(it->second.second))));
163   }
164
165   merge_result.set_error(
166       sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes));
167
168   // This will schedule a deletion operation on the DB thread, which will
169   // trigger a notification to propagate the deletion to Sync.
170   // NOTE: This must be called *after* the ProcessSyncChanges call above.
171   // Otherwise, an item that Sync is not yet aware of might expire, causing a
172   // Sync error when that item's deletion is propagated to Sync.
173   web_data_backend_->RemoveExpiredFormElements();
174
175   return merge_result;
176 }
177
178 void AutocompleteSyncableService::StopSyncing(syncer::ModelType type) {
179   DCHECK(CalledOnValidThread());
180   DCHECK_EQ(syncer::AUTOFILL, type);
181
182   sync_processor_.reset();
183   error_handler_.reset();
184 }
185
186 syncer::SyncDataList AutocompleteSyncableService::GetAllSyncData(
187     syncer::ModelType type) const {
188   DCHECK(CalledOnValidThread());
189   DCHECK(sync_processor_);
190   DCHECK_EQ(type, syncer::AUTOFILL);
191
192   syncer::SyncDataList current_data;
193
194   std::vector<AutofillEntry> entries;
195   if (!LoadAutofillData(&entries))
196     return current_data;
197
198   for (std::vector<AutofillEntry>::iterator it = entries.begin();
199        it != entries.end(); ++it) {
200     current_data.push_back(CreateSyncData(*it));
201   }
202
203   return current_data;
204 }
205
206 syncer::SyncError AutocompleteSyncableService::ProcessSyncChanges(
207     const tracked_objects::Location& from_here,
208     const syncer::SyncChangeList& change_list) {
209   DCHECK(CalledOnValidThread());
210   DCHECK(sync_processor_);
211
212   if (!sync_processor_) {
213     syncer::SyncError error(FROM_HERE,
214                             syncer::SyncError::DATATYPE_ERROR,
215                             "Models not yet associated.",
216                             syncer::AUTOFILL);
217     return error;
218   }
219
220   // Data is loaded only if we get new ADD/UPDATE change.
221   std::vector<AutofillEntry> entries;
222   scoped_ptr<AutocompleteEntryMap> db_entries;
223   std::vector<AutofillEntry> new_entries;
224
225   syncer::SyncError list_processing_error;
226
227   for (syncer::SyncChangeList::const_iterator i = change_list.begin();
228        i != change_list.end() && !list_processing_error.IsSet(); ++i) {
229     DCHECK(i->IsValid());
230     switch (i->change_type()) {
231       case syncer::SyncChange::ACTION_ADD:
232       case syncer::SyncChange::ACTION_UPDATE:
233         if (!db_entries) {
234           if (!LoadAutofillData(&entries)) {
235             return error_handler_->CreateAndUploadError(
236                 FROM_HERE,
237                 "Could not get the autocomplete data from WebDatabase.");
238           }
239           db_entries.reset(new AutocompleteEntryMap);
240           for (std::vector<AutofillEntry>::iterator it = entries.begin();
241                it != entries.end(); ++it) {
242             (*db_entries)[it->key()] =
243                 std::make_pair(syncer::SyncChange::ACTION_ADD, it);
244           }
245         }
246         CreateOrUpdateEntry(i->sync_data(), db_entries.get(), &new_entries);
247         break;
248
249       case syncer::SyncChange::ACTION_DELETE: {
250         DCHECK(i->sync_data().GetSpecifics().has_autofill())
251             << "Autofill specifics data not present on delete!";
252         const sync_pb::AutofillSpecifics& autofill =
253             i->sync_data().GetSpecifics().autofill();
254         if (autofill.has_value())
255           list_processing_error = AutofillEntryDelete(autofill);
256         else
257           DVLOG(1) << "Delete for old-style autofill profile being dropped!";
258         break;
259       }
260
261       case syncer::SyncChange::ACTION_INVALID:
262         NOTREACHED();
263         return error_handler_->CreateAndUploadError(
264             FROM_HERE,
265             "ProcessSyncChanges failed on ChangeType " +
266                  syncer::SyncChange::ChangeTypeToString(i->change_type()));
267     }
268   }
269
270   if (!SaveChangesToWebData(new_entries)) {
271     return error_handler_->CreateAndUploadError(
272         FROM_HERE,
273         "Failed to update webdata.");
274   }
275
276   // This will schedule a deletion operation on the DB thread, which will
277   // trigger a notification to propagate the deletion to Sync.
278   web_data_backend_->RemoveExpiredFormElements();
279
280   return list_processing_error;
281 }
282
283 void AutocompleteSyncableService::AutofillEntriesChanged(
284     const AutofillChangeList& changes) {
285   // Check if sync is on. If we receive this notification prior to sync being
286   // started, we'll notify sync to start as soon as it can and later process all
287   // entries when MergeDataAndStartSyncing() is called. If we receive this
288   // notification after sync has exited, it will be synced the next time Chrome
289   // starts.
290   if (sync_processor_) {
291     ActOnChanges(changes);
292   } else if (!flare_.is_null()) {
293     flare_.Run(syncer::AUTOFILL);
294     flare_.Reset();
295   }
296 }
297
298 bool AutocompleteSyncableService::LoadAutofillData(
299     std::vector<AutofillEntry>* entries) const {
300   return GetAutofillTable()->GetAllAutofillEntries(entries);
301 }
302
303 bool AutocompleteSyncableService::SaveChangesToWebData(
304     const std::vector<AutofillEntry>& new_entries) {
305   DCHECK(CalledOnValidThread());
306   if (!GetAutofillTable()->UpdateAutofillEntries(new_entries))
307     return false;
308
309   web_data_backend_->NotifyOfMultipleAutofillChanges();
310   return true;
311 }
312
313 // Creates or updates an autocomplete entry based on |data|.
314 void AutocompleteSyncableService::CreateOrUpdateEntry(
315     const syncer::SyncData& data,
316     AutocompleteEntryMap* loaded_data,
317     std::vector<AutofillEntry>* new_entries) {
318   const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
319   const sync_pb::AutofillSpecifics& autofill_specifics(specifics.autofill());
320
321   if (!autofill_specifics.has_value()) {
322     DVLOG(1) << "Add/Update for old-style autofill profile being dropped!";
323     return;
324   }
325
326   AutofillKey key(autofill_specifics.name().c_str(),
327                   autofill_specifics.value().c_str());
328   AutocompleteEntryMap::iterator it = loaded_data->find(key);
329   const google::protobuf::RepeatedField<int64_t>& timestamps =
330       autofill_specifics.usage_timestamp();
331   if (it == loaded_data->end()) {
332     // New entry.
333     base::Time date_created, date_last_used;
334     if (timestamps.size() > 0) {
335       date_created = base::Time::FromInternalValue(*timestamps.begin());
336       date_last_used = base::Time::FromInternalValue(*timestamps.rbegin());
337     }
338     new_entries->push_back(AutofillEntry(key, date_created, date_last_used));
339   } else {
340     // Entry already present - merge if necessary.
341     base::Time date_created, date_last_used;
342     bool different = MergeTimestamps(timestamps, *it->second.second,
343                                      &date_created, &date_last_used);
344     if (different) {
345       AutofillEntry new_entry(
346           it->second.second->key(), date_created, date_last_used);
347       new_entries->push_back(new_entry);
348       // Update the sync db since the timestamps have changed.
349       *(it->second.second) = new_entry;
350       it->second.first = syncer::SyncChange::ACTION_UPDATE;
351     } else {
352       loaded_data->erase(it);
353     }
354   }
355 }
356
357 // static
358 void AutocompleteSyncableService::WriteAutofillEntry(
359     const AutofillEntry& entry, sync_pb::EntitySpecifics* autofill_specifics) {
360   sync_pb::AutofillSpecifics* autofill =
361       autofill_specifics->mutable_autofill();
362   autofill->set_name(base::UTF16ToUTF8(entry.key().name()));
363   autofill->set_value(base::UTF16ToUTF8(entry.key().value()));
364   autofill->add_usage_timestamp(entry.date_created().ToInternalValue());
365   if (entry.date_created() != entry.date_last_used())
366     autofill->add_usage_timestamp(entry.date_last_used().ToInternalValue());
367 }
368
369 syncer::SyncError AutocompleteSyncableService::AutofillEntryDelete(
370     const sync_pb::AutofillSpecifics& autofill) {
371   if (!GetAutofillTable()->RemoveFormElement(
372           base::UTF8ToUTF16(autofill.name()),
373           base::UTF8ToUTF16(autofill.value()))) {
374     return error_handler_->CreateAndUploadError(
375         FROM_HERE,
376         "Could not remove autocomplete entry from WebDatabase.");
377   }
378   return syncer::SyncError();
379 }
380
381 void AutocompleteSyncableService::ActOnChanges(
382      const AutofillChangeList& changes) {
383   DCHECK(sync_processor_);
384   syncer::SyncChangeList new_changes;
385   for (AutofillChangeList::const_iterator change = changes.begin();
386        change != changes.end(); ++change) {
387     switch (change->type()) {
388       case AutofillChange::ADD:
389       case AutofillChange::UPDATE: {
390         base::Time date_created, date_last_used;
391         bool success = GetAutofillTable()->GetAutofillTimestamps(
392             change->key().name(), change->key().value(),
393             &date_created, &date_last_used);
394         DCHECK(success);
395         AutofillEntry entry(change->key(), date_created, date_last_used);
396         syncer::SyncChange::SyncChangeType change_type =
397            (change->type() == AutofillChange::ADD) ?
398             syncer::SyncChange::ACTION_ADD :
399             syncer::SyncChange::ACTION_UPDATE;
400         new_changes.push_back(syncer::SyncChange(FROM_HERE,
401                                                  change_type,
402                                                  CreateSyncData(entry)));
403         break;
404       }
405
406       case AutofillChange::REMOVE: {
407         AutofillEntry entry(change->key(), base::Time(), base::Time());
408         new_changes.push_back(
409             syncer::SyncChange(FROM_HERE,
410                                syncer::SyncChange::ACTION_DELETE,
411                                CreateSyncData(entry)));
412         break;
413       }
414     }
415   }
416   syncer::SyncError error =
417       sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
418   if (error.IsSet()) {
419     DVLOG(1) << "[AUTOCOMPLETE SYNC] Failed processing change.  Error: "
420              << error.message();
421   }
422 }
423
424 syncer::SyncData AutocompleteSyncableService::CreateSyncData(
425     const AutofillEntry& entry) const {
426   sync_pb::EntitySpecifics autofill_specifics;
427   WriteAutofillEntry(entry, &autofill_specifics);
428   std::string tag(KeyToTag(base::UTF16ToUTF8(entry.key().name()),
429                            base::UTF16ToUTF8(entry.key().value())));
430   return syncer::SyncData::CreateLocalData(tag, tag, autofill_specifics);
431 }
432
433 AutofillTable* AutocompleteSyncableService::GetAutofillTable() const {
434   return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase());
435 }
436
437 // static
438 std::string AutocompleteSyncableService::KeyToTag(const std::string& name,
439                                                   const std::string& value) {
440   std::string prefix(kAutofillEntryNamespaceTag);
441   return prefix + net::EscapePath(name) + "|" + net::EscapePath(value);
442 }