Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """An implementation of the server side of the Chromium sync protocol. | 5 """An implementation of the server side of the Chromium sync protocol. |
| 6 | 6 |
| 7 The details of the protocol are described mostly by comments in the protocol | 7 The details of the protocol are described mostly by comments in the protocol |
| 8 buffer definition at chrome/browser/sync/protocol/sync.proto. | 8 buffer definition at chrome/browser/sync/protocol/sync.proto. |
| 9 """ | 9 """ |
| 10 | 10 |
| 11 import cgi | 11 import cgi |
| 12 import copy | 12 import copy |
| 13 import operator | 13 import operator |
| 14 import pickle | 14 import pickle |
| 15 import random | 15 import random |
| 16 import string | |
| 16 import sys | 17 import sys |
| 17 import threading | 18 import threading |
| 18 import time | 19 import time |
| 19 import urlparse | 20 import urlparse |
| 20 | 21 |
| 21 import app_notification_specifics_pb2 | 22 import app_notification_specifics_pb2 |
| 22 import app_setting_specifics_pb2 | 23 import app_setting_specifics_pb2 |
| 23 import app_specifics_pb2 | 24 import app_specifics_pb2 |
| 24 import autofill_specifics_pb2 | 25 import autofill_specifics_pb2 |
| 25 import bookmark_specifics_pb2 | 26 import bookmark_specifics_pb2 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 90 TYPED_URL: SYNC_TYPE_FIELDS['typed_url'], | 91 TYPED_URL: SYNC_TYPE_FIELDS['typed_url'], |
| 91 } | 92 } |
| 92 | 93 |
| 93 # The parent ID used to indicate a top-level node. | 94 # The parent ID used to indicate a top-level node. |
| 94 ROOT_ID = '0' | 95 ROOT_ID = '0' |
| 95 | 96 |
| 96 # Unix time epoch in struct_time format. The tuple corresponds to UTC Wednesday | 97 # Unix time epoch in struct_time format. The tuple corresponds to UTC Wednesday |
| 97 # Jan 1 1970, 00:00:00, non-dst. | 98 # Jan 1 1970, 00:00:00, non-dst. |
| 98 UNIX_TIME_EPOCH = (1970, 1, 1, 0, 0, 0, 3, 1, 0) | 99 UNIX_TIME_EPOCH = (1970, 1, 1, 0, 0, 0, 3, 1, 0) |
| 99 | 100 |
| 101 # The number of characters in the server-generated encryption key. | |
| 102 KEYSTORE_KEY_LENGTH = 16 | |
| 103 | |
| 100 class Error(Exception): | 104 class Error(Exception): |
| 101 """Error class for this module.""" | 105 """Error class for this module.""" |
| 102 | 106 |
| 103 | 107 |
| 104 class ProtobufDataTypeFieldNotUnique(Error): | 108 class ProtobufDataTypeFieldNotUnique(Error): |
| 105 """An entry should not have more than one data type present.""" | 109 """An entry should not have more than one data type present.""" |
| 106 | 110 |
| 107 | 111 |
| 108 class DataTypeIdNotRecognized(Error): | 112 class DataTypeIdNotRecognized(Error): |
| 109 """The requested data type is not recognized.""" | 113 """The requested data type is not recognized.""" |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 461 self._entries = {} | 465 self._entries = {} |
| 462 | 466 |
| 463 self.ResetStoreBirthday() | 467 self.ResetStoreBirthday() |
| 464 | 468 |
| 465 self.migration_history = MigrationHistory() | 469 self.migration_history = MigrationHistory() |
| 466 | 470 |
| 467 self.induced_error = sync_pb2.ClientToServerResponse.Error() | 471 self.induced_error = sync_pb2.ClientToServerResponse.Error() |
| 468 self.induced_error_frequency = 0 | 472 self.induced_error_frequency = 0 |
| 469 self.sync_count_before_errors = 0 | 473 self.sync_count_before_errors = 0 |
| 470 | 474 |
| 475 self._key = ''.join(random.choice( | |
| 476 string.ascii_uppercase + string.digits) for x in range( | |
| 477 KEYSTORE_KEY_LENGTH)) | |
| 478 | |
| 471 def _SaveEntry(self, entry): | 479 def _SaveEntry(self, entry): |
| 472 """Insert or update an entry in the change log, and give it a new version. | 480 """Insert or update an entry in the change log, and give it a new version. |
| 473 | 481 |
| 474 The ID fields of this entry are assumed to be valid server IDs. This | 482 The ID fields of this entry are assumed to be valid server IDs. This |
| 475 entry will be updated with a new version number and sync_timestamp. | 483 entry will be updated with a new version number and sync_timestamp. |
| 476 | 484 |
| 477 Args: | 485 Args: |
| 478 entry: The entry to be added or updated. | 486 entry: The entry to be added or updated. |
| 479 """ | 487 """ |
| 480 self._version += 1 | 488 self._version += 1 |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 657 | 665 |
| 658 # Restrict batch to requested types. Tombstones are untyped | 666 # Restrict batch to requested types. Tombstones are untyped |
| 659 # and will always get included. | 667 # and will always get included. |
| 660 filtered = [copy.deepcopy(item) for item in batch | 668 filtered = [copy.deepcopy(item) for item in batch |
| 661 if item.deleted or sieve.ClientWantsItem(item)] | 669 if item.deleted or sieve.ClientWantsItem(item)] |
| 662 | 670 |
| 663 # The new client timestamp is the timestamp of the last item in the | 671 # The new client timestamp is the timestamp of the last item in the |
| 664 # batch, even if that item was filtered out. | 672 # batch, even if that item was filtered out. |
| 665 return (batch[-1].version, filtered, len(new_changes) - len(batch)) | 673 return (batch[-1].version, filtered, len(new_changes) - len(batch)) |
| 666 | 674 |
| 675 def GetKey(self): | |
|
tim (not reviewing)
2012/07/26 21:53:15
does anything use this?
Nicolas Zea
2012/07/27 00:43:15
Yes, in the HandleGetUpdates at the bottom of the
| |
| 676 """Returns the encryption key for this account.""" | |
| 677 print "Returning encryption key: %s" % self._key | |
| 678 return self._key | |
| 679 | |
| 667 def _CopyOverImmutableFields(self, entry): | 680 def _CopyOverImmutableFields(self, entry): |
| 668 """Preserve immutable fields by copying pre-commit state. | 681 """Preserve immutable fields by copying pre-commit state. |
| 669 | 682 |
| 670 Args: | 683 Args: |
| 671 entry: A sync entity from the client. | 684 entry: A sync entity from the client. |
| 672 """ | 685 """ |
| 673 if entry.id_string in self._entries: | 686 if entry.id_string in self._entries: |
| 674 if self._entries[entry.id_string].HasField( | 687 if self._entries[entry.id_string].HasField( |
| 675 'server_defined_unique_tag'): | 688 'server_defined_unique_tag'): |
| 676 entry.server_defined_unique_tag = ( | 689 entry.server_defined_unique_tag = ( |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1036 response = 'Could not interpret datatype name' | 1049 response = 'Could not interpret datatype name' |
| 1037 code = 400 | 1050 code = 400 |
| 1038 finally: | 1051 finally: |
| 1039 self.account_lock.release() | 1052 self.account_lock.release() |
| 1040 return (code, '<html><title>Migration: %d</title><H1>%d %s</H1></html>' % | 1053 return (code, '<html><title>Migration: %d</title><H1>%d %s</H1></html>' % |
| 1041 (code, code, response)) | 1054 (code, code, response)) |
| 1042 | 1055 |
| 1043 def HandleSetInducedError(self, path): | 1056 def HandleSetInducedError(self, path): |
| 1044 query = urlparse.urlparse(path)[4] | 1057 query = urlparse.urlparse(path)[4] |
| 1045 self.account_lock.acquire() | 1058 self.account_lock.acquire() |
| 1046 code = 200; | 1059 code = 200 |
| 1047 response = 'Success' | 1060 response = 'Success' |
| 1048 error = sync_pb2.ClientToServerResponse.Error() | 1061 error = sync_pb2.ClientToServerResponse.Error() |
| 1049 try: | 1062 try: |
| 1050 error_type = urlparse.parse_qs(query)['error'] | 1063 error_type = urlparse.parse_qs(query)['error'] |
| 1051 action = urlparse.parse_qs(query)['action'] | 1064 action = urlparse.parse_qs(query)['action'] |
| 1052 error.error_type = int(error_type[0]) | 1065 error.error_type = int(error_type[0]) |
| 1053 error.action = int(action[0]) | 1066 error.action = int(action[0]) |
| 1054 try: | 1067 try: |
| 1055 error.url = (urlparse.parse_qs(query)['url'])[0] | 1068 error.url = (urlparse.parse_qs(query)['url'])[0] |
| 1056 except KeyError: | 1069 except KeyError: |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1125 | 1138 |
| 1126 try: | 1139 try: |
| 1127 request = sync_pb2.ClientToServerMessage() | 1140 request = sync_pb2.ClientToServerMessage() |
| 1128 request.MergeFromString(raw_request) | 1141 request.MergeFromString(raw_request) |
| 1129 contents = request.message_contents | 1142 contents = request.message_contents |
| 1130 | 1143 |
| 1131 response = sync_pb2.ClientToServerResponse() | 1144 response = sync_pb2.ClientToServerResponse() |
| 1132 response.error_code = sync_enums_pb2.SyncEnums.SUCCESS | 1145 response.error_code = sync_enums_pb2.SyncEnums.SUCCESS |
| 1133 self.CheckStoreBirthday(request) | 1146 self.CheckStoreBirthday(request) |
| 1134 response.store_birthday = self.account.store_birthday | 1147 response.store_birthday = self.account.store_birthday |
| 1135 self.CheckTransientError(); | 1148 self.CheckTransientError() |
| 1136 self.CheckSendError(); | 1149 self.CheckSendError() |
| 1137 | 1150 |
| 1138 print_context('->') | 1151 print_context('->') |
| 1139 | 1152 |
| 1140 if contents == sync_pb2.ClientToServerMessage.AUTHENTICATE: | 1153 if contents == sync_pb2.ClientToServerMessage.AUTHENTICATE: |
| 1141 print 'Authenticate' | 1154 print 'Authenticate' |
| 1142 # We accept any authentication token, and support only one account. | 1155 # We accept any authentication token, and support only one account. |
| 1143 # TODO(nick): Mock out the GAIA authentication as well; hook up here. | 1156 # TODO(nick): Mock out the GAIA authentication as well; hook up here. |
| 1144 response.authenticate.user.email = 'syncjuser@chromium' | 1157 response.authenticate.user.email = 'syncjuser@chromium' |
| 1145 response.authenticate.user.display_name = 'Sync J User' | 1158 response.authenticate.user.display_name = 'Sync J User' |
| 1146 elif contents == sync_pb2.ClientToServerMessage.COMMIT: | 1159 elif contents == sync_pb2.ClientToServerMessage.COMMIT: |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1255 | 1268 |
| 1256 update_sieve.CheckMigrationState() | 1269 update_sieve.CheckMigrationState() |
| 1257 | 1270 |
| 1258 new_timestamp, entries, remaining = self.account.GetChanges(update_sieve) | 1271 new_timestamp, entries, remaining = self.account.GetChanges(update_sieve) |
| 1259 | 1272 |
| 1260 update_response.changes_remaining = remaining | 1273 update_response.changes_remaining = remaining |
| 1261 for entry in entries: | 1274 for entry in entries: |
| 1262 reply = update_response.entries.add() | 1275 reply = update_response.entries.add() |
| 1263 reply.CopyFrom(entry) | 1276 reply.CopyFrom(entry) |
| 1264 update_sieve.SaveProgress(new_timestamp, update_response) | 1277 update_sieve.SaveProgress(new_timestamp, update_response) |
| 1278 | |
| 1279 if update_request.need_encryption_key: | |
| 1280 update_response.encryption_key = self.account.GetKey() | |
| OLD | NEW |