Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync / glue / generic_change_processor.cc
blob91931922c6f79c58907eefdbb781193f587b2c48
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.
5 #include "chrome/browser/sync/glue/generic_change_processor.h"
7 #include "base/location.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "sync/api/sync_change.h"
12 #include "sync/api/sync_error.h"
13 #include "sync/api/syncable_service.h"
14 #include "sync/internal_api/public/base_node.h"
15 #include "sync/internal_api/public/change_record.h"
16 #include "sync/internal_api/public/read_node.h"
17 #include "sync/internal_api/public/read_transaction.h"
18 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
19 #include "sync/internal_api/public/write_node.h"
20 #include "sync/internal_api/public/write_transaction.h"
21 #include "sync/syncable/entry.h" // TODO(tim): Bug 123674.
23 using content::BrowserThread;
25 namespace browser_sync {
27 namespace {
29 void SetNodeSpecifics(const sync_pb::EntitySpecifics& entity_specifics,
30 syncer::WriteNode* write_node) {
31 if (syncer::GetModelTypeFromSpecifics(entity_specifics) ==
32 syncer::PASSWORDS) {
33 write_node->SetPasswordSpecifics(
34 entity_specifics.password().client_only_encrypted_data());
35 } else {
36 write_node->SetEntitySpecifics(entity_specifics);
40 syncer::SyncData BuildRemoteSyncData(
41 int64 sync_id,
42 const syncer::BaseNode& read_node) {
43 // Use the specifics of non-password datatypes directly (encryption has
44 // already been handled).
45 if (read_node.GetModelType() != syncer::PASSWORDS) {
46 return syncer::SyncData::CreateRemoteData(sync_id,
47 read_node.GetEntitySpecifics(),
48 read_node.GetModificationTime());
51 // Passwords must be accessed differently, to account for their encryption,
52 // and stored into a temporary EntitySpecifics.
53 sync_pb::EntitySpecifics password_holder;
54 password_holder.mutable_password()->mutable_client_only_encrypted_data()->
55 CopyFrom(read_node.GetPasswordSpecifics());
56 return syncer::SyncData::CreateRemoteData(sync_id,
57 password_holder,
58 read_node.GetModificationTime());
61 } // namespace
63 GenericChangeProcessor::GenericChangeProcessor(
64 DataTypeErrorHandler* error_handler,
65 const base::WeakPtr<syncer::SyncableService>& local_service,
66 const base::WeakPtr<syncer::SyncMergeResult>& merge_result,
67 syncer::UserShare* user_share)
68 : ChangeProcessor(error_handler),
69 local_service_(local_service),
70 merge_result_(merge_result),
71 share_handle_(user_share) {
72 DCHECK(CalledOnValidThread());
75 GenericChangeProcessor::~GenericChangeProcessor() {
76 DCHECK(CalledOnValidThread());
79 void GenericChangeProcessor::ApplyChangesFromSyncModel(
80 const syncer::BaseTransaction* trans,
81 int64 model_version,
82 const syncer::ImmutableChangeRecordList& changes) {
83 DCHECK(CalledOnValidThread());
84 DCHECK(syncer_changes_.empty());
85 for (syncer::ChangeRecordList::const_iterator it =
86 changes.Get().begin(); it != changes.Get().end(); ++it) {
87 if (it->action == syncer::ChangeRecord::ACTION_DELETE) {
88 syncer_changes_.push_back(
89 syncer::SyncChange(
90 FROM_HERE,
91 syncer::SyncChange::ACTION_DELETE,
92 syncer::SyncData::CreateRemoteData(
93 it->id, it->specifics, base::Time())));
94 } else {
95 syncer::SyncChange::SyncChangeType action =
96 (it->action == syncer::ChangeRecord::ACTION_ADD) ?
97 syncer::SyncChange::ACTION_ADD : syncer::SyncChange::ACTION_UPDATE;
98 // Need to load specifics from node.
99 syncer::ReadNode read_node(trans);
100 if (read_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) {
101 error_handler()->OnSingleDatatypeUnrecoverableError(
102 FROM_HERE,
103 "Failed to look up data for received change with id " +
104 base::Int64ToString(it->id));
105 return;
107 syncer_changes_.push_back(
108 syncer::SyncChange(
109 FROM_HERE,
110 action,
111 BuildRemoteSyncData(it->id, read_node)));
116 void GenericChangeProcessor::CommitChangesFromSyncModel() {
117 DCHECK(CalledOnValidThread());
118 if (syncer_changes_.empty())
119 return;
120 if (!local_service_.get()) {
121 syncer::ModelType type = syncer_changes_[0].sync_data().GetDataType();
122 syncer::SyncError error(FROM_HERE,
123 syncer::SyncError::DATATYPE_ERROR,
124 "Local service destroyed.",
125 type);
126 error_handler()->OnSingleDatatypeUnrecoverableError(error.location(),
127 error.message());
128 return;
130 syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE,
131 syncer_changes_);
132 syncer_changes_.clear();
133 if (error.IsSet()) {
134 error_handler()->OnSingleDatatypeUnrecoverableError(
135 error.location(), error.message());
139 syncer::SyncDataList GenericChangeProcessor::GetAllSyncData(
140 syncer::ModelType type) const {
141 // This is slow / memory intensive. Should be used sparingly by datatypes.
142 syncer::SyncDataList data;
143 GetAllSyncDataReturnError(type, &data);
144 return data;
147 syncer::SyncError GenericChangeProcessor::GetAllSyncDataReturnError(
148 syncer::ModelType type,
149 syncer::SyncDataList* current_sync_data) const {
150 DCHECK(CalledOnValidThread());
151 std::string type_name = syncer::ModelTypeToString(type);
152 syncer::ReadTransaction trans(FROM_HERE, share_handle());
153 syncer::ReadNode root(&trans);
154 if (root.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
155 syncer::BaseNode::INIT_OK) {
156 syncer::SyncError error(FROM_HERE,
157 syncer::SyncError::DATATYPE_ERROR,
158 "Server did not create the top-level " + type_name +
159 " node. We might be running against an out-of-"
160 "date server.",
161 type);
162 return error;
165 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
166 DCHECK_NE(type, syncer::BOOKMARKS);
168 std::vector<int64> child_ids;
169 root.GetChildIds(&child_ids);
171 for (std::vector<int64>::iterator it = child_ids.begin();
172 it != child_ids.end(); ++it) {
173 syncer::ReadNode sync_child_node(&trans);
174 if (sync_child_node.InitByIdLookup(*it) !=
175 syncer::BaseNode::INIT_OK) {
176 syncer::SyncError error(FROM_HERE,
177 syncer::SyncError::DATATYPE_ERROR,
178 "Failed to fetch child node for type " +
179 type_name + ".",
180 type);
181 return error;
183 current_sync_data->push_back(BuildRemoteSyncData(sync_child_node.GetId(),
184 sync_child_node));
186 return syncer::SyncError();
189 int GenericChangeProcessor::GetSyncCountForType(syncer::ModelType type) {
190 syncer::ReadTransaction trans(FROM_HERE, share_handle());
191 syncer::ReadNode root(&trans);
192 if (root.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
193 syncer::BaseNode::INIT_OK)
194 return 0;
196 // Subtract one to account for type's root node.
197 return root.GetTotalNodeCount() - 1;
200 namespace {
202 // TODO(isherman): Investigating http://crbug.com/121592
203 // WARNING: this code is sensitive to compiler optimizations. Be careful
204 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
205 // the compiler attempts to merge it with other calls, losing useful information
206 // in breakpad uploads.
207 syncer::SyncError LogLookupFailure(
208 syncer::BaseNode::InitByLookupResult lookup_result,
209 const tracked_objects::Location& from_here,
210 const std::string& error_prefix,
211 syncer::ModelType type,
212 DataTypeErrorHandler* error_handler) {
213 switch (lookup_result) {
214 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD: {
215 syncer::SyncError error;
216 error.Reset(from_here,
217 error_prefix +
218 "could not find entry matching the lookup criteria.",
219 type);
220 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
221 error.message());
222 LOG(ERROR) << "Delete: Bad entry.";
223 return error;
225 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL: {
226 syncer::SyncError error;
227 error.Reset(from_here, error_prefix + "entry is already deleted.", type);
228 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
229 error.message());
230 LOG(ERROR) << "Delete: Deleted entry.";
231 return error;
233 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY: {
234 syncer::SyncError error;
235 error.Reset(from_here, error_prefix + "unable to decrypt", type);
236 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
237 error.message());
238 LOG(ERROR) << "Delete: Undecryptable entry.";
239 return error;
241 case syncer::BaseNode::INIT_FAILED_PRECONDITION: {
242 syncer::SyncError error;
243 error.Reset(from_here,
244 error_prefix + "a precondition was not met for calling init.",
245 type);
246 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
247 error.message());
248 LOG(ERROR) << "Delete: Failed precondition.";
249 return error;
251 default: {
252 syncer::SyncError error;
253 // Should have listed all the possible error cases above.
254 error.Reset(from_here, error_prefix + "unknown error", type);
255 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
256 error.message());
257 LOG(ERROR) << "Delete: Unknown error.";
258 return error;
263 syncer::SyncError AttemptDelete(
264 const syncer::SyncChange& change,
265 syncer::ModelType type,
266 const std::string& type_str,
267 syncer::WriteNode* node,
268 DataTypeErrorHandler* error_handler) {
269 DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE);
270 if (change.sync_data().IsLocal()) {
271 const std::string& tag = change.sync_data().GetTag();
272 if (tag.empty()) {
273 syncer::SyncError error(
274 FROM_HERE,
275 syncer::SyncError::DATATYPE_ERROR,
276 "Failed to delete " + type_str + " node. Local data, empty tag. " +
277 change.location().ToString(),
278 type);
279 error_handler->OnSingleDatatypeUnrecoverableError(error.location(),
280 error.message());
281 NOTREACHED();
282 return error;
285 syncer::BaseNode::InitByLookupResult result =
286 node->InitByClientTagLookup(change.sync_data().GetDataType(), tag);
287 if (result != syncer::BaseNode::INIT_OK) {
288 return LogLookupFailure(
289 result, FROM_HERE,
290 "Failed to delete " + type_str + " node. Local data. " +
291 change.location().ToString(),
292 type, error_handler);
294 } else {
295 syncer::BaseNode::InitByLookupResult result =
296 node->InitByIdLookup(change.sync_data().GetRemoteId());
297 if (result != syncer::BaseNode::INIT_OK) {
298 return LogLookupFailure(
299 result, FROM_HERE,
300 "Failed to delete " + type_str + " node. Non-local data. " +
301 change.location().ToString(),
302 type, error_handler);
305 if (IsActOnceDataType(type))
306 node->Drop();
307 else
308 node->Tombstone();
309 return syncer::SyncError();
312 } // namespace
314 // WARNING: this code is sensitive to compiler optimizations. Be careful
315 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
316 // the compiler attempts to merge it with other calls, losing useful information
317 // in breakpad uploads.
318 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges(
319 const tracked_objects::Location& from_here,
320 const syncer::SyncChangeList& list_of_changes) {
321 DCHECK(CalledOnValidThread());
322 syncer::WriteTransaction trans(from_here, share_handle());
324 for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin();
325 iter != list_of_changes.end();
326 ++iter) {
327 const syncer::SyncChange& change = *iter;
328 DCHECK_NE(change.sync_data().GetDataType(), syncer::UNSPECIFIED);
329 syncer::ModelType type = change.sync_data().GetDataType();
330 std::string type_str = syncer::ModelTypeToString(type);
331 syncer::WriteNode sync_node(&trans);
332 if (change.change_type() == syncer::SyncChange::ACTION_DELETE) {
333 syncer::SyncError error =
334 AttemptDelete(change, type, type_str, &sync_node,
335 error_handler());
336 if (error.IsSet()) {
337 NOTREACHED();
338 return error;
340 if (merge_result_.get()) {
341 merge_result_->set_num_items_deleted(
342 merge_result_->num_items_deleted() + 1);
344 } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) {
345 // TODO(sync): Handle other types of creation (custom parents, folders,
346 // etc.).
347 syncer::ReadNode root_node(&trans);
348 if (root_node.InitByTagLookup(
349 syncer::ModelTypeToRootTag(change.sync_data().GetDataType())) !=
350 syncer::BaseNode::INIT_OK) {
351 syncer::SyncError error(FROM_HERE,
352 syncer::SyncError::DATATYPE_ERROR,
353 "Failed to look up root node for type " +
354 type_str,
355 type);
356 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
357 error.message());
358 NOTREACHED();
359 LOG(ERROR) << "Create: no root node.";
360 return error;
362 syncer::WriteNode::InitUniqueByCreationResult result =
363 sync_node.InitUniqueByCreation(change.sync_data().GetDataType(),
364 root_node,
365 change.sync_data().GetTag());
366 if (result != syncer::WriteNode::INIT_SUCCESS) {
367 std::string error_prefix = "Failed to create " + type_str + " node: " +
368 change.location().ToString() + ", ";
369 switch (result) {
370 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG: {
371 syncer::SyncError error;
372 error.Reset(FROM_HERE, error_prefix + "empty tag", type);
373 error_handler()->OnSingleDatatypeUnrecoverableError(
374 FROM_HERE, error.message());
375 LOG(ERROR) << "Create: Empty tag.";
376 return error;
378 case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS: {
379 syncer::SyncError error;
380 error.Reset(FROM_HERE, error_prefix + "entry already exists", type);
381 error_handler()->OnSingleDatatypeUnrecoverableError(
382 FROM_HERE, error.message());
383 LOG(ERROR) << "Create: Entry exists.";
384 return error;
386 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: {
387 syncer::SyncError error;
388 error.Reset(FROM_HERE, error_prefix + "failed to create entry",
389 type);
390 error_handler()->OnSingleDatatypeUnrecoverableError(
391 FROM_HERE, error.message());
392 LOG(ERROR) << "Create: Could not create entry.";
393 return error;
395 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR: {
396 syncer::SyncError error;
397 error.Reset(FROM_HERE, error_prefix + "failed to set predecessor",
398 type);
399 error_handler()->OnSingleDatatypeUnrecoverableError(
400 FROM_HERE, error.message());
401 LOG(ERROR) << "Create: Bad predecessor.";
402 return error;
404 default: {
405 syncer::SyncError error;
406 error.Reset(FROM_HERE, error_prefix + "unknown error", type);
407 error_handler()->OnSingleDatatypeUnrecoverableError(
408 FROM_HERE, error.message());
409 LOG(ERROR) << "Create: Unknown error.";
410 return error;
414 sync_node.SetTitle(base::UTF8ToWide(change.sync_data().GetTitle()));
415 SetNodeSpecifics(change.sync_data().GetSpecifics(), &sync_node);
416 if (merge_result_.get()) {
417 merge_result_->set_num_items_added(merge_result_->num_items_added() +
420 } else if (change.change_type() == syncer::SyncChange::ACTION_UPDATE) {
421 // TODO(zea): consider having this logic for all possible changes?
422 syncer::BaseNode::InitByLookupResult result =
423 sync_node.InitByClientTagLookup(change.sync_data().GetDataType(),
424 change.sync_data().GetTag());
425 if (result != syncer::BaseNode::INIT_OK) {
426 std::string error_prefix = "Failed to load " + type_str + " node. " +
427 change.location().ToString() + ", ";
428 if (result == syncer::BaseNode::INIT_FAILED_PRECONDITION) {
429 syncer::SyncError error;
430 error.Reset(FROM_HERE,
431 error_prefix + "empty tag",
432 type);
433 error_handler()->OnSingleDatatypeUnrecoverableError(
434 FROM_HERE, error.message());
435 LOG(ERROR) << "Update: Empty tag.";
436 return error;
437 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD) {
438 syncer::SyncError error;
439 error.Reset(FROM_HERE,
440 error_prefix + "bad entry",
441 type);
442 error_handler()->OnSingleDatatypeUnrecoverableError(
443 FROM_HERE, error.message());
444 LOG(ERROR) << "Update: bad entry.";
445 return error;
446 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL) {
447 syncer::SyncError error;
448 error.Reset(FROM_HERE,
449 error_prefix + "deleted entry",
450 type);
451 error_handler()->OnSingleDatatypeUnrecoverableError(
452 FROM_HERE, error.message());
453 LOG(ERROR) << "Update: deleted entry.";
454 return error;
455 } else {
456 syncer::Cryptographer* crypto = trans.GetCryptographer();
457 syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes());
458 const sync_pb::EntitySpecifics& specifics =
459 sync_node.GetEntry()->GetSpecifics();
460 CHECK(specifics.has_encrypted());
461 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted());
462 const bool agreement = encrypted_types.Has(type);
463 if (!agreement && !can_decrypt) {
464 syncer::SyncError error;
465 error.Reset(FROM_HERE,
466 "Failed to load encrypted entry, missing key and "
467 "nigori mismatch for " + type_str + ".",
468 type);
469 error_handler()->OnSingleDatatypeUnrecoverableError(
470 FROM_HERE, error.message());
471 LOG(ERROR) << "Update: encr case 1.";
472 return error;
473 } else if (agreement && can_decrypt) {
474 syncer::SyncError error;
475 error.Reset(FROM_HERE,
476 "Failed to load encrypted entry, we have the key "
477 "and the nigori matches (?!) for " + type_str + ".",
478 type);
479 error_handler()->OnSingleDatatypeUnrecoverableError(
480 FROM_HERE, error.message());
481 LOG(ERROR) << "Update: encr case 2.";
482 return error;
483 } else if (agreement) {
484 syncer::SyncError error;
485 error.Reset(FROM_HERE,
486 "Failed to load encrypted entry, missing key and "
487 "the nigori matches for " + type_str + ".",
488 type);
489 error_handler()->OnSingleDatatypeUnrecoverableError(
490 FROM_HERE, error.message());
491 LOG(ERROR) << "Update: encr case 3.";
492 return error;
493 } else {
494 syncer::SyncError error;
495 error.Reset(FROM_HERE,
496 "Failed to load encrypted entry, we have the key"
497 "(?!) and nigori mismatch for " + type_str + ".",
498 type);
499 error_handler()->OnSingleDatatypeUnrecoverableError(
500 FROM_HERE, error.message());
501 LOG(ERROR) << "Update: encr case 4.";
502 return error;
507 sync_node.SetTitle(base::UTF8ToWide(change.sync_data().GetTitle()));
508 SetNodeSpecifics(change.sync_data().GetSpecifics(), &sync_node);
509 if (merge_result_.get()) {
510 merge_result_->set_num_items_modified(
511 merge_result_->num_items_modified() + 1);
513 // TODO(sync): Support updating other parts of the sync node (title,
514 // successor, parent, etc.).
515 } else {
516 syncer::SyncError error(
517 FROM_HERE,
518 syncer::SyncError::DATATYPE_ERROR,
519 "Received unset SyncChange in the change processor, " +
520 change.location().ToString(),
521 type);
522 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
523 error.message());
524 NOTREACHED();
525 LOG(ERROR) << "Unset sync change.";
526 return error;
529 return syncer::SyncError();
532 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(
533 syncer::ModelType type,
534 bool* has_nodes) {
535 DCHECK(CalledOnValidThread());
536 DCHECK(has_nodes);
537 DCHECK_NE(type, syncer::UNSPECIFIED);
538 std::string type_name = syncer::ModelTypeToString(type);
539 std::string err_str = "Server did not create the top-level " + type_name +
540 " node. We might be running against an out-of-date server.";
541 *has_nodes = false;
542 syncer::ReadTransaction trans(FROM_HERE, share_handle());
543 syncer::ReadNode type_root_node(&trans);
544 if (type_root_node.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
545 syncer::BaseNode::INIT_OK) {
546 LOG(ERROR) << err_str;
547 return false;
550 // The sync model has user created nodes if the type's root node has any
551 // children.
552 *has_nodes = type_root_node.HasChildren();
553 return true;
556 bool GenericChangeProcessor::CryptoReadyIfNecessary(syncer::ModelType type) {
557 DCHECK(CalledOnValidThread());
558 DCHECK_NE(type, syncer::UNSPECIFIED);
559 // We only access the cryptographer while holding a transaction.
560 syncer::ReadTransaction trans(FROM_HERE, share_handle());
561 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
562 return !encrypted_types.Has(type) ||
563 trans.GetCryptographer()->is_ready();
566 void GenericChangeProcessor::StartImpl(Profile* profile) {
567 DCHECK(CalledOnValidThread());
570 syncer::UserShare* GenericChangeProcessor::share_handle() const {
571 DCHECK(CalledOnValidThread());
572 return share_handle_;
575 } // namespace browser_sync