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. 4 5 #include "sync/engine/download.h" 6 7 #include <string> 8 9 #include "base/command_line.h" 10 #include "sync/engine/process_updates_command.h" 11 #include "sync/engine/store_timestamps_command.h" 12 #include "sync/engine/syncer.h" 13 #include "sync/engine/syncer_proto_util.h" 14 #include "sync/internal_api/public/base/model_type_invalidation_map.h" 15 #include "sync/sessions/nudge_tracker.h" 16 #include "sync/syncable/directory.h" 17 #include "sync/syncable/nigori_handler.h" 18 #include "sync/syncable/syncable_read_transaction.h" 19 20 using sync_pb::DebugInfo; 21 22 namespace syncer { 23 24 using sessions::StatusController; 25 using sessions::SyncSession; 26 using sessions::SyncSessionContext; 27 using std::string; 28 29 namespace { 30 31 SyncerError HandleGetEncryptionKeyResponse( 32 const sync_pb::ClientToServerResponse& update_response, 33 syncable::Directory* dir) { 34 bool success = false; 35 if (update_response.get_updates().encryption_keys_size() == 0) { 36 LOG(ERROR) << "Failed to receive encryption key from server."; 37 return SERVER_RESPONSE_VALIDATION_FAILED; 38 } 39 syncable::ReadTransaction trans(FROM_HERE, dir); 40 syncable::NigoriHandler* nigori_handler = dir->GetNigoriHandler(); 41 success = nigori_handler->SetKeystoreKeys( 42 update_response.get_updates().encryption_keys(), 43 &trans); 44 45 DVLOG(1) << "GetUpdates returned " 46 << update_response.get_updates().encryption_keys_size() 47 << "encryption keys. Nigori keystore key " 48 << (success ? "" : "not ") << "updated."; 49 return (success ? SYNCER_OK : SERVER_RESPONSE_VALIDATION_FAILED); 50 } 51 52 sync_pb::SyncEnums::GetUpdatesOrigin ConvertConfigureSourceToOrigin( 53 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) { 54 switch (source) { 55 // Configurations: 56 case sync_pb::GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE: 57 return sync_pb::SyncEnums::NEWLY_SUPPORTED_DATATYPE; 58 case sync_pb::GetUpdatesCallerInfo::MIGRATION: 59 return sync_pb::SyncEnums::MIGRATION; 60 case sync_pb::GetUpdatesCallerInfo::RECONFIGURATION: 61 return sync_pb::SyncEnums::RECONFIGURATION; 62 case sync_pb::GetUpdatesCallerInfo::NEW_CLIENT: 63 return sync_pb::SyncEnums::NEW_CLIENT; 64 default: 65 NOTREACHED(); 66 return sync_pb::SyncEnums::UNKNOWN_ORIGIN; 67 } 68 } 69 70 bool ShouldRequestEncryptionKey( 71 SyncSessionContext* context) { 72 bool need_encryption_key = false; 73 if (context->keystore_encryption_enabled()) { 74 syncable::Directory* dir = context->directory(); 75 syncable::ReadTransaction trans(FROM_HERE, dir); 76 syncable::NigoriHandler* nigori_handler = dir->GetNigoriHandler(); 77 need_encryption_key = nigori_handler->NeedKeystoreKey(&trans); 78 } 79 return need_encryption_key; 80 } 81 82 SyncerError ExecuteDownloadUpdates( 83 SyncSession* session, 84 sync_pb::ClientToServerMessage* msg) { 85 sync_pb::ClientToServerResponse update_response; 86 StatusController* status = session->mutable_status_controller(); 87 bool need_encryption_key = ShouldRequestEncryptionKey(session->context()); 88 89 SyncerError result = SyncerProtoUtil::PostClientToServerMessage( 90 msg, 91 &update_response, 92 session); 93 94 DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString( 95 update_response); 96 97 if (result != SYNCER_OK) { 98 status->mutable_updates_response()->Clear(); 99 LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates"; 100 } else { 101 status->mutable_updates_response()->CopyFrom(update_response); 102 103 DVLOG(1) << "GetUpdates " 104 << " returned " << update_response.get_updates().entries_size() 105 << " updates and indicated " 106 << update_response.get_updates().changes_remaining() 107 << " updates left on server."; 108 109 if (need_encryption_key || 110 update_response.get_updates().encryption_keys_size() > 0) { 111 syncable::Directory* dir = session->context()->directory(); 112 status->set_last_get_key_result( 113 HandleGetEncryptionKeyResponse(update_response, dir)); 114 } 115 } 116 117 ProcessUpdatesCommand process_updates; 118 process_updates.Execute(session); 119 120 StoreTimestampsCommand store_timestamps; 121 store_timestamps.Execute(session); 122 123 return result; 124 } 125 126 void InitDownloadUpdatesRequest( 127 SyncSession* session, 128 bool create_mobile_bookmarks_folder, 129 sync_pb::ClientToServerMessage* message, 130 ModelTypeSet request_types) { 131 message->set_share(session->context()->account_name()); 132 message->set_message_contents(sync_pb::ClientToServerMessage::GET_UPDATES); 133 134 sync_pb::GetUpdatesMessage* get_updates = message->mutable_get_updates(); 135 136 // We want folders for our associated types, always. If we were to set 137 // this to false, the server would send just the non-container items 138 // (e.g. Bookmark URLs but not their containing folders). 139 get_updates->set_fetch_folders(true); 140 141 DebugInfo* debug_info = message->mutable_debug_info(); 142 AppendClientDebugInfoIfNeeded(session, debug_info); 143 144 get_updates->set_create_mobile_bookmarks_folder( 145 create_mobile_bookmarks_folder); 146 bool need_encryption_key = ShouldRequestEncryptionKey(session->context()); 147 get_updates->set_need_encryption_key(need_encryption_key); 148 149 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. 150 get_updates->mutable_caller_info()->set_notifications_enabled( 151 session->context()->notifications_enabled()); 152 153 StatusController* status = session->mutable_status_controller(); 154 status->set_updates_request_types(request_types); 155 156 syncable::Directory* dir = session->context()->directory(); 157 for (ModelTypeSet::Iterator it = request_types.First(); 158 it.Good(); it.Inc()) { 159 if (ProxyTypes().Has(it.Get())) 160 continue; 161 sync_pb::DataTypeProgressMarker* progress_marker = 162 get_updates->add_from_progress_marker(); 163 dir->GetDownloadProgress(it.Get(), progress_marker); 164 } 165 } 166 167 } // namespace 168 169 SyncerError NormalDownloadUpdates( 170 SyncSession* session, 171 bool create_mobile_bookmarks_folder, 172 ModelTypeSet request_types, 173 const sessions::NudgeTracker& nudge_tracker) { 174 sync_pb::ClientToServerMessage client_to_server_message; 175 InitDownloadUpdatesRequest( 176 session, 177 create_mobile_bookmarks_folder, 178 &client_to_server_message, 179 request_types); 180 sync_pb::GetUpdatesMessage* get_updates = 181 client_to_server_message.mutable_get_updates(); 182 183 // Request updates for all requested types. 184 DVLOG(1) << "Getting updates for types " 185 << ModelTypeSetToString(request_types); 186 DCHECK(!request_types.Empty()); 187 188 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. 189 get_updates->mutable_caller_info()->set_source( 190 nudge_tracker.updates_source()); 191 192 // Set the new and improved version of source, too. 193 get_updates->set_get_updates_origin(sync_pb::SyncEnums::GU_TRIGGER); 194 195 // Fill in the notification hints. 196 for (int i = 0; i < get_updates->from_progress_marker_size(); ++i) { 197 sync_pb::DataTypeProgressMarker* progress_marker = 198 get_updates->mutable_from_progress_marker(i); 199 ModelType type = GetModelTypeFromSpecificsFieldNumber( 200 progress_marker->data_type_id()); 201 202 DCHECK(!nudge_tracker.IsTypeThrottled(type)) 203 << "Throttled types should have been removed from the request_types."; 204 205 nudge_tracker.SetLegacyNotificationHint(type, progress_marker); 206 nudge_tracker.FillProtoMessage( 207 type, 208 progress_marker->mutable_get_update_triggers()); 209 } 210 211 return ExecuteDownloadUpdates(session, &client_to_server_message); 212 } 213 214 SyncerError DownloadUpdatesForConfigure( 215 SyncSession* session, 216 bool create_mobile_bookmarks_folder, 217 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source, 218 ModelTypeSet request_types) { 219 sync_pb::ClientToServerMessage client_to_server_message; 220 InitDownloadUpdatesRequest( 221 session, 222 create_mobile_bookmarks_folder, 223 &client_to_server_message, 224 request_types); 225 sync_pb::GetUpdatesMessage* get_updates = 226 client_to_server_message.mutable_get_updates(); 227 228 // Request updates for all enabled types. 229 DVLOG(1) << "Initial download for types " 230 << ModelTypeSetToString(request_types); 231 DCHECK(!request_types.Empty()); 232 233 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. 234 get_updates->mutable_caller_info()->set_source(source); 235 236 // Set the new and improved version of source, too. 237 sync_pb::SyncEnums::GetUpdatesOrigin origin = 238 ConvertConfigureSourceToOrigin(source); 239 get_updates->set_get_updates_origin(origin); 240 241 return ExecuteDownloadUpdates(session, &client_to_server_message); 242 } 243 244 SyncerError DownloadUpdatesForPoll( 245 SyncSession* session, 246 bool create_mobile_bookmarks_folder, 247 ModelTypeSet request_types) { 248 sync_pb::ClientToServerMessage client_to_server_message; 249 InitDownloadUpdatesRequest( 250 session, 251 create_mobile_bookmarks_folder, 252 &client_to_server_message, 253 request_types); 254 sync_pb::GetUpdatesMessage* get_updates = 255 client_to_server_message.mutable_get_updates(); 256 257 DVLOG(1) << "Polling for types " 258 << ModelTypeSetToString(request_types); 259 DCHECK(!request_types.Empty()); 260 261 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. 262 get_updates->mutable_caller_info()->set_source( 263 sync_pb::GetUpdatesCallerInfo::PERIODIC); 264 265 // Set the new and improved version of source, too. 266 get_updates->set_get_updates_origin(sync_pb::SyncEnums::PERIODIC); 267 268 return ExecuteDownloadUpdates(session, &client_to_server_message); 269 } 270 271 void AppendClientDebugInfoIfNeeded( 272 SyncSession* session, 273 DebugInfo* debug_info) { 274 // We want to send the debug info only once per sync cycle. Check if it has 275 // already been sent. 276 if (!session->status_controller().debug_info_sent()) { 277 DVLOG(1) << "Sending client debug info ..."; 278 // could be null in some unit tests. 279 if (session->context()->debug_info_getter()) { 280 session->context()->debug_info_getter()->GetAndClearDebugInfo( 281 debug_info); 282 } 283 session->mutable_status_controller()->set_debug_info_sent(); 284 } 285 } 286 287 } // namespace syncer 288