summaryrefslogtreecommitdiffstats
path: root/sync/engine/get_updates_processor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sync/engine/get_updates_processor.cc')
-rw-r--r--sync/engine/get_updates_processor.cc167
1 files changed, 166 insertions, 1 deletions
diff --git a/sync/engine/get_updates_processor.cc b/sync/engine/get_updates_processor.cc
index 449f718..2ffc4b3 100644
--- a/sync/engine/get_updates_processor.cc
+++ b/sync/engine/get_updates_processor.cc
@@ -6,9 +6,16 @@
#include <map>
+#include "base/debug/trace_event.h"
#include "sync/engine/get_updates_delegate.h"
+#include "sync/engine/syncer_proto_util.h"
#include "sync/engine/update_handler.h"
#include "sync/protocol/sync.pb.h"
+#include "sync/sessions/status_controller.h"
+#include "sync/sessions/sync_session.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/nigori_handler.h"
+#include "sync/syncable/syncable_read_transaction.h"
typedef std::vector<const sync_pb::SyncEntity*> SyncEntityList;
typedef std::map<syncer::ModelType, SyncEntityList> TypeSyncEntityMap;
@@ -19,6 +26,35 @@ typedef std::map<ModelType, size_t> TypeToIndexMap;
namespace {
+bool ShouldRequestEncryptionKey(sessions::SyncSessionContext* context) {
+ syncable::Directory* dir = context->directory();
+ syncable::ReadTransaction trans(FROM_HERE, dir);
+ syncable::NigoriHandler* nigori_handler = dir->GetNigoriHandler();
+ return nigori_handler->NeedKeystoreKey(&trans);
+}
+
+
+SyncerError HandleGetEncryptionKeyResponse(
+ const sync_pb::ClientToServerResponse& update_response,
+ syncable::Directory* dir) {
+ bool success = false;
+ if (update_response.get_updates().encryption_keys_size() == 0) {
+ LOG(ERROR) << "Failed to receive encryption key from server.";
+ return SERVER_RESPONSE_VALIDATION_FAILED;
+ }
+ syncable::ReadTransaction trans(FROM_HERE, dir);
+ syncable::NigoriHandler* nigori_handler = dir->GetNigoriHandler();
+ success = nigori_handler->SetKeystoreKeys(
+ update_response.get_updates().encryption_keys(),
+ &trans);
+
+ DVLOG(1) << "GetUpdates returned "
+ << update_response.get_updates().encryption_keys_size()
+ << "encryption keys. Nigori keystore key "
+ << (success ? "" : "not ") << "updated.";
+ return (success ? SYNCER_OK : SERVER_RESPONSE_VALIDATION_FAILED);
+}
+
// Given a GetUpdates response, iterates over all the returned items and
// divides them according to their type. Outputs a map from model types to
// received SyncEntities. The output map will have entries (possibly empty)
@@ -74,6 +110,34 @@ void PartitionProgressMarkersByType(
}
}
+// Initializes the parts of the GetUpdatesMessage that depend on shared state,
+// like the ShouldRequestEncryptionKey() status. This is kept separate from the
+// other of the message-building functions to make the rest of the code easier
+// to test.
+void InitDownloadUpdatesContext(
+ sessions::SyncSession* session,
+ bool create_mobile_bookmarks_folder,
+ sync_pb::ClientToServerMessage* message) {
+ message->set_share(session->context()->account_name());
+ message->set_message_contents(sync_pb::ClientToServerMessage::GET_UPDATES);
+
+ sync_pb::GetUpdatesMessage* get_updates = message->mutable_get_updates();
+
+ // We want folders for our associated types, always. If we were to set
+ // this to false, the server would send just the non-container items
+ // (e.g. Bookmark URLs but not their containing folders).
+ get_updates->set_fetch_folders(true);
+
+ get_updates->set_create_mobile_bookmarks_folder(
+ create_mobile_bookmarks_folder);
+ bool need_encryption_key = ShouldRequestEncryptionKey(session->context());
+ get_updates->set_need_encryption_key(need_encryption_key);
+
+ // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information.
+ get_updates->mutable_caller_info()->set_notifications_enabled(
+ session->context()->notifications_enabled());
+}
+
} // namespace
GetUpdatesProcessor::GetUpdatesProcessor(UpdateHandlerMap* update_handler_map,
@@ -82,9 +146,29 @@ GetUpdatesProcessor::GetUpdatesProcessor(UpdateHandlerMap* update_handler_map,
GetUpdatesProcessor::~GetUpdatesProcessor() {}
+SyncerError GetUpdatesProcessor::DownloadUpdates(
+ ModelTypeSet request_types,
+ sessions::SyncSession* session,
+ bool create_mobile_bookmarks_folder) {
+ TRACE_EVENT0("sync", "DownloadUpdates");
+
+ sync_pb::ClientToServerMessage message;
+ InitDownloadUpdatesContext(session,
+ create_mobile_bookmarks_folder,
+ &message);
+ PrepareGetUpdates(request_types, &message);
+
+ SyncerError result = ExecuteDownloadUpdates(request_types, session, &message);
+ session->mutable_status_controller()->set_last_download_updates_result(
+ result);
+ return result;
+}
+
void GetUpdatesProcessor::PrepareGetUpdates(
ModelTypeSet gu_types,
- sync_pb::GetUpdatesMessage* get_updates) {
+ sync_pb::ClientToServerMessage* message) {
+ sync_pb::GetUpdatesMessage* get_updates = message->mutable_get_updates();
+
for (ModelTypeSet::Iterator it = gu_types.First(); it.Good(); it.Inc()) {
UpdateHandlerMap::iterator handler_it = update_handler_map_->find(it.Get());
DCHECK(handler_it != update_handler_map_->end());
@@ -95,6 +179,80 @@ void GetUpdatesProcessor::PrepareGetUpdates(
delegate_.HelpPopulateGuMessage(get_updates);
}
+SyncerError GetUpdatesProcessor::ExecuteDownloadUpdates(
+ ModelTypeSet request_types,
+ sessions::SyncSession* session,
+ sync_pb::ClientToServerMessage* msg) {
+ sync_pb::ClientToServerResponse update_response;
+ sessions::StatusController* status = session->mutable_status_controller();
+ bool need_encryption_key = ShouldRequestEncryptionKey(session->context());
+
+ if (session->context()->debug_info_getter()) {
+ sync_pb::DebugInfo* debug_info = msg->mutable_debug_info();
+ CopyClientDebugInfo(session->context()->debug_info_getter(), debug_info);
+ }
+
+ SyncerError result = SyncerProtoUtil::PostClientToServerMessage(
+ msg,
+ &update_response,
+ session);
+
+ DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString(
+ update_response);
+
+ if (result != SYNCER_OK) {
+ LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates";
+ return result;
+ }
+
+ DVLOG(1) << "GetUpdates "
+ << " returned " << update_response.get_updates().entries_size()
+ << " updates and indicated "
+ << update_response.get_updates().changes_remaining()
+ << " updates left on server.";
+
+ if (session->context()->debug_info_getter()) {
+ // Clear debug info now that we have successfully sent it to the server.
+ DVLOG(1) << "Clearing client debug info.";
+ session->context()->debug_info_getter()->ClearDebugInfo();
+ }
+
+ if (need_encryption_key ||
+ update_response.get_updates().encryption_keys_size() > 0) {
+ syncable::Directory* dir = session->context()->directory();
+ status->set_last_get_key_result(
+ HandleGetEncryptionKeyResponse(update_response, dir));
+ }
+
+ return ProcessResponse(update_response.get_updates(),
+ request_types,
+ status);
+}
+
+SyncerError GetUpdatesProcessor::ProcessResponse(
+ const sync_pb::GetUpdatesResponse& gu_response,
+ ModelTypeSet request_types,
+ sessions::StatusController* status) {
+ status->increment_num_updates_downloaded_by(gu_response.entries_size());
+
+ // The changes remaining field is used to prevent the client from looping. If
+ // that field is being set incorrectly, we're in big trouble.
+ if (!gu_response.has_changes_remaining()) {
+ return SERVER_RESPONSE_VALIDATION_FAILED;
+ }
+ status->set_num_server_changes_remaining(gu_response.changes_remaining());
+
+ if (!ProcessGetUpdatesResponse(request_types, gu_response, status)) {
+ return SERVER_RESPONSE_VALIDATION_FAILED;
+ }
+
+ if (gu_response.changes_remaining() == 0) {
+ return SYNCER_OK;
+ } else {
+ return SERVER_MORE_TO_DOWNLOAD;
+ }
+}
+
bool GetUpdatesProcessor::ProcessGetUpdatesResponse(
ModelTypeSet gu_types,
const sync_pb::GetUpdatesResponse& gu_response,
@@ -148,4 +306,11 @@ void GetUpdatesProcessor::ApplyUpdates(
delegate_.ApplyUpdates(status_controller, update_handler_map_);
}
+void GetUpdatesProcessor::CopyClientDebugInfo(
+ sessions::DebugInfoGetter* debug_info_getter,
+ sync_pb::DebugInfo* debug_info) {
+ DVLOG(1) << "Copying client debug info to send.";
+ debug_info_getter->GetDebugInfo(debug_info);
+}
+
} // namespace syncer