Update .DEPS.git
[chromium-blink-merge.git] / sync / engine / download.cc
blob3f32cd1d9e868c1a6396a4bb400506cc8bae07d7
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"
7 #include <string>
9 #include "base/command_line.h"
10 #include "sync/engine/syncer.h"
11 #include "sync/engine/syncer_proto_util.h"
12 #include "sync/sessions/nudge_tracker.h"
13 #include "sync/syncable/directory.h"
14 #include "sync/syncable/nigori_handler.h"
15 #include "sync/syncable/syncable_read_transaction.h"
17 namespace syncer {
19 using sessions::StatusController;
20 using sessions::SyncSession;
21 using sessions::SyncSessionContext;
22 using std::string;
24 namespace download {
26 namespace {
28 typedef std::map<ModelType, size_t> TypeToIndexMap;
30 SyncerError HandleGetEncryptionKeyResponse(
31 const sync_pb::ClientToServerResponse& update_response,
32 syncable::Directory* dir) {
33 bool success = false;
34 if (update_response.get_updates().encryption_keys_size() == 0) {
35 LOG(ERROR) << "Failed to receive encryption key from server.";
36 return SERVER_RESPONSE_VALIDATION_FAILED;
38 syncable::ReadTransaction trans(FROM_HERE, dir);
39 syncable::NigoriHandler* nigori_handler = dir->GetNigoriHandler();
40 success = nigori_handler->SetKeystoreKeys(
41 update_response.get_updates().encryption_keys(),
42 &trans);
44 DVLOG(1) << "GetUpdates returned "
45 << update_response.get_updates().encryption_keys_size()
46 << "encryption keys. Nigori keystore key "
47 << (success ? "" : "not ") << "updated.";
48 return (success ? SYNCER_OK : SERVER_RESPONSE_VALIDATION_FAILED);
51 sync_pb::SyncEnums::GetUpdatesOrigin ConvertConfigureSourceToOrigin(
52 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
53 switch (source) {
54 // Configurations:
55 case sync_pb::GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE:
56 return sync_pb::SyncEnums::NEWLY_SUPPORTED_DATATYPE;
57 case sync_pb::GetUpdatesCallerInfo::MIGRATION:
58 return sync_pb::SyncEnums::MIGRATION;
59 case sync_pb::GetUpdatesCallerInfo::RECONFIGURATION:
60 return sync_pb::SyncEnums::RECONFIGURATION;
61 case sync_pb::GetUpdatesCallerInfo::NEW_CLIENT:
62 return sync_pb::SyncEnums::NEW_CLIENT;
63 default:
64 NOTREACHED();
65 return sync_pb::SyncEnums::UNKNOWN_ORIGIN;
69 bool ShouldRequestEncryptionKey(
70 SyncSessionContext* context) {
71 bool need_encryption_key = false;
72 if (context->keystore_encryption_enabled()) {
73 syncable::Directory* dir = context->directory();
74 syncable::ReadTransaction trans(FROM_HERE, dir);
75 syncable::NigoriHandler* nigori_handler = dir->GetNigoriHandler();
76 need_encryption_key = nigori_handler->NeedKeystoreKey(&trans);
78 return need_encryption_key;
81 void InitDownloadUpdatesContext(
82 SyncSession* session,
83 bool create_mobile_bookmarks_folder,
84 sync_pb::ClientToServerMessage* message) {
85 message->set_share(session->context()->account_name());
86 message->set_message_contents(sync_pb::ClientToServerMessage::GET_UPDATES);
88 sync_pb::GetUpdatesMessage* get_updates = message->mutable_get_updates();
90 // We want folders for our associated types, always. If we were to set
91 // this to false, the server would send just the non-container items
92 // (e.g. Bookmark URLs but not their containing folders).
93 get_updates->set_fetch_folders(true);
95 get_updates->set_create_mobile_bookmarks_folder(
96 create_mobile_bookmarks_folder);
97 bool need_encryption_key = ShouldRequestEncryptionKey(session->context());
98 get_updates->set_need_encryption_key(need_encryption_key);
100 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information.
101 get_updates->mutable_caller_info()->set_notifications_enabled(
102 session->context()->notifications_enabled());
105 } // namespace
107 void BuildNormalDownloadUpdates(
108 SyncSession* session,
109 GetUpdatesProcessor* get_updates_processor,
110 bool create_mobile_bookmarks_folder,
111 ModelTypeSet request_types,
112 const sessions::NudgeTracker& nudge_tracker,
113 sync_pb::ClientToServerMessage* client_to_server_message) {
114 // Request updates for all requested types.
115 DVLOG(1) << "Getting updates for types "
116 << ModelTypeSetToString(request_types);
117 DCHECK(!request_types.Empty());
119 InitDownloadUpdatesContext(
120 session,
121 create_mobile_bookmarks_folder,
122 client_to_server_message);
124 BuildNormalDownloadUpdatesImpl(
125 Intersection(request_types, ProtocolTypes()),
126 get_updates_processor,
127 nudge_tracker,
128 client_to_server_message->mutable_get_updates());
131 void BuildNormalDownloadUpdatesImpl(
132 ModelTypeSet proto_request_types,
133 GetUpdatesProcessor* get_updates_processor,
134 const sessions::NudgeTracker& nudge_tracker,
135 sync_pb::GetUpdatesMessage* get_updates) {
136 DCHECK(!proto_request_types.Empty());
138 // Get progress markers and other data for requested types.
139 get_updates_processor->PrepareGetUpdates(proto_request_types, get_updates);
141 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information.
142 get_updates->mutable_caller_info()->set_source(
143 nudge_tracker.updates_source());
145 // Set the new and improved version of source, too.
146 get_updates->set_get_updates_origin(sync_pb::SyncEnums::GU_TRIGGER);
147 get_updates->set_is_retry(
148 nudge_tracker.IsRetryRequired(base::TimeTicks::Now()));
150 // Fill in the notification hints.
151 for (int i = 0; i < get_updates->from_progress_marker_size(); ++i) {
152 sync_pb::DataTypeProgressMarker* progress_marker =
153 get_updates->mutable_from_progress_marker(i);
154 ModelType type = GetModelTypeFromSpecificsFieldNumber(
155 progress_marker->data_type_id());
157 DCHECK(!nudge_tracker.IsTypeThrottled(type))
158 << "Throttled types should have been removed from the request_types.";
160 nudge_tracker.SetLegacyNotificationHint(type, progress_marker);
161 nudge_tracker.FillProtoMessage(
162 type,
163 progress_marker->mutable_get_update_triggers());
167 void BuildDownloadUpdatesForConfigure(
168 SyncSession* session,
169 GetUpdatesProcessor* get_updates_processor,
170 bool create_mobile_bookmarks_folder,
171 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
172 ModelTypeSet request_types,
173 sync_pb::ClientToServerMessage* client_to_server_message) {
174 // Request updates for all enabled types.
175 DVLOG(1) << "Initial download for types "
176 << ModelTypeSetToString(request_types);
178 InitDownloadUpdatesContext(
179 session,
180 create_mobile_bookmarks_folder,
181 client_to_server_message);
182 BuildDownloadUpdatesForConfigureImpl(
183 Intersection(request_types, ProtocolTypes()),
184 get_updates_processor,
185 source,
186 client_to_server_message->mutable_get_updates());
189 void BuildDownloadUpdatesForConfigureImpl(
190 ModelTypeSet proto_request_types,
191 GetUpdatesProcessor* get_updates_processor,
192 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
193 sync_pb::GetUpdatesMessage* get_updates) {
194 DCHECK(!proto_request_types.Empty());
196 // Get progress markers and other data for requested types.
197 get_updates_processor->PrepareGetUpdates(proto_request_types, get_updates);
199 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information.
200 get_updates->mutable_caller_info()->set_source(source);
202 // Set the new and improved version of source, too.
203 sync_pb::SyncEnums::GetUpdatesOrigin origin =
204 ConvertConfigureSourceToOrigin(source);
205 get_updates->set_get_updates_origin(origin);
208 void BuildDownloadUpdatesForPoll(
209 SyncSession* session,
210 GetUpdatesProcessor* get_updates_processor,
211 bool create_mobile_bookmarks_folder,
212 ModelTypeSet request_types,
213 sync_pb::ClientToServerMessage* client_to_server_message) {
214 DVLOG(1) << "Polling for types "
215 << ModelTypeSetToString(request_types);
217 InitDownloadUpdatesContext(
218 session,
219 create_mobile_bookmarks_folder,
220 client_to_server_message);
221 BuildDownloadUpdatesForPollImpl(
222 Intersection(request_types, ProtocolTypes()),
223 get_updates_processor,
224 client_to_server_message->mutable_get_updates());
227 void BuildDownloadUpdatesForPollImpl(
228 ModelTypeSet proto_request_types,
229 GetUpdatesProcessor* get_updates_processor,
230 sync_pb::GetUpdatesMessage* get_updates) {
231 DCHECK(!proto_request_types.Empty());
233 // Get progress markers and other data for requested types.
234 get_updates_processor->PrepareGetUpdates(proto_request_types, get_updates);
236 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information.
237 get_updates->mutable_caller_info()->set_source(
238 sync_pb::GetUpdatesCallerInfo::PERIODIC);
240 // Set the new and improved version of source, too.
241 get_updates->set_get_updates_origin(sync_pb::SyncEnums::PERIODIC);
244 void BuildDownloadUpdatesForRetry(
245 SyncSession* session,
246 GetUpdatesProcessor* get_updates_processor,
247 bool create_mobile_bookmarks_folder,
248 ModelTypeSet request_types,
249 sync_pb::ClientToServerMessage* client_to_server_message) {
250 DVLOG(1) << "Retrying for types "
251 << ModelTypeSetToString(request_types);
253 InitDownloadUpdatesContext(
254 session,
255 create_mobile_bookmarks_folder,
256 client_to_server_message);
257 BuildDownloadUpdatesForRetryImpl(
258 Intersection(request_types, ProtocolTypes()),
259 get_updates_processor,
260 client_to_server_message->mutable_get_updates());
263 void BuildDownloadUpdatesForRetryImpl(
264 ModelTypeSet proto_request_types,
265 GetUpdatesProcessor* get_updates_processor,
266 sync_pb::GetUpdatesMessage* get_updates) {
267 DCHECK(!proto_request_types.Empty());
269 get_updates_processor->PrepareGetUpdates(proto_request_types, get_updates);
271 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information.
272 get_updates->mutable_caller_info()->set_source(
273 sync_pb::GetUpdatesCallerInfo::RETRY);
275 // Set the new and improved version of source, too.
276 get_updates->set_get_updates_origin(sync_pb::SyncEnums::RETRY);
277 get_updates->set_is_retry(true);
280 SyncerError ExecuteDownloadUpdates(
281 ModelTypeSet request_types,
282 SyncSession* session,
283 GetUpdatesProcessor* get_updates_processor,
284 sync_pb::ClientToServerMessage* msg) {
285 sync_pb::ClientToServerResponse update_response;
286 StatusController* status = session->mutable_status_controller();
287 bool need_encryption_key = ShouldRequestEncryptionKey(session->context());
289 if (session->context()->debug_info_getter()) {
290 sync_pb::DebugInfo* debug_info = msg->mutable_debug_info();
291 CopyClientDebugInfo(session->context()->debug_info_getter(), debug_info);
294 SyncerError result = SyncerProtoUtil::PostClientToServerMessage(
295 msg,
296 &update_response,
297 session);
299 DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString(
300 update_response);
302 if (result != SYNCER_OK) {
303 LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates";
304 return result;
307 DVLOG(1) << "GetUpdates "
308 << " returned " << update_response.get_updates().entries_size()
309 << " updates and indicated "
310 << update_response.get_updates().changes_remaining()
311 << " updates left on server.";
313 if (session->context()->debug_info_getter()) {
314 // Clear debug info now that we have successfully sent it to the server.
315 DVLOG(1) << "Clearing client debug info.";
316 session->context()->debug_info_getter()->ClearDebugInfo();
319 if (need_encryption_key ||
320 update_response.get_updates().encryption_keys_size() > 0) {
321 syncable::Directory* dir = session->context()->directory();
322 status->set_last_get_key_result(
323 HandleGetEncryptionKeyResponse(update_response, dir));
326 const ModelTypeSet proto_request_types =
327 Intersection(request_types, ProtocolTypes());
329 return ProcessResponse(update_response.get_updates(),
330 proto_request_types,
331 get_updates_processor,
332 status);
335 SyncerError ProcessResponse(
336 const sync_pb::GetUpdatesResponse& gu_response,
337 ModelTypeSet proto_request_types,
338 GetUpdatesProcessor* get_updates_processor,
339 StatusController* status) {
340 status->increment_num_updates_downloaded_by(gu_response.entries_size());
342 // The changes remaining field is used to prevent the client from looping. If
343 // that field is being set incorrectly, we're in big trouble.
344 if (!gu_response.has_changes_remaining()) {
345 return SERVER_RESPONSE_VALIDATION_FAILED;
347 status->set_num_server_changes_remaining(gu_response.changes_remaining());
350 if (!get_updates_processor->ProcessGetUpdatesResponse(proto_request_types,
351 gu_response,
352 status)) {
353 return SERVER_RESPONSE_VALIDATION_FAILED;
356 if (gu_response.changes_remaining() == 0) {
357 return SYNCER_OK;
358 } else {
359 return SERVER_MORE_TO_DOWNLOAD;
363 void CopyClientDebugInfo(
364 sessions::DebugInfoGetter* debug_info_getter,
365 sync_pb::DebugInfo* debug_info) {
366 DVLOG(1) << "Copying client debug info to send.";
367 debug_info_getter->GetDebugInfo(debug_info);
370 } // namespace download
372 } // namespace syncer