| OLD | NEW |
| (Empty) |
| 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 "sync/engine/syncer_proto_util.h" | |
| 6 | |
| 7 #include <map> | |
| 8 | |
| 9 #include "base/format_macros.h" | |
| 10 #include "base/strings/stringprintf.h" | |
| 11 #include "google_apis/google_api_keys.h" | |
| 12 #include "sync/engine/net/server_connection_manager.h" | |
| 13 #include "sync/engine/syncer.h" | |
| 14 #include "sync/engine/syncer_types.h" | |
| 15 #include "sync/engine/traffic_logger.h" | |
| 16 #include "sync/internal_api/public/base/model_type.h" | |
| 17 #include "sync/protocol/sync_enums.pb.h" | |
| 18 #include "sync/protocol/sync_protocol_error.h" | |
| 19 #include "sync/sessions/sync_session.h" | |
| 20 #include "sync/syncable/directory.h" | |
| 21 #include "sync/syncable/entry.h" | |
| 22 #include "sync/syncable/syncable-inl.h" | |
| 23 #include "sync/syncable/syncable_proto_util.h" | |
| 24 #include "sync/util/time.h" | |
| 25 | |
| 26 using std::string; | |
| 27 using std::stringstream; | |
| 28 using sync_pb::ClientToServerMessage; | |
| 29 using sync_pb::ClientToServerResponse; | |
| 30 | |
| 31 namespace syncer { | |
| 32 | |
| 33 using sessions::SyncSession; | |
| 34 using syncable::BASE_VERSION; | |
| 35 using syncable::CTIME; | |
| 36 using syncable::ID; | |
| 37 using syncable::IS_DEL; | |
| 38 using syncable::IS_DIR; | |
| 39 using syncable::IS_UNSYNCED; | |
| 40 using syncable::MTIME; | |
| 41 using syncable::PARENT_ID; | |
| 42 | |
| 43 namespace { | |
| 44 | |
| 45 // Time to backoff syncing after receiving a throttled response. | |
| 46 const int kSyncDelayAfterThrottled = 2 * 60 * 60; // 2 hours | |
| 47 | |
| 48 void LogResponseProfilingData(const ClientToServerResponse& response) { | |
| 49 if (response.has_profiling_data()) { | |
| 50 stringstream response_trace; | |
| 51 response_trace << "Server response trace:"; | |
| 52 | |
| 53 if (response.profiling_data().has_user_lookup_time()) { | |
| 54 response_trace << " user lookup: " | |
| 55 << response.profiling_data().user_lookup_time() << "ms"; | |
| 56 } | |
| 57 | |
| 58 if (response.profiling_data().has_meta_data_write_time()) { | |
| 59 response_trace << " meta write: " | |
| 60 << response.profiling_data().meta_data_write_time() | |
| 61 << "ms"; | |
| 62 } | |
| 63 | |
| 64 if (response.profiling_data().has_meta_data_read_time()) { | |
| 65 response_trace << " meta read: " | |
| 66 << response.profiling_data().meta_data_read_time() << "ms"; | |
| 67 } | |
| 68 | |
| 69 if (response.profiling_data().has_file_data_write_time()) { | |
| 70 response_trace << " file write: " | |
| 71 << response.profiling_data().file_data_write_time() | |
| 72 << "ms"; | |
| 73 } | |
| 74 | |
| 75 if (response.profiling_data().has_file_data_read_time()) { | |
| 76 response_trace << " file read: " | |
| 77 << response.profiling_data().file_data_read_time() << "ms"; | |
| 78 } | |
| 79 | |
| 80 if (response.profiling_data().has_total_request_time()) { | |
| 81 response_trace << " total time: " | |
| 82 << response.profiling_data().total_request_time() << "ms"; | |
| 83 } | |
| 84 DVLOG(1) << response_trace.str(); | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 SyncerError ServerConnectionErrorAsSyncerError( | |
| 89 const HttpResponse::ServerConnectionCode server_status) { | |
| 90 switch (server_status) { | |
| 91 case HttpResponse::CONNECTION_UNAVAILABLE: | |
| 92 return NETWORK_CONNECTION_UNAVAILABLE; | |
| 93 case HttpResponse::IO_ERROR: | |
| 94 return NETWORK_IO_ERROR; | |
| 95 case HttpResponse::SYNC_SERVER_ERROR: | |
| 96 // FIXME what does this mean? | |
| 97 return SYNC_SERVER_ERROR; | |
| 98 case HttpResponse::SYNC_AUTH_ERROR: | |
| 99 return SYNC_AUTH_ERROR; | |
| 100 case HttpResponse::RETRY: | |
| 101 return SERVER_RETURN_TRANSIENT_ERROR; | |
| 102 case HttpResponse::SERVER_CONNECTION_OK: | |
| 103 case HttpResponse::NONE: | |
| 104 default: | |
| 105 NOTREACHED(); | |
| 106 return UNSET; | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 SyncProtocolErrorType PBErrorTypeToSyncProtocolErrorType( | |
| 111 const sync_pb::SyncEnums::ErrorType& error_type) { | |
| 112 switch (error_type) { | |
| 113 case sync_pb::SyncEnums::SUCCESS: | |
| 114 return SYNC_SUCCESS; | |
| 115 case sync_pb::SyncEnums::NOT_MY_BIRTHDAY: | |
| 116 return NOT_MY_BIRTHDAY; | |
| 117 case sync_pb::SyncEnums::THROTTLED: | |
| 118 return THROTTLED; | |
| 119 case sync_pb::SyncEnums::CLEAR_PENDING: | |
| 120 return CLEAR_PENDING; | |
| 121 case sync_pb::SyncEnums::TRANSIENT_ERROR: | |
| 122 return TRANSIENT_ERROR; | |
| 123 case sync_pb::SyncEnums::MIGRATION_DONE: | |
| 124 return MIGRATION_DONE; | |
| 125 case sync_pb::SyncEnums::DISABLED_BY_ADMIN: | |
| 126 return DISABLED_BY_ADMIN; | |
| 127 case sync_pb::SyncEnums::PARTIAL_FAILURE: | |
| 128 return PARTIAL_FAILURE; | |
| 129 case sync_pb::SyncEnums::CLIENT_DATA_OBSOLETE: | |
| 130 return CLIENT_DATA_OBSOLETE; | |
| 131 case sync_pb::SyncEnums::UNKNOWN: | |
| 132 return UNKNOWN_ERROR; | |
| 133 default: | |
| 134 NOTREACHED(); | |
| 135 return UNKNOWN_ERROR; | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 ClientAction PBActionToClientAction(const sync_pb::SyncEnums::Action& action) { | |
| 140 switch (action) { | |
| 141 case sync_pb::SyncEnums::UPGRADE_CLIENT: | |
| 142 return UPGRADE_CLIENT; | |
| 143 case sync_pb::SyncEnums::CLEAR_USER_DATA_AND_RESYNC: | |
| 144 return CLEAR_USER_DATA_AND_RESYNC; | |
| 145 case sync_pb::SyncEnums::ENABLE_SYNC_ON_ACCOUNT: | |
| 146 return ENABLE_SYNC_ON_ACCOUNT; | |
| 147 case sync_pb::SyncEnums::STOP_AND_RESTART_SYNC: | |
| 148 return STOP_AND_RESTART_SYNC; | |
| 149 case sync_pb::SyncEnums::DISABLE_SYNC_ON_CLIENT: | |
| 150 return DISABLE_SYNC_ON_CLIENT; | |
| 151 case sync_pb::SyncEnums::UNKNOWN_ACTION: | |
| 152 return UNKNOWN_ACTION; | |
| 153 default: | |
| 154 NOTREACHED(); | |
| 155 return UNKNOWN_ACTION; | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 // Returns true iff |message| is an initial GetUpdates request. | |
| 160 bool IsVeryFirstGetUpdates(const ClientToServerMessage& message) { | |
| 161 if (!message.has_get_updates()) | |
| 162 return false; | |
| 163 DCHECK_LT(0, message.get_updates().from_progress_marker_size()); | |
| 164 for (int i = 0; i < message.get_updates().from_progress_marker_size(); ++i) { | |
| 165 if (!message.get_updates().from_progress_marker(i).token().empty()) | |
| 166 return false; | |
| 167 } | |
| 168 return true; | |
| 169 } | |
| 170 | |
| 171 // Returns true iff |message| should contain a store birthday. | |
| 172 bool IsBirthdayRequired(const ClientToServerMessage& message) { | |
| 173 if (message.has_clear_server_data()) | |
| 174 return false; | |
| 175 if (message.has_commit()) | |
| 176 return true; | |
| 177 if (message.has_get_updates()) | |
| 178 return !IsVeryFirstGetUpdates(message); | |
| 179 NOTIMPLEMENTED(); | |
| 180 return true; | |
| 181 } | |
| 182 | |
| 183 SyncProtocolError ErrorCodeToSyncProtocolError( | |
| 184 const sync_pb::SyncEnums::ErrorType& error_type) { | |
| 185 SyncProtocolError error; | |
| 186 error.error_type = PBErrorTypeToSyncProtocolErrorType(error_type); | |
| 187 if (error_type == sync_pb::SyncEnums::CLEAR_PENDING || | |
| 188 error_type == sync_pb::SyncEnums::NOT_MY_BIRTHDAY) { | |
| 189 error.action = DISABLE_SYNC_ON_CLIENT; | |
| 190 } else if (error_type == sync_pb::SyncEnums::CLIENT_DATA_OBSOLETE) { | |
| 191 error.action = RESET_LOCAL_SYNC_DATA; | |
| 192 } else if (error_type == sync_pb::SyncEnums::DISABLED_BY_ADMIN) { | |
| 193 error.action = STOP_SYNC_FOR_DISABLED_ACCOUNT; | |
| 194 } // There is no other action we can compute for legacy server. | |
| 195 return error; | |
| 196 } | |
| 197 | |
| 198 } // namespace | |
| 199 | |
| 200 ModelTypeSet GetTypesToMigrate(const ClientToServerResponse& response) { | |
| 201 ModelTypeSet to_migrate; | |
| 202 for (int i = 0; i < response.migrated_data_type_id_size(); i++) { | |
| 203 int field_number = response.migrated_data_type_id(i); | |
| 204 ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number); | |
| 205 if (!IsRealDataType(model_type)) { | |
| 206 DLOG(WARNING) << "Unknown field number " << field_number; | |
| 207 continue; | |
| 208 } | |
| 209 to_migrate.Put(model_type); | |
| 210 } | |
| 211 return to_migrate; | |
| 212 } | |
| 213 | |
| 214 SyncProtocolError ConvertErrorPBToSyncProtocolError( | |
| 215 const sync_pb::ClientToServerResponse_Error& error) { | |
| 216 SyncProtocolError sync_protocol_error; | |
| 217 sync_protocol_error.error_type = | |
| 218 PBErrorTypeToSyncProtocolErrorType(error.error_type()); | |
| 219 sync_protocol_error.error_description = error.error_description(); | |
| 220 sync_protocol_error.url = error.url(); | |
| 221 sync_protocol_error.action = PBActionToClientAction(error.action()); | |
| 222 | |
| 223 if (error.error_data_type_ids_size() > 0) { | |
| 224 // THROTTLED and PARTIAL_FAILURE are currently the only error codes | |
| 225 // that uses |error_data_types|. | |
| 226 // In both cases, |error_data_types| are throttled. | |
| 227 for (int i = 0; i < error.error_data_type_ids_size(); ++i) { | |
| 228 int field_number = error.error_data_type_ids(i); | |
| 229 ModelType model_type = | |
| 230 GetModelTypeFromSpecificsFieldNumber(field_number); | |
| 231 if (!IsRealDataType(model_type)) { | |
| 232 DLOG(WARNING) << "Unknown field number " << field_number; | |
| 233 continue; | |
| 234 } | |
| 235 sync_protocol_error.error_data_types.Put(model_type); | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 return sync_protocol_error; | |
| 240 } | |
| 241 | |
| 242 // static | |
| 243 bool SyncerProtoUtil::VerifyResponseBirthday( | |
| 244 const ClientToServerResponse& response, | |
| 245 syncable::Directory* dir) { | |
| 246 | |
| 247 std::string local_birthday = dir->store_birthday(); | |
| 248 | |
| 249 if (local_birthday.empty()) { | |
| 250 if (!response.has_store_birthday()) { | |
| 251 LOG(WARNING) << "Expected a birthday on first sync."; | |
| 252 return false; | |
| 253 } | |
| 254 | |
| 255 DVLOG(1) << "New store birthday: " << response.store_birthday(); | |
| 256 dir->set_store_birthday(response.store_birthday()); | |
| 257 return true; | |
| 258 } | |
| 259 | |
| 260 // Error situation, but we're not stuck. | |
| 261 if (!response.has_store_birthday()) { | |
| 262 LOG(WARNING) << "No birthday in server response?"; | |
| 263 return true; | |
| 264 } | |
| 265 | |
| 266 if (response.store_birthday() != local_birthday) { | |
| 267 LOG(WARNING) << "Birthday changed, showing syncer stuck"; | |
| 268 return false; | |
| 269 } | |
| 270 | |
| 271 return true; | |
| 272 } | |
| 273 | |
| 274 // static | |
| 275 bool SyncerProtoUtil::IsSyncDisabledByAdmin( | |
| 276 const sync_pb::ClientToServerResponse& response) { | |
| 277 return (response.has_error_code() && | |
| 278 response.error_code() == sync_pb::SyncEnums::DISABLED_BY_ADMIN); | |
| 279 } | |
| 280 | |
| 281 // static | |
| 282 SyncProtocolError SyncerProtoUtil::GetProtocolErrorFromResponse( | |
| 283 const sync_pb::ClientToServerResponse& response, | |
| 284 syncable::Directory* dir) { | |
| 285 SyncProtocolError sync_protocol_error; | |
| 286 | |
| 287 // The DISABLED_BY_ADMIN error overrides other errors sent by the server. | |
| 288 if (IsSyncDisabledByAdmin(response)) { | |
| 289 sync_protocol_error.error_type = DISABLED_BY_ADMIN; | |
| 290 sync_protocol_error.action = STOP_SYNC_FOR_DISABLED_ACCOUNT; | |
| 291 } else if (!VerifyResponseBirthday(response, dir)) { | |
| 292 // If sync isn't disabled, first check for a birthday mismatch error. | |
| 293 if (response.error_code() == sync_pb::SyncEnums::CLIENT_DATA_OBSOLETE) { | |
| 294 // Server indicates that client needs to reset sync data. | |
| 295 sync_protocol_error.error_type = CLIENT_DATA_OBSOLETE; | |
| 296 sync_protocol_error.action = RESET_LOCAL_SYNC_DATA; | |
| 297 } else { | |
| 298 sync_protocol_error.error_type = NOT_MY_BIRTHDAY; | |
| 299 sync_protocol_error.action = DISABLE_SYNC_ON_CLIENT; | |
| 300 } | |
| 301 } else if (response.has_error()) { | |
| 302 // This is a new server. Just get the error from the protocol. | |
| 303 sync_protocol_error = ConvertErrorPBToSyncProtocolError(response.error()); | |
| 304 } else { | |
| 305 // Legacy server implementation. Compute the error based on |error_code|. | |
| 306 sync_protocol_error = ErrorCodeToSyncProtocolError(response.error_code()); | |
| 307 } | |
| 308 return sync_protocol_error; | |
| 309 } | |
| 310 | |
| 311 // static | |
| 312 void SyncerProtoUtil::AddRequestBirthday(syncable::Directory* dir, | |
| 313 ClientToServerMessage* msg) { | |
| 314 if (!dir->store_birthday().empty()) | |
| 315 msg->set_store_birthday(dir->store_birthday()); | |
| 316 } | |
| 317 | |
| 318 // static | |
| 319 void SyncerProtoUtil::AddBagOfChips(syncable::Directory* dir, | |
| 320 ClientToServerMessage* msg) { | |
| 321 msg->mutable_bag_of_chips()->ParseFromString(dir->bag_of_chips()); | |
| 322 } | |
| 323 | |
| 324 // static | |
| 325 void SyncerProtoUtil::SetProtocolVersion(ClientToServerMessage* msg) { | |
| 326 const int current_version = | |
| 327 ClientToServerMessage::default_instance().protocol_version(); | |
| 328 msg->set_protocol_version(current_version); | |
| 329 } | |
| 330 | |
| 331 // static | |
| 332 bool SyncerProtoUtil::PostAndProcessHeaders(ServerConnectionManager* scm, | |
| 333 sessions::SyncSession* session, | |
| 334 const ClientToServerMessage& msg, | |
| 335 ClientToServerResponse* response) { | |
| 336 ServerConnectionManager::PostBufferParams params; | |
| 337 DCHECK(msg.has_protocol_version()); | |
| 338 DCHECK_EQ(msg.protocol_version(), | |
| 339 ClientToServerMessage::default_instance().protocol_version()); | |
| 340 msg.SerializeToString(¶ms.buffer_in); | |
| 341 | |
| 342 // Fills in params.buffer_out and params.response. | |
| 343 if (!scm->PostBufferWithCachedAuth(¶ms)) { | |
| 344 LOG(WARNING) << "Error posting from syncer:" << params.response; | |
| 345 return false; | |
| 346 } | |
| 347 | |
| 348 return response->ParseFromString(params.buffer_out); | |
| 349 } | |
| 350 | |
| 351 base::TimeDelta SyncerProtoUtil::GetThrottleDelay( | |
| 352 const ClientToServerResponse& response) { | |
| 353 base::TimeDelta throttle_delay = | |
| 354 base::TimeDelta::FromSeconds(kSyncDelayAfterThrottled); | |
| 355 if (response.has_client_command()) { | |
| 356 const sync_pb::ClientCommand& command = response.client_command(); | |
| 357 if (command.has_throttle_delay_seconds()) { | |
| 358 throttle_delay = | |
| 359 base::TimeDelta::FromSeconds(command.throttle_delay_seconds()); | |
| 360 } | |
| 361 } | |
| 362 return throttle_delay; | |
| 363 } | |
| 364 | |
| 365 // static | |
| 366 SyncerError SyncerProtoUtil::PostClientToServerMessage( | |
| 367 ClientToServerMessage* msg, | |
| 368 ClientToServerResponse* response, | |
| 369 SyncSession* session, | |
| 370 ModelTypeSet* partial_failure_data_types) { | |
| 371 CHECK(response); | |
| 372 DCHECK(!msg->get_updates().has_from_timestamp()); // Deprecated. | |
| 373 DCHECK(!msg->get_updates().has_requested_types()); // Deprecated. | |
| 374 | |
| 375 // Add must-have fields. | |
| 376 SetProtocolVersion(msg); | |
| 377 AddRequestBirthday(session->context()->directory(), msg); | |
| 378 DCHECK(msg->has_store_birthday() || !IsBirthdayRequired(*msg)); | |
| 379 AddBagOfChips(session->context()->directory(), msg); | |
| 380 msg->set_api_key(google_apis::GetAPIKey()); | |
| 381 msg->mutable_client_status()->CopyFrom(session->context()->client_status()); | |
| 382 msg->set_invalidator_client_id(session->context()->invalidator_client_id()); | |
| 383 | |
| 384 syncable::Directory* dir = session->context()->directory(); | |
| 385 | |
| 386 LogClientToServerMessage(*msg); | |
| 387 if (!PostAndProcessHeaders(session->context()->connection_manager(), session, | |
| 388 *msg, response)) { | |
| 389 // There was an error establishing communication with the server. | |
| 390 // We can not proceed beyond this point. | |
| 391 const HttpResponse::ServerConnectionCode server_status = | |
| 392 session->context()->connection_manager()->server_status(); | |
| 393 | |
| 394 DCHECK_NE(server_status, HttpResponse::NONE); | |
| 395 DCHECK_NE(server_status, HttpResponse::SERVER_CONNECTION_OK); | |
| 396 | |
| 397 return ServerConnectionErrorAsSyncerError(server_status); | |
| 398 } | |
| 399 LogClientToServerResponse(*response); | |
| 400 | |
| 401 // Persist a bag of chips if it has been sent by the server. | |
| 402 PersistBagOfChips(dir, *response); | |
| 403 | |
| 404 SyncProtocolError sync_protocol_error = | |
| 405 GetProtocolErrorFromResponse(*response, dir); | |
| 406 | |
| 407 // Inform the delegate of the error we got. | |
| 408 session->delegate()->OnSyncProtocolError(sync_protocol_error); | |
| 409 | |
| 410 // Update our state for any other commands we've received. | |
| 411 if (response->has_client_command()) { | |
| 412 const sync_pb::ClientCommand& command = response->client_command(); | |
| 413 if (command.has_max_commit_batch_size()) { | |
| 414 session->context()->set_max_commit_batch_size( | |
| 415 command.max_commit_batch_size()); | |
| 416 } | |
| 417 | |
| 418 if (command.has_set_sync_long_poll_interval()) { | |
| 419 session->delegate()->OnReceivedLongPollIntervalUpdate( | |
| 420 base::TimeDelta::FromSeconds(command.set_sync_long_poll_interval())); | |
| 421 } | |
| 422 | |
| 423 if (command.has_set_sync_poll_interval()) { | |
| 424 session->delegate()->OnReceivedShortPollIntervalUpdate( | |
| 425 base::TimeDelta::FromSeconds(command.set_sync_poll_interval())); | |
| 426 } | |
| 427 | |
| 428 if (command.has_sessions_commit_delay_seconds()) { | |
| 429 std::map<ModelType, base::TimeDelta> delay_map; | |
| 430 delay_map[SESSIONS] = | |
| 431 base::TimeDelta::FromSeconds(command.sessions_commit_delay_seconds()); | |
| 432 session->delegate()->OnReceivedCustomNudgeDelays(delay_map); | |
| 433 } | |
| 434 | |
| 435 if (command.has_client_invalidation_hint_buffer_size()) { | |
| 436 session->delegate()->OnReceivedClientInvalidationHintBufferSize( | |
| 437 command.client_invalidation_hint_buffer_size()); | |
| 438 } | |
| 439 | |
| 440 if (command.has_gu_retry_delay_seconds()) { | |
| 441 session->delegate()->OnReceivedGuRetryDelay( | |
| 442 base::TimeDelta::FromSeconds(command.gu_retry_delay_seconds())); | |
| 443 } | |
| 444 | |
| 445 if (command.custom_nudge_delays_size() > 0) { | |
| 446 // Note that because this happens after the sessions_commit_delay_seconds | |
| 447 // handling, any SESSIONS value in this map will override the one in | |
| 448 // sessions_commit_delay_seconds. | |
| 449 std::map<ModelType, base::TimeDelta> delay_map; | |
| 450 for (int i = 0; i < command.custom_nudge_delays_size(); ++i) { | |
| 451 ModelType type = GetModelTypeFromSpecificsFieldNumber( | |
| 452 command.custom_nudge_delays(i).datatype_id()); | |
| 453 if (ProtocolTypes().Has(type)) { | |
| 454 delay_map[type] = base::TimeDelta::FromMilliseconds( | |
| 455 command.custom_nudge_delays(i).delay_ms()); | |
| 456 } | |
| 457 } | |
| 458 session->delegate()->OnReceivedCustomNudgeDelays(delay_map); | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 // Now do any special handling for the error type and decide on the return | |
| 463 // value. | |
| 464 switch (sync_protocol_error.error_type) { | |
| 465 case UNKNOWN_ERROR: | |
| 466 LOG(WARNING) << "Sync protocol out-of-date. The server is using a more " | |
| 467 << "recent version."; | |
| 468 return SERVER_RETURN_UNKNOWN_ERROR; | |
| 469 case SYNC_SUCCESS: | |
| 470 LogResponseProfilingData(*response); | |
| 471 return SYNCER_OK; | |
| 472 case THROTTLED: | |
| 473 if (sync_protocol_error.error_data_types.Empty()) { | |
| 474 DLOG(WARNING) << "Client fully throttled by syncer."; | |
| 475 session->delegate()->OnThrottled(GetThrottleDelay(*response)); | |
| 476 } else { | |
| 477 DLOG(WARNING) << "Some types throttled by syncer."; | |
| 478 session->delegate()->OnTypesThrottled( | |
| 479 sync_protocol_error.error_data_types, | |
| 480 GetThrottleDelay(*response)); | |
| 481 } | |
| 482 return SERVER_RETURN_THROTTLED; | |
| 483 case TRANSIENT_ERROR: | |
| 484 return SERVER_RETURN_TRANSIENT_ERROR; | |
| 485 case MIGRATION_DONE: | |
| 486 LOG_IF(ERROR, 0 >= response->migrated_data_type_id_size()) | |
| 487 << "MIGRATION_DONE but no types specified."; | |
| 488 session->delegate()->OnReceivedMigrationRequest( | |
| 489 GetTypesToMigrate(*response)); | |
| 490 return SERVER_RETURN_MIGRATION_DONE; | |
| 491 case CLEAR_PENDING: | |
| 492 return SERVER_RETURN_CLEAR_PENDING; | |
| 493 case NOT_MY_BIRTHDAY: | |
| 494 return SERVER_RETURN_NOT_MY_BIRTHDAY; | |
| 495 case DISABLED_BY_ADMIN: | |
| 496 return SERVER_RETURN_DISABLED_BY_ADMIN; | |
| 497 case PARTIAL_FAILURE: | |
| 498 // This only happens when partial throttling during GetUpdates. | |
| 499 if (!sync_protocol_error.error_data_types.Empty()) { | |
| 500 DLOG(WARNING) << "Some types throttled by syncer during GetUpdates."; | |
| 501 session->delegate()->OnTypesThrottled( | |
| 502 sync_protocol_error.error_data_types, GetThrottleDelay(*response)); | |
| 503 } | |
| 504 if (partial_failure_data_types != NULL) { | |
| 505 *partial_failure_data_types = sync_protocol_error.error_data_types; | |
| 506 } | |
| 507 return SERVER_RETURN_PARTIAL_FAILURE; | |
| 508 case CLIENT_DATA_OBSOLETE: | |
| 509 return SERVER_RETURN_CLIENT_DATA_OBSOLETE; | |
| 510 default: | |
| 511 NOTREACHED(); | |
| 512 return UNSET; | |
| 513 } | |
| 514 } | |
| 515 | |
| 516 // static | |
| 517 bool SyncerProtoUtil::ShouldMaintainPosition( | |
| 518 const sync_pb::SyncEntity& sync_entity) { | |
| 519 // Maintain positions for bookmarks that are not server-defined top-level | |
| 520 // folders. | |
| 521 return GetModelType(sync_entity) == BOOKMARKS | |
| 522 && !(sync_entity.folder() && | |
| 523 !sync_entity.server_defined_unique_tag().empty()); | |
| 524 } | |
| 525 | |
| 526 // static | |
| 527 bool SyncerProtoUtil::ShouldMaintainHierarchy( | |
| 528 const sync_pb::SyncEntity& sync_entity) { | |
| 529 // Maintain hierarchy for bookmarks or top-level items. | |
| 530 return GetModelType(sync_entity) == BOOKMARKS || | |
| 531 sync_entity.parent_id_string() == "0"; | |
| 532 } | |
| 533 | |
| 534 // static | |
| 535 const std::string& SyncerProtoUtil::NameFromSyncEntity( | |
| 536 const sync_pb::SyncEntity& entry) { | |
| 537 if (entry.has_non_unique_name()) | |
| 538 return entry.non_unique_name(); | |
| 539 return entry.name(); | |
| 540 } | |
| 541 | |
| 542 // static | |
| 543 const std::string& SyncerProtoUtil::NameFromCommitEntryResponse( | |
| 544 const sync_pb::CommitResponse_EntryResponse& entry) { | |
| 545 if (entry.has_non_unique_name()) | |
| 546 return entry.non_unique_name(); | |
| 547 return entry.name(); | |
| 548 } | |
| 549 | |
| 550 // static | |
| 551 void SyncerProtoUtil::PersistBagOfChips(syncable::Directory* dir, | |
| 552 const sync_pb::ClientToServerResponse& response) { | |
| 553 if (!response.has_new_bag_of_chips()) | |
| 554 return; | |
| 555 std::string bag_of_chips; | |
| 556 if (response.new_bag_of_chips().SerializeToString(&bag_of_chips)) | |
| 557 dir->set_bag_of_chips(bag_of_chips); | |
| 558 } | |
| 559 | |
| 560 std::string SyncerProtoUtil::SyncEntityDebugString( | |
| 561 const sync_pb::SyncEntity& entry) { | |
| 562 const std::string& mtime_str = | |
| 563 GetTimeDebugString(ProtoTimeToTime(entry.mtime())); | |
| 564 const std::string& ctime_str = | |
| 565 GetTimeDebugString(ProtoTimeToTime(entry.ctime())); | |
| 566 return base::StringPrintf( | |
| 567 "id: %s, parent_id: %s, " | |
| 568 "version: %" PRId64"d, " | |
| 569 "mtime: %" PRId64"d (%s), " | |
| 570 "ctime: %" PRId64"d (%s), " | |
| 571 "name: %s, sync_timestamp: %" PRId64"d, " | |
| 572 "%s ", | |
| 573 entry.id_string().c_str(), | |
| 574 entry.parent_id_string().c_str(), | |
| 575 entry.version(), | |
| 576 entry.mtime(), mtime_str.c_str(), | |
| 577 entry.ctime(), ctime_str.c_str(), | |
| 578 entry.name().c_str(), entry.sync_timestamp(), | |
| 579 entry.deleted() ? "deleted, ":""); | |
| 580 } | |
| 581 | |
| 582 namespace { | |
| 583 std::string GetUpdatesResponseString( | |
| 584 const sync_pb::GetUpdatesResponse& response) { | |
| 585 std::string output; | |
| 586 output.append("GetUpdatesResponse:\n"); | |
| 587 for (int i = 0; i < response.entries_size(); i++) { | |
| 588 output.append(SyncerProtoUtil::SyncEntityDebugString(response.entries(i))); | |
| 589 output.append("\n"); | |
| 590 } | |
| 591 return output; | |
| 592 } | |
| 593 } // namespace | |
| 594 | |
| 595 std::string SyncerProtoUtil::ClientToServerResponseDebugString( | |
| 596 const ClientToServerResponse& response) { | |
| 597 // Add more handlers as needed. | |
| 598 std::string output; | |
| 599 if (response.has_get_updates()) | |
| 600 output.append(GetUpdatesResponseString(response.get_updates())); | |
| 601 return output; | |
| 602 } | |
| 603 | |
| 604 } // namespace syncer | |
| OLD | NEW |