1 // Copyright 2013 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 "sync/engine/download.h"
9 #include "sync/engine/syncer_proto_util.h"
10 #include "sync/sessions/sync_session.h"
11 #include "sync/sessions/sync_session_context.h"
12 #include "sync/syncable/directory.h"
13 #include "sync/syncable/nigori_handler.h"
14 #include "sync/syncable/syncable_read_transaction.h"
18 using sessions::StatusController;
19 using sessions::SyncSession;
20 using sessions::SyncSessionContext;
25 SyncerError HandleGetEncryptionKeyResponse(
26 const sync_pb::ClientToServerResponse& update_response,
27 syncable::Directory* dir) {
29 if (update_response.get_updates().encryption_keys_size() == 0) {
30 LOG(ERROR) << "Failed to receive encryption key from server.";
31 return SERVER_RESPONSE_VALIDATION_FAILED;
33 syncable::ReadTransaction trans(FROM_HERE, dir);
34 syncable::NigoriHandler* nigori_handler = dir->GetNigoriHandler();
35 success = nigori_handler->SetKeystoreKeys(
36 update_response.get_updates().encryption_keys(),
39 DVLOG(1) << "GetUpdates returned "
40 << update_response.get_updates().encryption_keys_size()
41 << "encryption keys. Nigori keystore key "
42 << (success ? "" : "not ") << "updated.";
43 return (success ? SYNCER_OK : SERVER_RESPONSE_VALIDATION_FAILED);
46 bool ShouldRequestEncryptionKey(
47 SyncSessionContext* context) {
48 bool need_encryption_key = false;
49 if (context->keystore_encryption_enabled()) {
50 syncable::Directory* dir = context->directory();
51 syncable::ReadTransaction trans(FROM_HERE, dir);
52 syncable::NigoriHandler* nigori_handler = dir->GetNigoriHandler();
53 need_encryption_key = nigori_handler->NeedKeystoreKey(&trans);
55 return need_encryption_key;
62 void InitDownloadUpdatesContext(
64 bool create_mobile_bookmarks_folder,
65 sync_pb::ClientToServerMessage* message) {
66 message->set_share(session->context()->account_name());
67 message->set_message_contents(sync_pb::ClientToServerMessage::GET_UPDATES);
69 sync_pb::GetUpdatesMessage* get_updates = message->mutable_get_updates();
71 // We want folders for our associated types, always. If we were to set
72 // this to false, the server would send just the non-container items
73 // (e.g. Bookmark URLs but not their containing folders).
74 get_updates->set_fetch_folders(true);
76 get_updates->set_create_mobile_bookmarks_folder(
77 create_mobile_bookmarks_folder);
78 bool need_encryption_key = ShouldRequestEncryptionKey(session->context());
79 get_updates->set_need_encryption_key(need_encryption_key);
81 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information.
82 get_updates->mutable_caller_info()->set_notifications_enabled(
83 session->context()->notifications_enabled());
86 SyncerError ExecuteDownloadUpdates(
87 ModelTypeSet request_types,
89 GetUpdatesProcessor* get_updates_processor,
90 sync_pb::ClientToServerMessage* msg) {
91 sync_pb::ClientToServerResponse update_response;
92 StatusController* status = session->mutable_status_controller();
93 bool need_encryption_key = ShouldRequestEncryptionKey(session->context());
95 if (session->context()->debug_info_getter()) {
96 sync_pb::DebugInfo* debug_info = msg->mutable_debug_info();
97 CopyClientDebugInfo(session->context()->debug_info_getter(), debug_info);
100 SyncerError result = SyncerProtoUtil::PostClientToServerMessage(
105 DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString(
108 if (result != SYNCER_OK) {
109 LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates";
113 DVLOG(1) << "GetUpdates "
114 << " returned " << update_response.get_updates().entries_size()
115 << " updates and indicated "
116 << update_response.get_updates().changes_remaining()
117 << " updates left on server.";
119 if (session->context()->debug_info_getter()) {
120 // Clear debug info now that we have successfully sent it to the server.
121 DVLOG(1) << "Clearing client debug info.";
122 session->context()->debug_info_getter()->ClearDebugInfo();
125 if (need_encryption_key ||
126 update_response.get_updates().encryption_keys_size() > 0) {
127 syncable::Directory* dir = session->context()->directory();
128 status->set_last_get_key_result(
129 HandleGetEncryptionKeyResponse(update_response, dir));
132 return ProcessResponse(update_response.get_updates(),
134 get_updates_processor,
138 SyncerError ProcessResponse(
139 const sync_pb::GetUpdatesResponse& gu_response,
140 ModelTypeSet request_types,
141 GetUpdatesProcessor* get_updates_processor,
142 StatusController* status) {
143 status->increment_num_updates_downloaded_by(gu_response.entries_size());
145 // The changes remaining field is used to prevent the client from looping. If
146 // that field is being set incorrectly, we're in big trouble.
147 if (!gu_response.has_changes_remaining()) {
148 return SERVER_RESPONSE_VALIDATION_FAILED;
150 status->set_num_server_changes_remaining(gu_response.changes_remaining());
153 if (!get_updates_processor->ProcessGetUpdatesResponse(request_types,
156 return SERVER_RESPONSE_VALIDATION_FAILED;
159 if (gu_response.changes_remaining() == 0) {
162 return SERVER_MORE_TO_DOWNLOAD;
166 void CopyClientDebugInfo(
167 sessions::DebugInfoGetter* debug_info_getter,
168 sync_pb::DebugInfo* debug_info) {
169 DVLOG(1) << "Copying client debug info to send.";
170 debug_info_getter->GetDebugInfo(debug_info);
173 } // namespace download
175 } // namespace syncer