Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Side by Side Diff: sync/engine/syncer_proto_util.cc

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sync/engine/syncer_proto_util.h ('k') | sync/engine/syncer_proto_util_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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(&params.buffer_in);
341
342 // Fills in params.buffer_out and params.response.
343 if (!scm->PostBufferWithCachedAuth(&params)) {
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
OLDNEW
« no previous file with comments | « sync/engine/syncer_proto_util.h ('k') | sync/engine/syncer_proto_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698