| 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 "chrome/browser/sync/engine/syncer_proto_util.h" | |
| 6 | |
| 7 #include "base/format_macros.h" | |
| 8 #include "base/stringprintf.h" | |
| 9 #include "chrome/browser/sync/engine/net/server_connection_manager.h" | |
| 10 #include "chrome/browser/sync/engine/syncer.h" | |
| 11 #include "chrome/browser/sync/engine/syncer_types.h" | |
| 12 #include "chrome/browser/sync/protocol/service_constants.h" | |
| 13 #include "chrome/browser/sync/protocol/sync_protocol_error.h" | |
| 14 #include "chrome/browser/sync/sessions/sync_session.h" | |
| 15 #include "chrome/browser/sync/syncable/model_type.h" | |
| 16 #include "chrome/browser/sync/syncable/syncable-inl.h" | |
| 17 #include "chrome/browser/sync/syncable/syncable.h" | |
| 18 #include "chrome/browser/sync/util/time.h" | |
| 19 #include "sync/protocol/sync.pb.h" | |
| 20 #include "sync/protocol/sync_enums.pb.h" | |
| 21 | |
| 22 using browser_sync::SyncProtocolErrorType; | |
| 23 using std::string; | |
| 24 using std::stringstream; | |
| 25 using syncable::BASE_VERSION; | |
| 26 using syncable::CTIME; | |
| 27 using syncable::ID; | |
| 28 using syncable::IS_DEL; | |
| 29 using syncable::IS_DIR; | |
| 30 using syncable::IS_UNSYNCED; | |
| 31 using syncable::MTIME; | |
| 32 using syncable::PARENT_ID; | |
| 33 | |
| 34 namespace browser_sync { | |
| 35 using sessions::SyncSession; | |
| 36 | |
| 37 namespace { | |
| 38 | |
| 39 // Time to backoff syncing after receiving a throttled response. | |
| 40 const int kSyncDelayAfterThrottled = 2 * 60 * 60; // 2 hours | |
| 41 | |
| 42 void LogResponseProfilingData(const ClientToServerResponse& response) { | |
| 43 if (response.has_profiling_data()) { | |
| 44 stringstream response_trace; | |
| 45 response_trace << "Server response trace:"; | |
| 46 | |
| 47 if (response.profiling_data().has_user_lookup_time()) { | |
| 48 response_trace << " user lookup: " | |
| 49 << response.profiling_data().user_lookup_time() << "ms"; | |
| 50 } | |
| 51 | |
| 52 if (response.profiling_data().has_meta_data_write_time()) { | |
| 53 response_trace << " meta write: " | |
| 54 << response.profiling_data().meta_data_write_time() | |
| 55 << "ms"; | |
| 56 } | |
| 57 | |
| 58 if (response.profiling_data().has_meta_data_read_time()) { | |
| 59 response_trace << " meta read: " | |
| 60 << response.profiling_data().meta_data_read_time() << "ms"; | |
| 61 } | |
| 62 | |
| 63 if (response.profiling_data().has_file_data_write_time()) { | |
| 64 response_trace << " file write: " | |
| 65 << response.profiling_data().file_data_write_time() | |
| 66 << "ms"; | |
| 67 } | |
| 68 | |
| 69 if (response.profiling_data().has_file_data_read_time()) { | |
| 70 response_trace << " file read: " | |
| 71 << response.profiling_data().file_data_read_time() << "ms"; | |
| 72 } | |
| 73 | |
| 74 if (response.profiling_data().has_total_request_time()) { | |
| 75 response_trace << " total time: " | |
| 76 << response.profiling_data().total_request_time() << "ms"; | |
| 77 } | |
| 78 DVLOG(1) << response_trace.str(); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 SyncerError ServerConnectionErrorAsSyncerError( | |
| 83 const HttpResponse::ServerConnectionCode server_status) { | |
| 84 switch (server_status) { | |
| 85 case HttpResponse::CONNECTION_UNAVAILABLE: | |
| 86 return NETWORK_CONNECTION_UNAVAILABLE; | |
| 87 case HttpResponse::IO_ERROR: | |
| 88 return NETWORK_IO_ERROR; | |
| 89 case HttpResponse::SYNC_SERVER_ERROR: | |
| 90 // FIXME what does this mean? | |
| 91 return SYNC_SERVER_ERROR; | |
| 92 case HttpResponse::SYNC_AUTH_ERROR: | |
| 93 return SYNC_AUTH_ERROR; | |
| 94 case HttpResponse::RETRY: | |
| 95 return SERVER_RETURN_TRANSIENT_ERROR; | |
| 96 case HttpResponse::SERVER_CONNECTION_OK: | |
| 97 case HttpResponse::NONE: | |
| 98 default: | |
| 99 NOTREACHED(); | |
| 100 return UNSET; | |
| 101 } | |
| 102 } | |
| 103 | |
| 104 } // namespace | |
| 105 | |
| 106 // static | |
| 107 void SyncerProtoUtil::HandleMigrationDoneResponse( | |
| 108 const sync_pb::ClientToServerResponse* response, | |
| 109 sessions::SyncSession* session) { | |
| 110 LOG_IF(ERROR, 0 >= response->migrated_data_type_id_size()) | |
| 111 << "MIGRATION_DONE but no types specified."; | |
| 112 syncable::ModelTypeSet to_migrate; | |
| 113 for (int i = 0; i < response->migrated_data_type_id_size(); i++) { | |
| 114 to_migrate.Put(syncable::GetModelTypeFromSpecificsFieldNumber( | |
| 115 response->migrated_data_type_id(i))); | |
| 116 } | |
| 117 // TODO(akalin): This should be a set union. | |
| 118 session->mutable_status_controller()-> | |
| 119 set_types_needing_local_migration(to_migrate); | |
| 120 } | |
| 121 | |
| 122 // static | |
| 123 bool SyncerProtoUtil::VerifyResponseBirthday(syncable::Directory* dir, | |
| 124 const ClientToServerResponse* response) { | |
| 125 | |
| 126 std::string local_birthday = dir->store_birthday(); | |
| 127 | |
| 128 if (local_birthday.empty()) { | |
| 129 if (!response->has_store_birthday()) { | |
| 130 LOG(WARNING) << "Expected a birthday on first sync."; | |
| 131 return false; | |
| 132 } | |
| 133 | |
| 134 DVLOG(1) << "New store birthday: " << response->store_birthday(); | |
| 135 dir->set_store_birthday(response->store_birthday()); | |
| 136 return true; | |
| 137 } | |
| 138 | |
| 139 // Error situation, but we're not stuck. | |
| 140 if (!response->has_store_birthday()) { | |
| 141 LOG(WARNING) << "No birthday in server response?"; | |
| 142 return true; | |
| 143 } | |
| 144 | |
| 145 if (response->store_birthday() != local_birthday) { | |
| 146 LOG(WARNING) << "Birthday changed, showing syncer stuck"; | |
| 147 return false; | |
| 148 } | |
| 149 | |
| 150 return true; | |
| 151 } | |
| 152 | |
| 153 // static | |
| 154 void SyncerProtoUtil::AddRequestBirthday(syncable::Directory* dir, | |
| 155 ClientToServerMessage* msg) { | |
| 156 if (!dir->store_birthday().empty()) | |
| 157 msg->set_store_birthday(dir->store_birthday()); | |
| 158 } | |
| 159 | |
| 160 // static | |
| 161 bool SyncerProtoUtil::PostAndProcessHeaders(ServerConnectionManager* scm, | |
| 162 sessions::SyncSession* session, | |
| 163 const ClientToServerMessage& msg, | |
| 164 ClientToServerResponse* response) { | |
| 165 ServerConnectionManager::PostBufferParams params; | |
| 166 msg.SerializeToString(¶ms.buffer_in); | |
| 167 | |
| 168 ScopedServerStatusWatcher server_status_watcher(scm, ¶ms.response); | |
| 169 // Fills in params.buffer_out and params.response. | |
| 170 if (!scm->PostBufferWithCachedAuth(¶ms, &server_status_watcher)) { | |
| 171 LOG(WARNING) << "Error posting from syncer:" << params.response; | |
| 172 return false; | |
| 173 } | |
| 174 | |
| 175 std::string new_token = params.response.update_client_auth_header; | |
| 176 if (!new_token.empty()) { | |
| 177 SyncEngineEvent event(SyncEngineEvent::UPDATED_TOKEN); | |
| 178 event.updated_token = new_token; | |
| 179 session->context()->NotifyListeners(event); | |
| 180 } | |
| 181 | |
| 182 if (response->ParseFromString(params.buffer_out)) { | |
| 183 // TODO(tim): This is an egregious layering violation (bug 35060). | |
| 184 switch (response->error_code()) { | |
| 185 case sync_pb::SyncEnums::ACCESS_DENIED: | |
| 186 case sync_pb::SyncEnums::AUTH_INVALID: | |
| 187 case sync_pb::SyncEnums::USER_NOT_ACTIVATED: | |
| 188 // Fires on ScopedServerStatusWatcher | |
| 189 params.response.server_status = HttpResponse::SYNC_AUTH_ERROR; | |
| 190 return false; | |
| 191 default: | |
| 192 return true; | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 return false; | |
| 197 } | |
| 198 | |
| 199 base::TimeDelta SyncerProtoUtil::GetThrottleDelay( | |
| 200 const sync_pb::ClientToServerResponse& response) { | |
| 201 base::TimeDelta throttle_delay = | |
| 202 base::TimeDelta::FromSeconds(kSyncDelayAfterThrottled); | |
| 203 if (response.has_client_command()) { | |
| 204 const sync_pb::ClientCommand& command = response.client_command(); | |
| 205 if (command.has_throttle_delay_seconds()) { | |
| 206 throttle_delay = | |
| 207 base::TimeDelta::FromSeconds(command.throttle_delay_seconds()); | |
| 208 } | |
| 209 } | |
| 210 return throttle_delay; | |
| 211 } | |
| 212 | |
| 213 void SyncerProtoUtil::HandleThrottleError( | |
| 214 const SyncProtocolError& error, | |
| 215 const base::TimeTicks& throttled_until, | |
| 216 sessions::SyncSessionContext* context, | |
| 217 sessions::SyncSession::Delegate* delegate) { | |
| 218 DCHECK_EQ(error.error_type, browser_sync::THROTTLED); | |
| 219 if (error.error_data_types.Empty()) { | |
| 220 // No datatypes indicates the client should be completely throttled. | |
| 221 delegate->OnSilencedUntil(throttled_until); | |
| 222 } else { | |
| 223 context->SetUnthrottleTime(error.error_data_types, throttled_until); | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 namespace { | |
| 228 | |
| 229 // Helper function for an assertion in PostClientToServerMessage. | |
| 230 bool IsVeryFirstGetUpdates(const ClientToServerMessage& message) { | |
| 231 if (!message.has_get_updates()) | |
| 232 return false; | |
| 233 DCHECK_LT(0, message.get_updates().from_progress_marker_size()); | |
| 234 for (int i = 0; i < message.get_updates().from_progress_marker_size(); ++i) { | |
| 235 if (!message.get_updates().from_progress_marker(i).token().empty()) | |
| 236 return false; | |
| 237 } | |
| 238 return true; | |
| 239 } | |
| 240 | |
| 241 SyncProtocolErrorType ConvertSyncProtocolErrorTypePBToLocalType( | |
| 242 const sync_pb::SyncEnums::ErrorType& error_type) { | |
| 243 switch (error_type) { | |
| 244 case sync_pb::SyncEnums::SUCCESS: | |
| 245 return browser_sync::SYNC_SUCCESS; | |
| 246 case sync_pb::SyncEnums::NOT_MY_BIRTHDAY: | |
| 247 return browser_sync::NOT_MY_BIRTHDAY; | |
| 248 case sync_pb::SyncEnums::THROTTLED: | |
| 249 return browser_sync::THROTTLED; | |
| 250 case sync_pb::SyncEnums::CLEAR_PENDING: | |
| 251 return browser_sync::CLEAR_PENDING; | |
| 252 case sync_pb::SyncEnums::TRANSIENT_ERROR: | |
| 253 return browser_sync::TRANSIENT_ERROR; | |
| 254 case sync_pb::SyncEnums::MIGRATION_DONE: | |
| 255 return browser_sync::MIGRATION_DONE; | |
| 256 case sync_pb::SyncEnums::UNKNOWN: | |
| 257 return browser_sync::UNKNOWN_ERROR; | |
| 258 case sync_pb::SyncEnums::USER_NOT_ACTIVATED: | |
| 259 case sync_pb::SyncEnums::AUTH_INVALID: | |
| 260 case sync_pb::SyncEnums::ACCESS_DENIED: | |
| 261 return browser_sync::INVALID_CREDENTIAL; | |
| 262 default: | |
| 263 NOTREACHED(); | |
| 264 return browser_sync::UNKNOWN_ERROR; | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 browser_sync::ClientAction ConvertClientActionPBToLocalClientAction( | |
| 269 const sync_pb::ClientToServerResponse::Error::Action& action) { | |
| 270 switch (action) { | |
| 271 case ClientToServerResponse::Error::UPGRADE_CLIENT: | |
| 272 return browser_sync::UPGRADE_CLIENT; | |
| 273 case ClientToServerResponse::Error::CLEAR_USER_DATA_AND_RESYNC: | |
| 274 return browser_sync::CLEAR_USER_DATA_AND_RESYNC; | |
| 275 case ClientToServerResponse::Error::ENABLE_SYNC_ON_ACCOUNT: | |
| 276 return browser_sync::ENABLE_SYNC_ON_ACCOUNT; | |
| 277 case ClientToServerResponse::Error::STOP_AND_RESTART_SYNC: | |
| 278 return browser_sync::STOP_AND_RESTART_SYNC; | |
| 279 case ClientToServerResponse::Error::DISABLE_SYNC_ON_CLIENT: | |
| 280 return browser_sync::DISABLE_SYNC_ON_CLIENT; | |
| 281 case ClientToServerResponse::Error::UNKNOWN_ACTION: | |
| 282 return browser_sync::UNKNOWN_ACTION; | |
| 283 default: | |
| 284 NOTREACHED(); | |
| 285 return browser_sync::UNKNOWN_ACTION; | |
| 286 } | |
| 287 } | |
| 288 | |
| 289 browser_sync::SyncProtocolError ConvertErrorPBToLocalType( | |
| 290 const sync_pb::ClientToServerResponse::Error& error) { | |
| 291 browser_sync::SyncProtocolError sync_protocol_error; | |
| 292 sync_protocol_error.error_type = ConvertSyncProtocolErrorTypePBToLocalType( | |
| 293 error.error_type()); | |
| 294 sync_protocol_error.error_description = error.error_description(); | |
| 295 sync_protocol_error.url = error.url(); | |
| 296 sync_protocol_error.action = ConvertClientActionPBToLocalClientAction( | |
| 297 error.action()); | |
| 298 | |
| 299 if (error.error_data_type_ids_size() > 0) { | |
| 300 // THROTTLED is currently the only error code that uses |error_data_types|. | |
| 301 DCHECK_EQ(error.error_type(), sync_pb::SyncEnums::THROTTLED); | |
| 302 for (int i = 0; i < error.error_data_type_ids_size(); ++i) { | |
| 303 sync_protocol_error.error_data_types.Put( | |
| 304 syncable::GetModelTypeFromSpecificsFieldNumber( | |
| 305 error.error_data_type_ids(i))); | |
| 306 } | |
| 307 } | |
| 308 | |
| 309 return sync_protocol_error; | |
| 310 } | |
| 311 | |
| 312 // TODO(lipalani) : Rename these function names as per the CR for issue 7740067. | |
| 313 browser_sync::SyncProtocolError ConvertLegacyErrorCodeToNewError( | |
| 314 const sync_pb::SyncEnums::ErrorType& error_type) { | |
| 315 browser_sync::SyncProtocolError error; | |
| 316 error.error_type = ConvertSyncProtocolErrorTypePBToLocalType(error_type); | |
| 317 if (error_type == sync_pb::SyncEnums::CLEAR_PENDING || | |
| 318 error_type == sync_pb::SyncEnums::NOT_MY_BIRTHDAY) { | |
| 319 error.action = browser_sync::DISABLE_SYNC_ON_CLIENT; | |
| 320 } // There is no other action we can compute for legacy server. | |
| 321 return error; | |
| 322 } | |
| 323 | |
| 324 } // namespace | |
| 325 | |
| 326 // static | |
| 327 SyncerError SyncerProtoUtil::PostClientToServerMessage( | |
| 328 const ClientToServerMessage& msg, | |
| 329 ClientToServerResponse* response, | |
| 330 SyncSession* session) { | |
| 331 | |
| 332 CHECK(response); | |
| 333 DCHECK(!msg.get_updates().has_from_timestamp()); // Deprecated. | |
| 334 DCHECK(!msg.get_updates().has_requested_types()); // Deprecated. | |
| 335 DCHECK(msg.has_store_birthday() || IsVeryFirstGetUpdates(msg)) | |
| 336 << "Must call AddRequestBirthday to set birthday."; | |
| 337 | |
| 338 syncable::Directory* dir = session->context()->directory(); | |
| 339 | |
| 340 if (!PostAndProcessHeaders(session->context()->connection_manager(), session, | |
| 341 msg, response)) { | |
| 342 // There was an error establishing communication with the server. | |
| 343 // We can not proceed beyond this point. | |
| 344 const browser_sync::HttpResponse::ServerConnectionCode server_status = | |
| 345 session->context()->connection_manager()->server_status(); | |
| 346 | |
| 347 DCHECK_NE(server_status, browser_sync::HttpResponse::NONE); | |
| 348 DCHECK_NE(server_status, browser_sync::HttpResponse::SERVER_CONNECTION_OK); | |
| 349 | |
| 350 return ServerConnectionErrorAsSyncerError(server_status); | |
| 351 } | |
| 352 | |
| 353 browser_sync::SyncProtocolError sync_protocol_error; | |
| 354 | |
| 355 // Birthday mismatch overrides any error that is sent by the server. | |
| 356 if (!VerifyResponseBirthday(dir, response)) { | |
| 357 sync_protocol_error.error_type = browser_sync::NOT_MY_BIRTHDAY; | |
| 358 sync_protocol_error.action = | |
| 359 browser_sync::DISABLE_SYNC_ON_CLIENT; | |
| 360 } else if (response->has_error()) { | |
| 361 // This is a new server. Just get the error from the protocol. | |
| 362 sync_protocol_error = ConvertErrorPBToLocalType(response->error()); | |
| 363 } else { | |
| 364 // Legacy server implementation. Compute the error based on |error_code|. | |
| 365 sync_protocol_error = ConvertLegacyErrorCodeToNewError( | |
| 366 response->error_code()); | |
| 367 } | |
| 368 | |
| 369 // Now set the error into the status so the layers above us could read it. | |
| 370 sessions::StatusController* status = session->mutable_status_controller(); | |
| 371 status->set_sync_protocol_error(sync_protocol_error); | |
| 372 | |
| 373 // Inform the delegate of the error we got. | |
| 374 session->delegate()->OnSyncProtocolError(session->TakeSnapshot()); | |
| 375 | |
| 376 // Now do any special handling for the error type and decide on the return | |
| 377 // value. | |
| 378 switch (sync_protocol_error.error_type) { | |
| 379 case browser_sync::UNKNOWN_ERROR: | |
| 380 LOG(WARNING) << "Sync protocol out-of-date. The server is using a more " | |
| 381 << "recent version."; | |
| 382 return SERVER_RETURN_UNKNOWN_ERROR; | |
| 383 case browser_sync::SYNC_SUCCESS: | |
| 384 LogResponseProfilingData(*response); | |
| 385 return SYNCER_OK; | |
| 386 case browser_sync::THROTTLED: | |
| 387 LOG(WARNING) << "Client silenced by server."; | |
| 388 HandleThrottleError(sync_protocol_error, | |
| 389 base::TimeTicks::Now() + GetThrottleDelay(*response), | |
| 390 session->context(), | |
| 391 session->delegate()); | |
| 392 return SERVER_RETURN_THROTTLED; | |
| 393 case browser_sync::TRANSIENT_ERROR: | |
| 394 return SERVER_RETURN_TRANSIENT_ERROR; | |
| 395 case browser_sync::MIGRATION_DONE: | |
| 396 HandleMigrationDoneResponse(response, session); | |
| 397 return SERVER_RETURN_MIGRATION_DONE; | |
| 398 case browser_sync::CLEAR_PENDING: | |
| 399 return SERVER_RETURN_CLEAR_PENDING; | |
| 400 case browser_sync::NOT_MY_BIRTHDAY: | |
| 401 return SERVER_RETURN_NOT_MY_BIRTHDAY; | |
| 402 default: | |
| 403 NOTREACHED(); | |
| 404 return UNSET; | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 // static | |
| 409 bool SyncerProtoUtil::Compare(const syncable::Entry& local_entry, | |
| 410 const SyncEntity& server_entry) { | |
| 411 const std::string name = NameFromSyncEntity(server_entry); | |
| 412 | |
| 413 CHECK(local_entry.Get(ID) == server_entry.id()) << | |
| 414 " SyncerProtoUtil::Compare precondition not met."; | |
| 415 CHECK(server_entry.version() == local_entry.Get(BASE_VERSION)) << | |
| 416 " SyncerProtoUtil::Compare precondition not met."; | |
| 417 CHECK(!local_entry.Get(IS_UNSYNCED)) << | |
| 418 " SyncerProtoUtil::Compare precondition not met."; | |
| 419 | |
| 420 if (local_entry.Get(IS_DEL) && server_entry.deleted()) | |
| 421 return true; | |
| 422 if (local_entry.Get(CTIME) != ProtoTimeToTime(server_entry.ctime())) { | |
| 423 LOG(WARNING) << "ctime mismatch"; | |
| 424 return false; | |
| 425 } | |
| 426 | |
| 427 // These checks are somewhat prolix, but they're easier to debug than a big | |
| 428 // boolean statement. | |
| 429 string client_name = local_entry.Get(syncable::NON_UNIQUE_NAME); | |
| 430 if (client_name != name) { | |
| 431 LOG(WARNING) << "Client name mismatch"; | |
| 432 return false; | |
| 433 } | |
| 434 if (local_entry.Get(PARENT_ID) != server_entry.parent_id()) { | |
| 435 LOG(WARNING) << "Parent ID mismatch"; | |
| 436 return false; | |
| 437 } | |
| 438 if (local_entry.Get(IS_DIR) != server_entry.IsFolder()) { | |
| 439 LOG(WARNING) << "Dir field mismatch"; | |
| 440 return false; | |
| 441 } | |
| 442 if (local_entry.Get(IS_DEL) != server_entry.deleted()) { | |
| 443 LOG(WARNING) << "Deletion mismatch"; | |
| 444 return false; | |
| 445 } | |
| 446 if (!local_entry.Get(IS_DIR) && | |
| 447 (local_entry.Get(MTIME) != ProtoTimeToTime(server_entry.mtime()))) { | |
| 448 LOG(WARNING) << "mtime mismatch"; | |
| 449 return false; | |
| 450 } | |
| 451 | |
| 452 return true; | |
| 453 } | |
| 454 | |
| 455 // static | |
| 456 void SyncerProtoUtil::CopyProtoBytesIntoBlob(const std::string& proto_bytes, | |
| 457 syncable::Blob* blob) { | |
| 458 syncable::Blob proto_blob(proto_bytes.begin(), proto_bytes.end()); | |
| 459 blob->swap(proto_blob); | |
| 460 } | |
| 461 | |
| 462 // static | |
| 463 bool SyncerProtoUtil::ProtoBytesEqualsBlob(const std::string& proto_bytes, | |
| 464 const syncable::Blob& blob) { | |
| 465 if (proto_bytes.size() != blob.size()) | |
| 466 return false; | |
| 467 return std::equal(proto_bytes.begin(), proto_bytes.end(), blob.begin()); | |
| 468 } | |
| 469 | |
| 470 // static | |
| 471 void SyncerProtoUtil::CopyBlobIntoProtoBytes(const syncable::Blob& blob, | |
| 472 std::string* proto_bytes) { | |
| 473 std::string blob_string(blob.begin(), blob.end()); | |
| 474 proto_bytes->swap(blob_string); | |
| 475 } | |
| 476 | |
| 477 // static | |
| 478 const std::string& SyncerProtoUtil::NameFromSyncEntity( | |
| 479 const sync_pb::SyncEntity& entry) { | |
| 480 if (entry.has_non_unique_name()) | |
| 481 return entry.non_unique_name(); | |
| 482 return entry.name(); | |
| 483 } | |
| 484 | |
| 485 // static | |
| 486 const std::string& SyncerProtoUtil::NameFromCommitEntryResponse( | |
| 487 const CommitResponse_EntryResponse& entry) { | |
| 488 if (entry.has_non_unique_name()) | |
| 489 return entry.non_unique_name(); | |
| 490 return entry.name(); | |
| 491 } | |
| 492 | |
| 493 std::string SyncerProtoUtil::SyncEntityDebugString( | |
| 494 const sync_pb::SyncEntity& entry) { | |
| 495 const std::string& mtime_str = | |
| 496 GetTimeDebugString(ProtoTimeToTime(entry.mtime())); | |
| 497 const std::string& ctime_str = | |
| 498 GetTimeDebugString(ProtoTimeToTime(entry.ctime())); | |
| 499 return base::StringPrintf( | |
| 500 "id: %s, parent_id: %s, " | |
| 501 "version: %"PRId64"d, " | |
| 502 "mtime: %" PRId64"d (%s), " | |
| 503 "ctime: %" PRId64"d (%s), " | |
| 504 "name: %s, sync_timestamp: %" PRId64"d, " | |
| 505 "%s ", | |
| 506 entry.id_string().c_str(), | |
| 507 entry.parent_id_string().c_str(), | |
| 508 entry.version(), | |
| 509 entry.mtime(), mtime_str.c_str(), | |
| 510 entry.ctime(), ctime_str.c_str(), | |
| 511 entry.name().c_str(), entry.sync_timestamp(), | |
| 512 entry.deleted() ? "deleted, ":""); | |
| 513 } | |
| 514 | |
| 515 namespace { | |
| 516 std::string GetUpdatesResponseString( | |
| 517 const sync_pb::GetUpdatesResponse& response) { | |
| 518 std::string output; | |
| 519 output.append("GetUpdatesResponse:\n"); | |
| 520 for (int i = 0; i < response.entries_size(); i++) { | |
| 521 output.append(SyncerProtoUtil::SyncEntityDebugString(response.entries(i))); | |
| 522 output.append("\n"); | |
| 523 } | |
| 524 return output; | |
| 525 } | |
| 526 } // namespace | |
| 527 | |
| 528 std::string SyncerProtoUtil::ClientToServerResponseDebugString( | |
| 529 const sync_pb::ClientToServerResponse& response) { | |
| 530 // Add more handlers as needed. | |
| 531 std::string output; | |
| 532 if (response.has_get_updates()) | |
| 533 output.append(GetUpdatesResponseString(response.get_updates())); | |
| 534 return output; | |
| 535 } | |
| 536 | |
| 537 } // namespace browser_sync | |
| OLD | NEW |