1 // Copyright 2014 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 "components/sync/engine_impl/get_updates_processor.h"
6 
7 #include <stddef.h>
8 #include <string>
9 #include <utility>
10 
11 #include "base/trace_event/trace_event.h"
12 #include "components/sync/engine_impl/cycle/status_controller.h"
13 #include "components/sync/engine_impl/cycle/sync_cycle.h"
14 #include "components/sync/engine_impl/events/get_updates_response_event.h"
15 #include "components/sync/engine_impl/get_updates_delegate.h"
16 #include "components/sync/engine_impl/syncer_proto_util.h"
17 #include "components/sync/engine_impl/update_handler.h"
18 #include "components/sync/nigori/keystore_keys_handler.h"
19 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
20 
21 namespace syncer {
22 
23 namespace {
24 
25 using SyncEntityList = std::vector<const sync_pb::SyncEntity*>;
26 using TypeSyncEntityMap = std::map<ModelType, SyncEntityList>;
27 using TypeToIndexMap = std::map<ModelType, size_t>;
28 
ShouldRequestEncryptionKey(SyncCycleContext * context)29 bool ShouldRequestEncryptionKey(SyncCycleContext* context) {
30   return context->model_type_registry()
31       ->keystore_keys_handler()
32       ->NeedKeystoreKey();
33 }
34 
ExtractKeystoreKeys(const sync_pb::ClientToServerResponse & update_response)35 std::vector<std::vector<uint8_t>> ExtractKeystoreKeys(
36     const sync_pb::ClientToServerResponse& update_response) {
37   const google::protobuf::RepeatedPtrField<std::string>& encryption_keys =
38       update_response.get_updates().encryption_keys();
39   std::vector<std::vector<uint8_t>> keystore_keys;
40   keystore_keys.reserve(encryption_keys.size());
41   for (const std::string& key : encryption_keys)
42     keystore_keys.emplace_back(key.begin(), key.end());
43   return keystore_keys;
44 }
45 
HandleGetEncryptionKeyResponse(const sync_pb::ClientToServerResponse & update_response,SyncCycleContext * context)46 SyncerError HandleGetEncryptionKeyResponse(
47     const sync_pb::ClientToServerResponse& update_response,
48     SyncCycleContext* context) {
49   bool success = false;
50   if (update_response.get_updates().encryption_keys_size() == 0) {
51     LOG(ERROR) << "Failed to receive encryption key from server.";
52     return SyncerError(SyncerError::SERVER_RESPONSE_VALIDATION_FAILED);
53   }
54 
55   std::vector<std::vector<uint8_t>> keystore_keys =
56       ExtractKeystoreKeys(update_response);
57 
58   success =
59       context->model_type_registry()->keystore_keys_handler()->SetKeystoreKeys(
60           keystore_keys);
61 
62   DVLOG(1) << "GetUpdates returned "
63            << update_response.get_updates().encryption_keys_size()
64            << "encryption keys. Nigori keystore key " << (success ? "" : "not ")
65            << "updated.";
66   return (success
67               ? SyncerError(SyncerError::SYNCER_OK)
68               : SyncerError(SyncerError::SERVER_RESPONSE_VALIDATION_FAILED));
69 }
70 
71 // Given a GetUpdates response, iterates over all the returned items and
72 // divides them according to their type.  Outputs a map from model types to
73 // received SyncEntities.  The output map will have entries (possibly empty)
74 // for all types in |requested_types|.
PartitionUpdatesByType(const sync_pb::GetUpdatesResponse & gu_response,ModelTypeSet requested_types,TypeSyncEntityMap * updates_by_type)75 void PartitionUpdatesByType(const sync_pb::GetUpdatesResponse& gu_response,
76                             ModelTypeSet requested_types,
77                             TypeSyncEntityMap* updates_by_type) {
78   int update_count = gu_response.entries().size();
79   for (ModelType type : requested_types) {
80     updates_by_type->insert(std::make_pair(type, SyncEntityList()));
81   }
82   for (int i = 0; i < update_count; ++i) {
83     const sync_pb::SyncEntity& update = gu_response.entries(i);
84     ModelType type = GetModelType(update);
85     if (!IsRealDataType(type)) {
86       NOTREACHED() << "Received update with invalid type.";
87       continue;
88     }
89 
90     auto it = updates_by_type->find(type);
91     if (it == updates_by_type->end()) {
92       DLOG(WARNING) << "Received update for unexpected type, or the type is "
93                        "throttled or failed with partial failure:"
94                     << ModelTypeToString(type);
95       continue;
96     }
97 
98     it->second.push_back(&update);
99   }
100 }
101 
102 // Builds a map of ModelTypes to indices to progress markers in the given
103 // |gu_response| message.  The map is returned in the |index_map| parameter.
PartitionProgressMarkersByType(const sync_pb::GetUpdatesResponse & gu_response,const ModelTypeSet & request_types,TypeToIndexMap * index_map)104 void PartitionProgressMarkersByType(
105     const sync_pb::GetUpdatesResponse& gu_response,
106     const ModelTypeSet& request_types,
107     TypeToIndexMap* index_map) {
108   for (int i = 0; i < gu_response.new_progress_marker_size(); ++i) {
109     int field_number = gu_response.new_progress_marker(i).data_type_id();
110     ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number);
111     if (!IsRealDataType(model_type)) {
112       DLOG(WARNING) << "Unknown field number " << field_number;
113       continue;
114     }
115     if (!request_types.Has(model_type)) {
116       DLOG(WARNING)
117           << "Skipping unexpected progress marker for non-enabled type "
118           << ModelTypeToString(model_type);
119       continue;
120     }
121     index_map->insert(std::make_pair(model_type, i));
122   }
123 }
124 
PartitionContextMutationsByType(const sync_pb::GetUpdatesResponse & gu_response,const ModelTypeSet & request_types,TypeToIndexMap * index_map)125 void PartitionContextMutationsByType(
126     const sync_pb::GetUpdatesResponse& gu_response,
127     const ModelTypeSet& request_types,
128     TypeToIndexMap* index_map) {
129   for (int i = 0; i < gu_response.context_mutations_size(); ++i) {
130     int field_number = gu_response.context_mutations(i).data_type_id();
131     ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number);
132     if (!IsRealDataType(model_type)) {
133       DLOG(WARNING) << "Unknown field number " << field_number;
134       continue;
135     }
136     if (!request_types.Has(model_type)) {
137       DLOG(WARNING)
138           << "Skipping unexpected context mutation for non-enabled type "
139           << ModelTypeToString(model_type);
140       continue;
141     }
142     index_map->insert(std::make_pair(model_type, i));
143   }
144 }
145 
146 // Initializes the parts of the GetUpdatesMessage that depend on shared state,
147 // like the ShouldRequestEncryptionKey() status.  This is kept separate from the
148 // other of the message-building functions to make the rest of the code easier
149 // to test.
InitDownloadUpdatesContext(SyncCycle * cycle,sync_pb::ClientToServerMessage * message)150 void InitDownloadUpdatesContext(SyncCycle* cycle,
151                                 sync_pb::ClientToServerMessage* message) {
152   message->set_share(cycle->context()->account_name());
153   message->set_message_contents(sync_pb::ClientToServerMessage::GET_UPDATES);
154 
155   sync_pb::GetUpdatesMessage* get_updates = message->mutable_get_updates();
156 
157   // We want folders for our associated types, always.  If we were to set
158   // this to false, the server would send just the non-container items
159   // (e.g. Bookmark URLs but not their containing folders).
160   get_updates->set_fetch_folders(true);
161 
162   // This is a deprecated field that should be cleaned up after server's
163   // behavior is updated.
164   get_updates->set_create_mobile_bookmarks_folder(true);
165 
166   bool need_encryption_key = ShouldRequestEncryptionKey(cycle->context());
167   get_updates->set_need_encryption_key(need_encryption_key);
168 
169   get_updates->mutable_caller_info()->set_notifications_enabled(
170       cycle->context()->notifications_enabled());
171 }
172 
173 }  // namespace
174 
GetUpdatesProcessor(UpdateHandlerMap * update_handler_map,const GetUpdatesDelegate & delegate)175 GetUpdatesProcessor::GetUpdatesProcessor(UpdateHandlerMap* update_handler_map,
176                                          const GetUpdatesDelegate& delegate)
177     : update_handler_map_(update_handler_map), delegate_(delegate) {}
178 
~GetUpdatesProcessor()179 GetUpdatesProcessor::~GetUpdatesProcessor() {}
180 
DownloadUpdates(ModelTypeSet * request_types,SyncCycle * cycle)181 SyncerError GetUpdatesProcessor::DownloadUpdates(ModelTypeSet* request_types,
182                                                  SyncCycle* cycle) {
183   TRACE_EVENT0("sync", "DownloadUpdates");
184 
185   sync_pb::ClientToServerMessage message;
186   InitDownloadUpdatesContext(cycle, &message);
187   PrepareGetUpdates(*request_types, &message);
188 
189   SyncerError result = ExecuteDownloadUpdates(request_types, cycle, &message);
190   cycle->mutable_status_controller()->set_last_download_updates_result(result);
191   return result;
192 }
193 
PrepareGetUpdates(const ModelTypeSet & gu_types,sync_pb::ClientToServerMessage * message)194 void GetUpdatesProcessor::PrepareGetUpdates(
195     const ModelTypeSet& gu_types,
196     sync_pb::ClientToServerMessage* message) {
197   sync_pb::GetUpdatesMessage* get_updates = message->mutable_get_updates();
198 
199   for (ModelType type : gu_types) {
200     auto handler_it = update_handler_map_->find(type);
201     DCHECK(handler_it != update_handler_map_->end())
202         << "Failed to look up handler for " << ModelTypeToString(type);
203     sync_pb::DataTypeProgressMarker* progress_marker =
204         get_updates->add_from_progress_marker();
205     *progress_marker = handler_it->second->GetDownloadProgress();
206     progress_marker->clear_gc_directive();
207 
208     sync_pb::DataTypeContext context = handler_it->second->GetDataTypeContext();
209     if (!context.context().empty())
210       get_updates->add_client_contexts()->Swap(&context);
211   }
212 
213   delegate_.HelpPopulateGuMessage(get_updates);
214 }
215 
ExecuteDownloadUpdates(ModelTypeSet * request_types,SyncCycle * cycle,sync_pb::ClientToServerMessage * msg)216 SyncerError GetUpdatesProcessor::ExecuteDownloadUpdates(
217     ModelTypeSet* request_types,
218     SyncCycle* cycle,
219     sync_pb::ClientToServerMessage* msg) {
220   sync_pb::ClientToServerResponse update_response;
221   StatusController* status = cycle->mutable_status_controller();
222   bool need_encryption_key = ShouldRequestEncryptionKey(cycle->context());
223 
224   if (cycle->context()->debug_info_getter()) {
225     *msg->mutable_debug_info() =
226         cycle->context()->debug_info_getter()->GetDebugInfo();
227   }
228 
229   SyncerProtoUtil::AddRequiredFieldsToClientToServerMessage(cycle, msg);
230 
231   cycle->SendProtocolEvent(
232       *(delegate_.GetNetworkRequestEvent(base::Time::Now(), *msg)));
233 
234   ModelTypeSet partial_failure_data_types;
235 
236   SyncerError result = SyncerProtoUtil::PostClientToServerMessage(
237       *msg, &update_response, cycle, &partial_failure_data_types);
238 
239   DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString(
240       update_response);
241 
242   if (!partial_failure_data_types.Empty()) {
243     request_types->RemoveAll(partial_failure_data_types);
244   }
245 
246   if (result.value() != SyncerError::SYNCER_OK) {
247     GetUpdatesResponseEvent response_event(base::Time::Now(), update_response,
248                                            result);
249     cycle->SendProtocolEvent(response_event);
250 
251     // Sync authorization expires every 60 mintues, so SYNC_AUTH_ERROR will
252     // appear every 60 minutes, and then sync services will refresh the
253     // authorization. Therefore SYNC_AUTH_ERROR is excluded here to reduce the
254     // ERROR messages in the log.
255     if (result.value() != SyncerError::SYNC_AUTH_ERROR) {
256       LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates "
257                     "with error "
258                  << result.value();
259     }
260 
261     return result;
262   }
263 
264   DVLOG(1) << "GetUpdates returned "
265            << update_response.get_updates().entries_size() << " updates.";
266 
267   if (cycle->context()->debug_info_getter()) {
268     // Clear debug info now that we have successfully sent it to the server.
269     DVLOG(1) << "Clearing client debug info.";
270     cycle->context()->debug_info_getter()->ClearDebugInfo();
271   }
272 
273   if (need_encryption_key ||
274       update_response.get_updates().encryption_keys_size() > 0) {
275     status->set_last_get_key_result(
276         HandleGetEncryptionKeyResponse(update_response, cycle->context()));
277   }
278 
279   SyncerError process_result =
280       ProcessResponse(update_response.get_updates(), *request_types, status);
281 
282   GetUpdatesResponseEvent response_event(base::Time::Now(), update_response,
283                                          process_result);
284   cycle->SendProtocolEvent(response_event);
285 
286   DVLOG(1) << "GetUpdates result: " << process_result.ToString();
287 
288   return process_result;
289 }
290 
ProcessResponse(const sync_pb::GetUpdatesResponse & gu_response,const ModelTypeSet & request_types,StatusController * status)291 SyncerError GetUpdatesProcessor::ProcessResponse(
292     const sync_pb::GetUpdatesResponse& gu_response,
293     const ModelTypeSet& request_types,
294     StatusController* status) {
295   status->increment_num_updates_downloaded_by(gu_response.entries_size());
296 
297   // The changes remaining field is used to prevent the client from looping.  If
298   // that field is being set incorrectly, we're in big trouble.
299   if (!gu_response.has_changes_remaining()) {
300     return SyncerError(SyncerError::SERVER_RESPONSE_VALIDATION_FAILED);
301   }
302 
303   SyncerError result =
304       ProcessGetUpdatesResponse(request_types, gu_response, status);
305   if (result.value() != SyncerError::SYNCER_OK)
306     return result;
307 
308   if (gu_response.changes_remaining() == 0) {
309     return SyncerError(SyncerError::SYNCER_OK);
310   } else {
311     return SyncerError(SyncerError::SERVER_MORE_TO_DOWNLOAD);
312   }
313 }
314 
ProcessGetUpdatesResponse(const ModelTypeSet & gu_types,const sync_pb::GetUpdatesResponse & gu_response,StatusController * status_controller)315 SyncerError GetUpdatesProcessor::ProcessGetUpdatesResponse(
316     const ModelTypeSet& gu_types,
317     const sync_pb::GetUpdatesResponse& gu_response,
318     StatusController* status_controller) {
319   TypeSyncEntityMap updates_by_type;
320   PartitionUpdatesByType(gu_response, gu_types, &updates_by_type);
321   DCHECK_EQ(gu_types.Size(), updates_by_type.size());
322 
323   TypeToIndexMap progress_index_by_type;
324   PartitionProgressMarkersByType(gu_response, gu_types,
325                                  &progress_index_by_type);
326   if (gu_types.Size() != progress_index_by_type.size()) {
327     NOTREACHED() << "Missing progress markers in GetUpdates response.";
328     return SyncerError(SyncerError::SERVER_RESPONSE_VALIDATION_FAILED);
329   }
330 
331   TypeToIndexMap context_by_type;
332   PartitionContextMutationsByType(gu_response, gu_types, &context_by_type);
333 
334   // Iterate over these maps in parallel, processing updates for each type.
335   auto progress_marker_iter = progress_index_by_type.begin();
336   auto updates_iter = updates_by_type.begin();
337   for (; (progress_marker_iter != progress_index_by_type.end() &&
338           updates_iter != updates_by_type.end());
339        ++progress_marker_iter, ++updates_iter) {
340     DCHECK_EQ(progress_marker_iter->first, updates_iter->first);
341     ModelType type = progress_marker_iter->first;
342 
343     auto update_handler_iter = update_handler_map_->find(type);
344 
345     sync_pb::DataTypeContext context;
346     auto context_iter = context_by_type.find(type);
347     if (context_iter != context_by_type.end())
348       context.CopyFrom(gu_response.context_mutations(context_iter->second));
349 
350     if (update_handler_iter != update_handler_map_->end()) {
351       SyncerError result =
352           update_handler_iter->second->ProcessGetUpdatesResponse(
353               gu_response.new_progress_marker(progress_marker_iter->second),
354               context, updates_iter->second, status_controller);
355       if (result.value() != SyncerError::SYNCER_OK)
356         return result;
357     } else {
358       DLOG(WARNING) << "Ignoring received updates of a type we can't handle.  "
359                     << "Type is: " << ModelTypeToString(type);
360       continue;
361     }
362   }
363   DCHECK(progress_marker_iter == progress_index_by_type.end() &&
364          updates_iter == updates_by_type.end());
365 
366   return SyncerError(SyncerError::SYNCER_OK);
367 }
368 
ApplyUpdates(const ModelTypeSet & gu_types,StatusController * status_controller)369 void GetUpdatesProcessor::ApplyUpdates(const ModelTypeSet& gu_types,
370                                        StatusController* status_controller) {
371   status_controller->set_get_updates_request_types(gu_types);
372   delegate_.ApplyUpdates(gu_types, status_controller, update_handler_map_);
373 }
374 
375 }  // namespace syncer
376