syncer_proto_util.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  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. #include "components/sync/engine/syncer_proto_util.h"
  5. #include <map>
  6. #include "base/format_macros.h"
  7. #include "base/logging.h"
  8. #include "base/metrics/histogram_functions.h"
  9. #include "base/metrics/histogram_macros.h"
  10. #include "base/strings/stringprintf.h"
  11. #include "base/time/time.h"
  12. #include "components/sync/base/model_type.h"
  13. #include "components/sync/base/time.h"
  14. #include "components/sync/engine/cycle/sync_cycle_context.h"
  15. #include "components/sync/engine/net/server_connection_manager.h"
  16. #include "components/sync/engine/syncer.h"
  17. #include "components/sync/engine/traffic_logger.h"
  18. #include "components/sync/protocol/data_type_progress_marker.pb.h"
  19. #include "components/sync/protocol/sync_enums.pb.h"
  20. #include "components/sync/protocol/sync_protocol_error.h"
  21. #include "google_apis/google_api_keys.h"
  22. #include "third_party/abseil-cpp/absl/types/optional.h"
  23. using std::string;
  24. using std::stringstream;
  25. using sync_pb::ClientToServerMessage;
  26. using sync_pb::ClientToServerResponse;
  27. namespace syncer {
  28. namespace {
  29. // Time to backoff syncing after receiving a throttled response.
  30. constexpr base::TimeDelta kSyncDelayAfterThrottled = base::Hours(2);
  31. SyncerError ServerConnectionErrorAsSyncerError(
  32. const HttpResponse::ServerConnectionCode server_status,
  33. int net_error_code,
  34. int http_status_code) {
  35. switch (server_status) {
  36. case HttpResponse::CONNECTION_UNAVAILABLE:
  37. return SyncerError::NetworkConnectionUnavailable(net_error_code);
  38. case HttpResponse::IO_ERROR:
  39. return SyncerError(SyncerError::NETWORK_IO_ERROR);
  40. case HttpResponse::SYNC_SERVER_ERROR:
  41. // This means the server returned a non-401 HTTP error.
  42. return SyncerError::HttpError(http_status_code);
  43. case HttpResponse::SYNC_AUTH_ERROR:
  44. // This means the server returned an HTTP 401 (unauthorized) error.
  45. return SyncerError::HttpError(http_status_code);
  46. case HttpResponse::SERVER_CONNECTION_OK:
  47. case HttpResponse::NONE:
  48. default:
  49. NOTREACHED();
  50. return SyncerError();
  51. }
  52. }
  53. SyncProtocolErrorType PBErrorTypeToSyncProtocolErrorType(
  54. const sync_pb::SyncEnums::ErrorType& error_type) {
  55. switch (error_type) {
  56. case sync_pb::SyncEnums::SUCCESS:
  57. return SYNC_SUCCESS;
  58. case sync_pb::SyncEnums::NOT_MY_BIRTHDAY:
  59. return NOT_MY_BIRTHDAY;
  60. case sync_pb::SyncEnums::THROTTLED:
  61. return THROTTLED;
  62. case sync_pb::SyncEnums::CLEAR_PENDING:
  63. return CLEAR_PENDING;
  64. case sync_pb::SyncEnums::TRANSIENT_ERROR:
  65. return TRANSIENT_ERROR;
  66. case sync_pb::SyncEnums::MIGRATION_DONE:
  67. return MIGRATION_DONE;
  68. case sync_pb::SyncEnums::DISABLED_BY_ADMIN:
  69. return DISABLED_BY_ADMIN;
  70. case sync_pb::SyncEnums::PARTIAL_FAILURE:
  71. return PARTIAL_FAILURE;
  72. case sync_pb::SyncEnums::CLIENT_DATA_OBSOLETE:
  73. return CLIENT_DATA_OBSOLETE;
  74. case sync_pb::SyncEnums::UNKNOWN:
  75. return UNKNOWN_ERROR;
  76. case sync_pb::SyncEnums::ENCRYPTION_OBSOLETE:
  77. return ENCRYPTION_OBSOLETE;
  78. }
  79. NOTREACHED();
  80. return UNKNOWN_ERROR;
  81. }
  82. ClientAction PBActionToClientAction(const sync_pb::SyncEnums::Action& action) {
  83. switch (action) {
  84. case sync_pb::SyncEnums::UPGRADE_CLIENT:
  85. return UPGRADE_CLIENT;
  86. case sync_pb::SyncEnums::UNKNOWN_ACTION:
  87. return UNKNOWN_ACTION;
  88. }
  89. NOTREACHED();
  90. return UNKNOWN_ACTION;
  91. }
  92. // Returns true iff |message| is an initial GetUpdates request.
  93. bool IsVeryFirstGetUpdates(const ClientToServerMessage& message) {
  94. if (!message.has_get_updates())
  95. return false;
  96. DCHECK_LT(0, message.get_updates().from_progress_marker_size());
  97. for (int i = 0; i < message.get_updates().from_progress_marker_size(); ++i) {
  98. if (!message.get_updates().from_progress_marker(i).token().empty())
  99. return false;
  100. }
  101. return true;
  102. }
  103. // Returns true iff |message| should contain a store birthday.
  104. bool IsBirthdayRequired(const ClientToServerMessage& message) {
  105. if (message.has_clear_server_data())
  106. return false;
  107. if (message.has_commit())
  108. return true;
  109. if (message.has_get_updates())
  110. return !IsVeryFirstGetUpdates(message);
  111. NOTIMPLEMENTED();
  112. return true;
  113. }
  114. SyncProtocolError ErrorCodeToSyncProtocolError(
  115. const sync_pb::SyncEnums::ErrorType& error_type) {
  116. SyncProtocolError error;
  117. error.error_type = PBErrorTypeToSyncProtocolErrorType(error_type);
  118. if (error_type == sync_pb::SyncEnums::CLEAR_PENDING ||
  119. error_type == sync_pb::SyncEnums::NOT_MY_BIRTHDAY ||
  120. error_type == sync_pb::SyncEnums::ENCRYPTION_OBSOLETE) {
  121. error.action = DISABLE_SYNC_ON_CLIENT;
  122. } else if (error_type == sync_pb::SyncEnums::CLIENT_DATA_OBSOLETE) {
  123. error.action = RESET_LOCAL_SYNC_DATA;
  124. } else if (error_type == sync_pb::SyncEnums::DISABLED_BY_ADMIN) {
  125. error.action = STOP_SYNC_FOR_DISABLED_ACCOUNT;
  126. } // There is no other action we can compute for legacy server.
  127. return error;
  128. }
  129. // Verifies the store birthday, alerting/resetting as appropriate if there's a
  130. // mismatch. Return false if the syncer should be stuck.
  131. bool ProcessResponseBirthday(const ClientToServerResponse& response,
  132. SyncCycleContext* context) {
  133. const std::string& local_birthday = context->birthday();
  134. if (local_birthday.empty()) {
  135. if (!response.has_store_birthday()) {
  136. DLOG(WARNING) << "Expected a birthday on first sync.";
  137. return false;
  138. }
  139. DVLOG(1) << "New store birthday: " << response.store_birthday();
  140. context->set_birthday(response.store_birthday());
  141. return true;
  142. }
  143. // Error situation, but we're not stuck.
  144. if (!response.has_store_birthday()) {
  145. DLOG(WARNING) << "No birthday in server response?";
  146. return true;
  147. }
  148. if (response.store_birthday() != local_birthday) {
  149. DLOG(WARNING) << "Birthday changed, showing syncer stuck";
  150. return false;
  151. }
  152. return true;
  153. }
  154. void SaveBagOfChipsFromResponse(const sync_pb::ClientToServerResponse& response,
  155. SyncCycleContext* context) {
  156. if (!response.has_new_bag_of_chips())
  157. return;
  158. std::string bag_of_chips;
  159. if (response.new_bag_of_chips().SerializeToString(&bag_of_chips))
  160. context->set_bag_of_chips(bag_of_chips);
  161. }
  162. } // namespace
  163. ModelTypeSet GetTypesToMigrate(const ClientToServerResponse& response) {
  164. ModelTypeSet to_migrate;
  165. for (int i = 0; i < response.migrated_data_type_id_size(); i++) {
  166. int field_number = response.migrated_data_type_id(i);
  167. ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number);
  168. if (!IsRealDataType(model_type)) {
  169. DLOG(WARNING) << "Unknown field number " << field_number;
  170. continue;
  171. }
  172. to_migrate.Put(model_type);
  173. }
  174. return to_migrate;
  175. }
  176. SyncProtocolError ConvertErrorPBToSyncProtocolError(
  177. const sync_pb::ClientToServerResponse_Error& error) {
  178. SyncProtocolError sync_protocol_error;
  179. sync_protocol_error.error_type =
  180. PBErrorTypeToSyncProtocolErrorType(error.error_type());
  181. sync_protocol_error.error_description = error.error_description();
  182. sync_protocol_error.action = PBActionToClientAction(error.action());
  183. if (error.error_data_type_ids_size() > 0) {
  184. // THROTTLED and PARTIAL_FAILURE are currently the only error codes
  185. // that uses |error_data_types|.
  186. // In both cases, |error_data_types| are throttled.
  187. for (int i = 0; i < error.error_data_type_ids_size(); ++i) {
  188. int field_number = error.error_data_type_ids(i);
  189. ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number);
  190. if (!IsRealDataType(model_type)) {
  191. DLOG(WARNING) << "Unknown field number " << field_number;
  192. continue;
  193. }
  194. sync_protocol_error.error_data_types.Put(model_type);
  195. }
  196. }
  197. return sync_protocol_error;
  198. }
  199. // static
  200. bool SyncerProtoUtil::IsSyncDisabledByAdmin(
  201. const sync_pb::ClientToServerResponse& response) {
  202. return (response.has_error_code() &&
  203. response.error_code() == sync_pb::SyncEnums::DISABLED_BY_ADMIN);
  204. }
  205. // static
  206. SyncProtocolError SyncerProtoUtil::GetProtocolErrorFromResponse(
  207. const sync_pb::ClientToServerResponse& response,
  208. SyncCycleContext* context) {
  209. SyncProtocolError sync_protocol_error;
  210. // The DISABLED_BY_ADMIN error overrides other errors sent by the server.
  211. if (IsSyncDisabledByAdmin(response)) {
  212. sync_protocol_error.error_type = DISABLED_BY_ADMIN;
  213. sync_protocol_error.action = STOP_SYNC_FOR_DISABLED_ACCOUNT;
  214. } else if (response.has_error()) {
  215. // If the server provides explicit error information, just honor it.
  216. sync_protocol_error = ConvertErrorPBToSyncProtocolError(response.error());
  217. } else if (!ProcessResponseBirthday(response, context)) {
  218. // If sync isn't disabled, first check for a birthday mismatch error.
  219. if (response.error_code() == sync_pb::SyncEnums::CLIENT_DATA_OBSOLETE) {
  220. // Server indicates that client needs to reset sync data.
  221. sync_protocol_error.error_type = CLIENT_DATA_OBSOLETE;
  222. sync_protocol_error.action = RESET_LOCAL_SYNC_DATA;
  223. } else {
  224. sync_protocol_error.error_type = NOT_MY_BIRTHDAY;
  225. sync_protocol_error.action = DISABLE_SYNC_ON_CLIENT;
  226. }
  227. } else {
  228. // Legacy server implementation. Compute the error based on |error_code|.
  229. sync_protocol_error = ErrorCodeToSyncProtocolError(response.error_code());
  230. }
  231. // Trivially inferred actions.
  232. if (sync_protocol_error.action == UNKNOWN_ACTION &&
  233. sync_protocol_error.error_type == ENCRYPTION_OBSOLETE) {
  234. sync_protocol_error.action = DISABLE_SYNC_ON_CLIENT;
  235. }
  236. return sync_protocol_error;
  237. }
  238. // static
  239. void SyncerProtoUtil::SetProtocolVersion(ClientToServerMessage* msg) {
  240. const int current_version =
  241. ClientToServerMessage::default_instance().protocol_version();
  242. msg->set_protocol_version(current_version);
  243. }
  244. // static
  245. bool SyncerProtoUtil::PostAndProcessHeaders(ServerConnectionManager* scm,
  246. const ClientToServerMessage& msg,
  247. ClientToServerResponse* response) {
  248. DCHECK(msg.has_protocol_version());
  249. DCHECK_EQ(msg.protocol_version(),
  250. ClientToServerMessage::default_instance().protocol_version());
  251. std::string buffer_in;
  252. msg.SerializeToString(&buffer_in);
  253. UMA_HISTOGRAM_ENUMERATION("Sync.PostedClientToServerMessage",
  254. msg.message_contents(),
  255. ClientToServerMessage::Contents_MAX + 1);
  256. std::map<int, std::string> progress_marker_token_per_data_type;
  257. if (msg.has_get_updates()) {
  258. UMA_HISTOGRAM_ENUMERATION("Sync.PostedGetUpdatesOrigin",
  259. msg.get_updates().get_updates_origin(),
  260. sync_pb::SyncEnums::GetUpdatesOrigin_ARRAYSIZE);
  261. for (const sync_pb::DataTypeProgressMarker& progress_marker :
  262. msg.get_updates().from_progress_marker()) {
  263. progress_marker_token_per_data_type[progress_marker.data_type_id()] =
  264. progress_marker.token();
  265. UMA_HISTOGRAM_ENUMERATION(
  266. "Sync.PostedDataTypeGetUpdatesRequest",
  267. ModelTypeHistogramValue(GetModelTypeFromSpecificsFieldNumber(
  268. progress_marker.data_type_id())));
  269. }
  270. }
  271. const base::Time start_time = base::Time::Now();
  272. // User-initiated sync messages should not be batched. GET_UPDATES messages
  273. // are mostly safe to consider non-user-initiated.
  274. // TODO(https://crbug.com/1293657): Confirm that treating GET_UPDATES as
  275. // non-user-initiated is reasonable. GET_UPDATES messages could be latency
  276. // sensitive since these requests most commonly happen because of some
  277. // user-initiated changes on a different device.
  278. bool allow_batching =
  279. msg.message_contents() == ClientToServerMessage::GET_UPDATES;
  280. // Fills in buffer_out.
  281. std::string buffer_out;
  282. HttpResponse http_response =
  283. scm->PostBufferWithCachedAuth(buffer_in, allow_batching, &buffer_out);
  284. if (http_response.server_status != HttpResponse::SERVER_CONNECTION_OK) {
  285. LOG(WARNING) << "Error posting from syncer:" << http_response;
  286. return false;
  287. }
  288. if (!response->ParseFromString(buffer_out)) {
  289. DLOG(WARNING) << "Error parsing response from sync server";
  290. return false;
  291. }
  292. UMA_HISTOGRAM_MEDIUM_TIMES("Sync.PostedClientToServerMessageLatency",
  293. base::Time::Now() - start_time);
  294. // The error can be specified in 2 different fields, so consider both of them.
  295. sync_pb::SyncEnums::ErrorType error_type =
  296. response->has_error() ? response->error().error_type()
  297. : response->error_code();
  298. if (error_type != sync_pb::SyncEnums::SUCCESS) {
  299. base::UmaHistogramSparse("Sync.PostedClientToServerMessageError2",
  300. error_type);
  301. }
  302. return true;
  303. }
  304. base::TimeDelta SyncerProtoUtil::GetThrottleDelay(
  305. const ClientToServerResponse& response) {
  306. base::TimeDelta throttle_delay = kSyncDelayAfterThrottled;
  307. if (response.has_client_command()) {
  308. const sync_pb::ClientCommand& command = response.client_command();
  309. if (command.has_throttle_delay_seconds()) {
  310. throttle_delay = base::Seconds(command.throttle_delay_seconds());
  311. }
  312. }
  313. return throttle_delay;
  314. }
  315. // static
  316. void SyncerProtoUtil::AddRequiredFieldsToClientToServerMessage(
  317. const SyncCycle* cycle,
  318. sync_pb::ClientToServerMessage* msg) {
  319. DCHECK(msg);
  320. SetProtocolVersion(msg);
  321. const std::string birthday = cycle->context()->birthday();
  322. if (!birthday.empty())
  323. msg->set_store_birthday(birthday);
  324. DCHECK(msg->has_store_birthday() || !IsBirthdayRequired(*msg));
  325. msg->mutable_bag_of_chips()->ParseFromString(
  326. cycle->context()->bag_of_chips());
  327. msg->set_api_key(google_apis::GetAPIKey());
  328. msg->mutable_client_status()->CopyFrom(cycle->context()->client_status());
  329. msg->set_invalidator_client_id(cycle->context()->invalidator_client_id());
  330. }
  331. // static
  332. SyncerError SyncerProtoUtil::PostClientToServerMessage(
  333. const ClientToServerMessage& msg,
  334. ClientToServerResponse* response,
  335. SyncCycle* cycle,
  336. ModelTypeSet* partial_failure_data_types) {
  337. DCHECK(response);
  338. DCHECK(msg.has_protocol_version());
  339. DCHECK(msg.has_store_birthday() || !IsBirthdayRequired(msg));
  340. DCHECK(msg.has_bag_of_chips());
  341. DCHECK(msg.has_api_key());
  342. DCHECK(msg.has_client_status());
  343. DCHECK(msg.has_invalidator_client_id());
  344. LogClientToServerMessage(msg);
  345. if (!PostAndProcessHeaders(cycle->context()->connection_manager(), msg,
  346. response)) {
  347. // There was an error establishing communication with the server.
  348. // We can not proceed beyond this point.
  349. const HttpResponse::ServerConnectionCode server_status =
  350. cycle->context()->connection_manager()->server_status();
  351. DCHECK_NE(server_status, HttpResponse::NONE);
  352. DCHECK_NE(server_status, HttpResponse::SERVER_CONNECTION_OK);
  353. return ServerConnectionErrorAsSyncerError(
  354. server_status, cycle->context()->connection_manager()->net_error_code(),
  355. cycle->context()->connection_manager()->http_status_code());
  356. }
  357. LogClientToServerResponse(*response);
  358. // Remember a bag of chips if it has been sent by the server.
  359. SaveBagOfChipsFromResponse(*response, cycle->context());
  360. SyncProtocolError sync_protocol_error =
  361. GetProtocolErrorFromResponse(*response, cycle->context());
  362. // Inform the delegate of the error we got.
  363. cycle->delegate()->OnSyncProtocolError(sync_protocol_error);
  364. // Update our state for any other commands we've received.
  365. if (response->has_client_command()) {
  366. const sync_pb::ClientCommand& command = response->client_command();
  367. if (command.has_max_commit_batch_size()) {
  368. cycle->context()->set_max_commit_batch_size(
  369. command.max_commit_batch_size());
  370. }
  371. if (command.has_set_sync_poll_interval()) {
  372. base::TimeDelta interval =
  373. base::Seconds(command.set_sync_poll_interval());
  374. if (interval.is_zero()) {
  375. DLOG(WARNING) << "Received zero poll interval from server. Ignoring.";
  376. } else {
  377. cycle->context()->set_poll_interval(interval);
  378. cycle->delegate()->OnReceivedPollIntervalUpdate(interval);
  379. }
  380. }
  381. if (command.has_sessions_commit_delay_seconds()) {
  382. std::map<ModelType, base::TimeDelta> delay_map;
  383. delay_map[SESSIONS] =
  384. base::Seconds(command.sessions_commit_delay_seconds());
  385. cycle->delegate()->OnReceivedCustomNudgeDelays(delay_map);
  386. }
  387. if (command.has_client_invalidation_hint_buffer_size()) {
  388. cycle->delegate()->OnReceivedClientInvalidationHintBufferSize(
  389. command.client_invalidation_hint_buffer_size());
  390. }
  391. if (command.has_gu_retry_delay_seconds()) {
  392. cycle->delegate()->OnReceivedGuRetryDelay(
  393. base::Seconds(command.gu_retry_delay_seconds()));
  394. }
  395. if (command.custom_nudge_delays_size() > 0) {
  396. // Note that because this happens after the sessions_commit_delay_seconds
  397. // handling, any SESSIONS value in this map will override the one in
  398. // sessions_commit_delay_seconds.
  399. std::map<ModelType, base::TimeDelta> delay_map;
  400. for (int i = 0; i < command.custom_nudge_delays_size(); ++i) {
  401. ModelType type = GetModelTypeFromSpecificsFieldNumber(
  402. command.custom_nudge_delays(i).datatype_id());
  403. if (type != UNSPECIFIED) {
  404. delay_map[type] =
  405. base::Milliseconds(command.custom_nudge_delays(i).delay_ms());
  406. }
  407. }
  408. cycle->delegate()->OnReceivedCustomNudgeDelays(delay_map);
  409. }
  410. absl::optional<int> max_tokens;
  411. if (command.has_extension_types_max_tokens()) {
  412. max_tokens = command.extension_types_max_tokens();
  413. }
  414. absl::optional<base::TimeDelta> refill_interval;
  415. if (command.has_extension_types_refill_interval_seconds()) {
  416. refill_interval =
  417. base::Seconds(command.extension_types_refill_interval_seconds());
  418. }
  419. absl::optional<base::TimeDelta> depleted_quota_nudge_delay;
  420. if (command.has_extension_types_depleted_quota_nudge_delay_seconds()) {
  421. depleted_quota_nudge_delay = base::Seconds(
  422. command.extension_types_depleted_quota_nudge_delay_seconds());
  423. }
  424. if (max_tokens || refill_interval || depleted_quota_nudge_delay) {
  425. cycle->delegate()->OnReceivedQuotaParamsForExtensionTypes(
  426. max_tokens, refill_interval, depleted_quota_nudge_delay);
  427. }
  428. }
  429. // Now do any special handling for the error type and decide on the return
  430. // value.
  431. switch (sync_protocol_error.error_type) {
  432. case UNKNOWN_ERROR:
  433. LOG(WARNING) << "Sync protocol out-of-date. The server is using a more "
  434. << "recent version.";
  435. return SyncerError(SyncerError::SERVER_RETURN_UNKNOWN_ERROR);
  436. case SYNC_SUCCESS:
  437. return SyncerError(SyncerError::SYNCER_OK);
  438. case THROTTLED:
  439. if (sync_protocol_error.error_data_types.Empty()) {
  440. DLOG(WARNING) << "Client fully throttled by syncer.";
  441. cycle->delegate()->OnThrottled(GetThrottleDelay(*response));
  442. } else {
  443. // This is a special case, since server only throttle some of datatype,
  444. // so can treat this case as partial failure.
  445. DLOG(WARNING) << "Some types throttled by syncer.";
  446. cycle->delegate()->OnTypesThrottled(
  447. sync_protocol_error.error_data_types, GetThrottleDelay(*response));
  448. if (partial_failure_data_types != nullptr) {
  449. *partial_failure_data_types = sync_protocol_error.error_data_types;
  450. }
  451. return SyncerError(SyncerError::SYNCER_OK);
  452. }
  453. return SyncerError(SyncerError::SERVER_RETURN_THROTTLED);
  454. case TRANSIENT_ERROR:
  455. return SyncerError(SyncerError::SERVER_RETURN_TRANSIENT_ERROR);
  456. case MIGRATION_DONE:
  457. LOG_IF(ERROR, 0 >= response->migrated_data_type_id_size())
  458. << "MIGRATION_DONE but no types specified.";
  459. cycle->delegate()->OnReceivedMigrationRequest(
  460. GetTypesToMigrate(*response));
  461. return SyncerError(SyncerError::SERVER_RETURN_MIGRATION_DONE);
  462. case CLEAR_PENDING:
  463. return SyncerError(SyncerError::SERVER_RETURN_CLEAR_PENDING);
  464. case NOT_MY_BIRTHDAY:
  465. return SyncerError(SyncerError::SERVER_RETURN_NOT_MY_BIRTHDAY);
  466. case DISABLED_BY_ADMIN:
  467. return SyncerError(SyncerError::SERVER_RETURN_DISABLED_BY_ADMIN);
  468. case PARTIAL_FAILURE:
  469. // This only happens when partial backoff during GetUpdates.
  470. if (!sync_protocol_error.error_data_types.Empty()) {
  471. DLOG(WARNING)
  472. << "Some types got partial failure by syncer during GetUpdates.";
  473. cycle->delegate()->OnTypesBackedOff(
  474. sync_protocol_error.error_data_types);
  475. }
  476. if (partial_failure_data_types != nullptr) {
  477. *partial_failure_data_types = sync_protocol_error.error_data_types;
  478. }
  479. return SyncerError(SyncerError::SYNCER_OK);
  480. case CLIENT_DATA_OBSOLETE:
  481. return SyncerError(SyncerError::SERVER_RETURN_CLIENT_DATA_OBSOLETE);
  482. case ENCRYPTION_OBSOLETE:
  483. return SyncerError(SyncerError::SERVER_RETURN_ENCRYPTION_OBSOLETE);
  484. }
  485. NOTREACHED();
  486. return SyncerError();
  487. }
  488. // static
  489. bool SyncerProtoUtil::ShouldMaintainPosition(
  490. const sync_pb::SyncEntity& sync_entity) {
  491. // Maintain positions for bookmarks that are not server-defined top-level
  492. // folders.
  493. return GetModelTypeFromSpecifics(sync_entity.specifics()) == BOOKMARKS &&
  494. !(sync_entity.folder() &&
  495. !sync_entity.server_defined_unique_tag().empty());
  496. }
  497. // static
  498. bool SyncerProtoUtil::ShouldMaintainHierarchy(
  499. const sync_pb::SyncEntity& sync_entity) {
  500. // Maintain hierarchy for bookmarks or top-level items.
  501. return GetModelTypeFromSpecifics(sync_entity.specifics()) == BOOKMARKS ||
  502. sync_entity.parent_id_string() == "0";
  503. }
  504. std::string SyncerProtoUtil::SyncEntityDebugString(
  505. const sync_pb::SyncEntity& entry) {
  506. const std::string& mtime_str =
  507. GetTimeDebugString(ProtoTimeToTime(entry.mtime()));
  508. const std::string& ctime_str =
  509. GetTimeDebugString(ProtoTimeToTime(entry.ctime()));
  510. return base::StringPrintf(
  511. "id: %s, parent_id: %s, "
  512. "version: %" PRId64
  513. "d, "
  514. "mtime: %" PRId64
  515. "d (%s), "
  516. "ctime: %" PRId64
  517. "d (%s), "
  518. "name: %s, "
  519. "d, "
  520. "%s ",
  521. entry.id_string().c_str(), entry.parent_id_string().c_str(),
  522. entry.version(), entry.mtime(), mtime_str.c_str(), entry.ctime(),
  523. ctime_str.c_str(), entry.name().c_str(),
  524. entry.deleted() ? "deleted, " : "");
  525. }
  526. namespace {
  527. std::string GetUpdatesResponseString(
  528. const sync_pb::GetUpdatesResponse& response) {
  529. std::string output;
  530. output.append("GetUpdatesResponse:\n");
  531. for (int i = 0; i < response.entries_size(); i++) {
  532. output.append(SyncerProtoUtil::SyncEntityDebugString(response.entries(i)));
  533. output.append("\n");
  534. }
  535. return output;
  536. }
  537. } // namespace
  538. std::string SyncerProtoUtil::ClientToServerResponseDebugString(
  539. const ClientToServerResponse& response) {
  540. // Add more handlers as needed.
  541. std::string output;
  542. if (response.has_get_updates())
  543. output.append(GetUpdatesResponseString(response.get_updates()));
  544. return output;
  545. }
  546. } // namespace syncer