1 // Copyright 2016 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 #ifndef COMPONENTS_SYNC_ENGINE_IMPL_LOOPBACK_SERVER_LOOPBACK_SERVER_H_
6 #define COMPONENTS_SYNC_ENGINE_IMPL_LOOPBACK_SERVER_LOOPBACK_SERVER_H_
7 
8 #include <stdint.h>
9 
10 #include <map>
11 #include <memory>
12 #include <string>
13 #include <vector>
14 
15 #include "base/callback.h"
16 #include "base/files/file_path.h"
17 #include "base/files/important_file_writer.h"
18 #include "base/optional.h"
19 #include "base/sequence_checker.h"
20 #include "base/values.h"
21 #include "components/sync/base/model_type.h"
22 #include "components/sync/engine_impl/loopback_server/loopback_server_entity.h"
23 #include "components/sync/protocol/loopback_server.pb.h"
24 #include "components/sync/protocol/sync.pb.h"
25 #include "net/http/http_status_code.h"
26 
27 namespace fake_server {
28 class FakeServer;
29 }
30 
31 namespace syncer {
32 
33 // A loopback version of the Sync server used for local profile serialization.
34 class LoopbackServer : public base::ImportantFileWriter::DataSerializer {
35  public:
36   class ObserverForTests {
37    public:
~ObserverForTests()38     virtual ~ObserverForTests() {}
39 
40     // Called after the server has processed a successful commit. The types
41     // updated as part of the commit are passed in |committed_model_types|.
42     virtual void OnCommit(const std::string& committer_invalidator_client_id,
43                           syncer::ModelTypeSet committed_model_types) = 0;
44 
45     // Called when a page URL is committed via SESSIONS and the user has
46     // enabled "history sync" in the settings UI (which is detected by verifying
47     // if TYPED_URLS is an enabled type, as part of the commit request).
48     virtual void OnHistoryCommit(const std::string& url) = 0;
49   };
50 
51   explicit LoopbackServer(const base::FilePath& persistent_file);
52   ~LoopbackServer() override;
53 
54   // Handles a /command POST (with the given |message|) to the server.
55   // |response| must not be null.
56   net::HttpStatusCode HandleCommand(
57       const sync_pb::ClientToServerMessage& message,
58       sync_pb::ClientToServerResponse* response);
59 
60   // Enables strong consistency model (i.e. server detects conflicts).
61   void EnableStrongConsistencyWithConflictDetectionModel();
62 
63   // Sets a maximum batch size for GetUpdates requests.
SetMaxGetUpdatesBatchSize(int batch_size)64   void SetMaxGetUpdatesBatchSize(int batch_size) {
65     max_get_updates_batch_size_ = batch_size;
66   }
67 
SetBagOfChipsForTesting(const sync_pb::ChipBag & bag_of_chips)68   void SetBagOfChipsForTesting(const sync_pb::ChipBag& bag_of_chips) {
69     bag_of_chips_ = bag_of_chips;
70   }
71 
TriggerMigrationForTesting(ModelTypeSet model_types)72   void TriggerMigrationForTesting(ModelTypeSet model_types) {
73     for (const ModelType type : model_types) {
74       ++migration_versions_[type];
75     }
76   }
77 
GetKeystoreKeysForTesting()78   const std::vector<std::vector<uint8_t>>& GetKeystoreKeysForTesting() const {
79     return keystore_keys_;
80   }
81 
82   void AddNewKeystoreKeyForTesting();
83 
SetThrottledTypesForTesting(ModelTypeSet model_types)84   void SetThrottledTypesForTesting(ModelTypeSet model_types) {
85     throttled_types_ = model_types;
86   }
87 
88  private:
89   // Allow the FakeServer decorator to inspect the internals of this class.
90   friend class fake_server::FakeServer;
91 
92   using EntityMap =
93       std::map<std::string, std::unique_ptr<LoopbackServerEntity>>;
94 
95   using ResponseTypeProvider =
96       base::RepeatingCallback<sync_pb::CommitResponse::ResponseType(
97           const LoopbackServerEntity& entity)>;
98 
99   // ImportantFileWriter::DataSerializer:
100   bool SerializeData(std::string* data) override;
101 
102   // Gets LoopbackServer ready for syncing.
103   void Init();
104 
105   // Processes a GetUpdates call.
106   bool HandleGetUpdatesRequest(const sync_pb::GetUpdatesMessage& get_updates,
107                                const std::string& store_birthday,
108                                const std::string& invalidator_client_id,
109                                sync_pb::GetUpdatesResponse* response,
110                                std::vector<ModelType>* datatypes_to_migrate);
111 
112   // Processes a Commit call.
113   bool HandleCommitRequest(const sync_pb::CommitMessage& message,
114                            const std::string& invalidator_client_id,
115                            sync_pb::CommitResponse* response,
116                            ModelTypeSet* throttled_datatypes_in_request);
117 
118   void ClearServerData();
119 
120   // Creates and saves a permanent folder for Bookmarks (e.g., Bookmark Bar).
121   bool CreatePermanentBookmarkFolder(const std::string& server_tag,
122                                      const std::string& name);
123 
124   // Inserts the default permanent items in |entities_|.
125   bool CreateDefaultPermanentItems();
126 
127   // Returns generated key which may contain any bytes (not necessarily UTF-8).
128   std::vector<uint8_t> GenerateNewKeystoreKey() const;
129 
130   // Saves a |entity| to |entities_|.
131   void SaveEntity(std::unique_ptr<LoopbackServerEntity> entity);
132 
133   // Commits a client-side SyncEntity to the server as a LoopbackServerEntity.
134   // The client that sent the commit is identified via |client_guid|. The
135   // parent ID string present in |client_entity| should be ignored in favor
136   // of |parent_id|. If the commit is successful, the entity's server ID string
137   // is returned and a new LoopbackServerEntity is saved in |entities_|.
138   std::string CommitEntity(
139       const sync_pb::SyncEntity& client_entity,
140       sync_pb::CommitResponse_EntryResponse* entry_response,
141       const std::string& client_guid,
142       const std::string& parent_id);
143 
144   // Populates |entry_response| based on the stored entity identified by
145   // |entity_id|. It is assumed that the entity identified by |entity_id| has
146   // already been stored using SaveEntity.
147   void BuildEntryResponseForSuccessfulCommit(
148       const std::string& entity_id,
149       sync_pb::CommitResponse_EntryResponse* entry_response);
150 
151   // Determines whether the SyncEntity with id_string |id| is a child of an
152   // entity with id_string |potential_parent_id|.
153   bool IsChild(const std::string& id, const std::string& potential_parent_id);
154 
155   // Creates and saves tombstones for all children of the entity with the given
156   // |parent_id|. A tombstone is not created for the entity itself.
157   void DeleteChildren(const std::string& parent_id);
158 
159   // Updates the |entity| to a new version and increments the version counter
160   // that the server uses to assign versions.
161   void UpdateEntityVersion(LoopbackServerEntity* entity);
162 
163   // Returns the store birthday.
164   std::string GetStoreBirthday() const;
165 
166   // Returns all entities stored by the server of the given |model_type|.
167   // Permanent entities are excluded. This method is only used in tests.
168   std::vector<sync_pb::SyncEntity> GetSyncEntitiesByModelType(
169       syncer::ModelType model_type);
170 
171   // Returns a list of permanent entities of the given |model_type|. This method
172   // is only used in tests.
173   std::vector<sync_pb::SyncEntity> GetPermanentSyncEntitiesByModelType(
174       syncer::ModelType model_type);
175 
176   // Creates a DicionaryValue representation of all entities present in the
177   // server. The dictionary keys are the strings generated by ModelTypeToString
178   // and the values are ListValues containing StringValue versions of entity
179   // names. Permanent entities are excluded. Used by test to verify the contents
180   // of the server state.
181   std::unique_ptr<base::DictionaryValue> GetEntitiesAsDictionaryValue();
182 
183   // Modifies the entity on the server with the given |id|. The entity's
184   // EntitySpecifics are replaced with |updated_specifics| and its version is
185   // updated to n+1. If the given |id| does not exist or the ModelType of
186   // |updated_specifics| does not match the entity, false is returned.
187   // Otherwise, true is returned to represent a successful modification.
188   //
189   // This method sometimes updates entity data beyond EntitySpecifics. For
190   // example, in the case of a bookmark, changing the BookmarkSpecifics title
191   // field will modify the top-level entity's name field.
192   // This method is only used in tests.
193   bool ModifyEntitySpecifics(const std::string& id,
194                              const sync_pb::EntitySpecifics& updated_specifics);
195 
196   // This method is only used in tests.
197   bool ModifyBookmarkEntity(const std::string& id,
198                             const std::string& parent_id,
199                             const sync_pb::EntitySpecifics& updated_specifics);
200 
201   // Use this callback to generate response types for entities. They will still
202   // be "committed" and stored as normal, this only affects the response type
203   // the client sees. This allows tests to still inspect what the client has
204   // done, although not as useful of a mechanism for multi client tests. Care
205   // should be taken when failing responses, as the client will go into
206   // exponential backoff, which can cause tests to be slow or time out.
207   // This method is only used in tests.
208   void OverrideResponseType(ResponseTypeProvider response_type_override);
209 
210   // Serializes the server state to |proto|.
211   void SerializeState(sync_pb::LoopbackServerProto* proto) const;
212 
213   // Populates the server state from |proto|. Returns true iff successful.
214   bool DeSerializeState(const sync_pb::LoopbackServerProto& proto);
215 
216   // Schedules committing state to disk at some later time. Repeat calls are
217   // batched together. Outstanding scheduled writes are committed at shutdown.
218   // Returns true on success.
219   bool ScheduleSaveStateToFile();
220 
221   // Loads all entities and server state from a protobuf file. Returns true on
222   // success.
223   bool LoadStateFromFile();
224 
set_observer_for_tests(ObserverForTests * observer)225   void set_observer_for_tests(ObserverForTests* observer) {
226     observer_for_tests_ = observer;
227   }
228 
229   bool strong_consistency_model_enabled_;
230 
231   // This is the last version number assigned to an entity. The next entity will
232   // have a version number of version_ + 1.
233   int64_t version_;
234 
235   int64_t store_birthday_;
236 
237   ModelTypeSet throttled_types_;
238 
239   base::Optional<sync_pb::ChipBag> bag_of_chips_;
240 
241   std::map<ModelType, int> migration_versions_;
242 
243   int max_get_updates_batch_size_ = 1000000;
244 
245   EntityMap entities_;
246   std::vector<std::vector<uint8_t>> keystore_keys_;
247 
248   // The file used to store the local sync data.
249   base::FilePath persistent_file_;
250 
251   // Used to limit the rate of file rewrites due to updates.
252   base::ImportantFileWriter writer_;
253 
254   // Used to verify that LoopbackServer is only used from one sequence.
255   SEQUENCE_CHECKER(sequence_checker_);
256 
257   // Used to observe the completion of commit messages for the sake of testing.
258   ObserverForTests* observer_for_tests_;
259 
260   // Response type override callback used in tests.
261   ResponseTypeProvider response_type_override_;
262 };
263 
264 }  // namespace syncer
265 
266 #endif  // COMPONENTS_SYNC_ENGINE_IMPL_LOOPBACK_SERVER_LOOPBACK_SERVER_H_
267