Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python2.4 | 1 #!/usr/bin/python2.4 |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """An implementation of the server side of the Chromium sync protocol. | 6 """An implementation of the server side of the Chromium sync protocol. |
| 7 | 7 |
| 8 The details of the protocol are described mostly by comments in the protocol | 8 The details of the protocol are described mostly by comments in the protocol |
| 9 buffer definition at chrome/browser/sync/protocol/sync.proto. | 9 buffer definition at chrome/browser/sync/protocol/sync.proto. |
| 10 """ | 10 """ |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 98 | 98 |
| 99 | 99 |
| 100 class StoreBirthdayError(Error): | 100 class StoreBirthdayError(Error): |
| 101 """The client sent a birthday that doesn't correspond to this server.""" | 101 """The client sent a birthday that doesn't correspond to this server.""" |
| 102 | 102 |
| 103 | 103 |
| 104 class TransientError(Error): | 104 class TransientError(Error): |
| 105 """The client would be sent a transient error.""" | 105 """The client would be sent a transient error.""" |
| 106 | 106 |
| 107 | 107 |
| 108 class SyncInducedError(Error): | |
| 109 """The client would be sent an error.""" | |
| 110 | |
| 111 | |
| 108 def GetEntryType(entry): | 112 def GetEntryType(entry): |
| 109 """Extract the sync type from a SyncEntry. | 113 """Extract the sync type from a SyncEntry. |
| 110 | 114 |
| 111 Args: | 115 Args: |
| 112 entry: A SyncEntity protobuf object whose type to determine. | 116 entry: A SyncEntity protobuf object whose type to determine. |
| 113 Returns: | 117 Returns: |
| 114 An enum value from ALL_TYPES if the entry's type can be determined, or None | 118 An enum value from ALL_TYPES if the entry's type can be determined, or None |
| 115 if the type cannot be determined. | 119 if the type cannot be determined. |
| 116 Raises: | 120 Raises: |
| 117 ProtobufExtensionNotUnique: More than one type was indicated by the entry. | 121 ProtobufExtensionNotUnique: More than one type was indicated by the entry. |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 408 self._version = 0 | 412 self._version = 0 |
| 409 | 413 |
| 410 # The definitive copy of this client's items: a map from ID string to a | 414 # The definitive copy of this client's items: a map from ID string to a |
| 411 # SyncEntity protocol buffer. | 415 # SyncEntity protocol buffer. |
| 412 self._entries = {} | 416 self._entries = {} |
| 413 | 417 |
| 414 self.ResetStoreBirthday() | 418 self.ResetStoreBirthday() |
| 415 | 419 |
| 416 self.migration_history = MigrationHistory() | 420 self.migration_history = MigrationHistory() |
| 417 | 421 |
| 422 self.induced_error = sync_pb2.ClientToServerResponse.Error() | |
| 423 | |
| 418 def _SaveEntry(self, entry): | 424 def _SaveEntry(self, entry): |
| 419 """Insert or update an entry in the change log, and give it a new version. | 425 """Insert or update an entry in the change log, and give it a new version. |
| 420 | 426 |
| 421 The ID fields of this entry are assumed to be valid server IDs. This | 427 The ID fields of this entry are assumed to be valid server IDs. This |
| 422 entry will be updated with a new version number and sync_timestamp. | 428 entry will be updated with a new version number and sync_timestamp. |
| 423 | 429 |
| 424 Args: | 430 Args: |
| 425 entry: The entry to be added or updated. | 431 entry: The entry to be added or updated. |
| 426 """ | 432 """ |
| 427 self._version += 1 | 433 self._version += 1 |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 873 nigori_tag = "google_chrome_nigori" | 879 nigori_tag = "google_chrome_nigori" |
| 874 nigori_original = self._entries.get(self._ServerTagToId(nigori_tag)) | 880 nigori_original = self._entries.get(self._ServerTagToId(nigori_tag)) |
| 875 if (nigori_original.specifics.Extensions[nigori_specifics_pb2.nigori]. | 881 if (nigori_original.specifics.Extensions[nigori_specifics_pb2.nigori]. |
| 876 sync_tabs): | 882 sync_tabs): |
| 877 return | 883 return |
| 878 nigori_new = copy.deepcopy(nigori_original) | 884 nigori_new = copy.deepcopy(nigori_original) |
| 879 nigori_new.specifics.Extensions[nigori_specifics_pb2.nigori].sync_tabs = ( | 885 nigori_new.specifics.Extensions[nigori_specifics_pb2.nigori].sync_tabs = ( |
| 880 True) | 886 True) |
| 881 self._SaveEntry(nigori_new) | 887 self._SaveEntry(nigori_new) |
| 882 | 888 |
| 889 def SetInducedError(self, error): | |
| 890 self.induced_error = error | |
| 891 | |
| 892 def GetInducedError(self): | |
| 893 return self.induced_error | |
| 894 | |
| 883 | 895 |
| 884 class TestServer(object): | 896 class TestServer(object): |
| 885 """An object to handle requests for one (and only one) Chrome Sync account. | 897 """An object to handle requests for one (and only one) Chrome Sync account. |
| 886 | 898 |
| 887 TestServer consumes the sync command messages that are the outermost | 899 TestServer consumes the sync command messages that are the outermost |
| 888 layers of the protocol, performs the corresponding actions on its | 900 layers of the protocol, performs the corresponding actions on its |
| 889 SyncDataModel, and constructs an appropropriate response message. | 901 SyncDataModel, and constructs an appropropriate response message. |
| 890 """ | 902 """ |
| 891 | 903 |
| 892 def __init__(self): | 904 def __init__(self): |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 915 if not request.HasField('store_birthday'): | 927 if not request.HasField('store_birthday'): |
| 916 return | 928 return |
| 917 if self.account.StoreBirthday() != request.store_birthday: | 929 if self.account.StoreBirthday() != request.store_birthday: |
| 918 raise StoreBirthdayError | 930 raise StoreBirthdayError |
| 919 | 931 |
| 920 def CheckTransientError(self): | 932 def CheckTransientError(self): |
| 921 """Raises TransientError if transient_error variable is set.""" | 933 """Raises TransientError if transient_error variable is set.""" |
| 922 if self.transient_error: | 934 if self.transient_error: |
| 923 raise TransientError | 935 raise TransientError |
| 924 | 936 |
| 937 def CheckSendError(self): | |
| 938 """Raises SyncInducedError if needed.""" | |
| 939 if self.account.induced_error.error_type !=\ | |
| 940 sync_pb2.ClientToServerResponse.UNKNOWN: | |
| 941 raise SyncInducedError | |
| 942 | |
| 925 def HandleMigrate(self, path): | 943 def HandleMigrate(self, path): |
| 926 query = urlparse.urlparse(path)[4] | 944 query = urlparse.urlparse(path)[4] |
| 927 code = 200 | 945 code = 200 |
| 928 self.account_lock.acquire() | 946 self.account_lock.acquire() |
| 929 try: | 947 try: |
| 930 datatypes = [DataTypeStringToSyncTypeLoose(x) | 948 datatypes = [DataTypeStringToSyncTypeLoose(x) |
| 931 for x in urlparse.parse_qs(query).get('type',[])] | 949 for x in urlparse.parse_qs(query).get('type',[])] |
| 932 if datatypes: | 950 if datatypes: |
| 933 self.account.TriggerMigration(datatypes) | 951 self.account.TriggerMigration(datatypes) |
| 934 response = 'Migrated datatypes %s' % ( | 952 response = 'Migrated datatypes %s' % ( |
| 935 ' and '.join(SyncTypeToString(x).upper() for x in datatypes)) | 953 ' and '.join(SyncTypeToString(x).upper() for x in datatypes)) |
| 936 else: | 954 else: |
| 937 response = 'Please specify one or more <i>type=name</i> parameters' | 955 response = 'Please specify one or more <i>type=name</i> parameters' |
| 938 code = 400 | 956 code = 400 |
| 939 except DataTypeIdNotRecognized, error: | 957 except DataTypeIdNotRecognized, error: |
| 940 response = 'Could not interpret datatype name' | 958 response = 'Could not interpret datatype name' |
| 941 code = 400 | 959 code = 400 |
| 942 finally: | 960 finally: |
| 943 self.account_lock.release() | 961 self.account_lock.release() |
| 944 return (code, '<html><title>Migration: %d</title><H1>%d %s</H1></html>' % | 962 return (code, '<html><title>Migration: %d</title><H1>%d %s</H1></html>' % |
| 945 (code, code, response)) | 963 (code, code, response)) |
| 946 | 964 |
| 965 def HandleSetInducedError(self, path): | |
| 966 query = urlparse.urlparse(path)[4] | |
| 967 self.account_lock.acquire() | |
| 968 code = 200; | |
| 969 response = 'Success' | |
| 970 error = sync_pb2.ClientToServerResponse.Error() | |
| 971 try: | |
| 972 error_type = urlparse.parse_qs(query)['error'] | |
| 973 action = urlparse.parse_qs(query)['action'] | |
| 974 error.error_type = int(error_type[0]) | |
| 975 error.action = int(action[0]) | |
| 976 try: | |
| 977 error.url = (urlparse.parse_qs(query)['url'])[0] | |
| 978 except KeyError: | |
| 979 error.url = '' | |
| 980 try: | |
| 981 error.error_description = \ | |
| 982 (urlparse.parse_qs(query)['error_description'])[0] | |
| 983 except KeyError: | |
| 984 error.error_description = '' | |
| 985 self.account.SetInducedError(error) | |
| 986 response = ('Error = %d, action = %d, url = %s, description = %s' % | |
| 987 (error.error_type, error.action, | |
| 988 error.url, | |
| 989 error.error_description)) | |
| 990 except error: | |
| 991 response = 'Could not parse url' | |
| 992 code = 400 | |
| 993 finally: | |
| 994 self.account_lock.release() | |
| 995 return (code, '<html><title>SetError: %d</title><H1>%d %s</H1></html>' % | |
| 996 (code, code, response)) | |
| 997 | |
| 947 def HandleCreateBirthdayError(self): | 998 def HandleCreateBirthdayError(self): |
| 948 self.account.ResetStoreBirthday() | 999 self.account.ResetStoreBirthday() |
| 949 return ( | 1000 return ( |
| 950 200, | 1001 200, |
| 951 '<html><title>Birthday error</title><H1>Birthday error</H1></html>') | 1002 '<html><title>Birthday error</title><H1>Birthday error</H1></html>') |
| 952 | 1003 |
| 953 def HandleSetTransientError(self): | 1004 def HandleSetTransientError(self): |
| 954 self.transient_error = True | 1005 self.transient_error = True |
| 955 return ( | 1006 return ( |
| 956 200, | 1007 200, |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 985 try: | 1036 try: |
| 986 request = sync_pb2.ClientToServerMessage() | 1037 request = sync_pb2.ClientToServerMessage() |
| 987 request.MergeFromString(raw_request) | 1038 request.MergeFromString(raw_request) |
| 988 contents = request.message_contents | 1039 contents = request.message_contents |
| 989 | 1040 |
| 990 response = sync_pb2.ClientToServerResponse() | 1041 response = sync_pb2.ClientToServerResponse() |
| 991 response.error_code = sync_pb2.ClientToServerResponse.SUCCESS | 1042 response.error_code = sync_pb2.ClientToServerResponse.SUCCESS |
| 992 self.CheckStoreBirthday(request) | 1043 self.CheckStoreBirthday(request) |
| 993 response.store_birthday = self.account.store_birthday | 1044 response.store_birthday = self.account.store_birthday |
| 994 self.CheckTransientError(); | 1045 self.CheckTransientError(); |
| 1046 self.CheckSendError(); | |
| 995 | 1047 |
| 996 print_context('->') | 1048 print_context('->') |
| 997 | 1049 |
| 998 if contents == sync_pb2.ClientToServerMessage.AUTHENTICATE: | 1050 if contents == sync_pb2.ClientToServerMessage.AUTHENTICATE: |
| 999 print 'Authenticate' | 1051 print 'Authenticate' |
| 1000 # We accept any authentication token, and support only one account. | 1052 # We accept any authentication token, and support only one account. |
| 1001 # TODO(nick): Mock out the GAIA authentication as well; hook up here. | 1053 # TODO(nick): Mock out the GAIA authentication as well; hook up here. |
| 1002 response.authenticate.user.email = 'syncjuser@chromium' | 1054 response.authenticate.user.email = 'syncjuser@chromium' |
| 1003 response.authenticate.user.display_name = 'Sync J User' | 1055 response.authenticate.user.display_name = 'Sync J User' |
| 1004 elif contents == sync_pb2.ClientToServerMessage.COMMIT: | 1056 elif contents == sync_pb2.ClientToServerMessage.COMMIT: |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 1023 SyncTypeToProtocolDataTypeId(x) for x in error.datatypes] | 1075 SyncTypeToProtocolDataTypeId(x) for x in error.datatypes] |
| 1024 return (200, response.SerializeToString()) | 1076 return (200, response.SerializeToString()) |
| 1025 except StoreBirthdayError, error: | 1077 except StoreBirthdayError, error: |
| 1026 print_context('<-') | 1078 print_context('<-') |
| 1027 print 'NOT_MY_BIRTHDAY' | 1079 print 'NOT_MY_BIRTHDAY' |
| 1028 response = sync_pb2.ClientToServerResponse() | 1080 response = sync_pb2.ClientToServerResponse() |
| 1029 response.store_birthday = self.account.store_birthday | 1081 response.store_birthday = self.account.store_birthday |
| 1030 response.error_code = sync_pb2.ClientToServerResponse.NOT_MY_BIRTHDAY | 1082 response.error_code = sync_pb2.ClientToServerResponse.NOT_MY_BIRTHDAY |
| 1031 return (200, response.SerializeToString()) | 1083 return (200, response.SerializeToString()) |
| 1032 except TransientError, error: | 1084 except TransientError, error: |
| 1085 ### This is deprecated now. Would be remvoved once test cases are removed. | |
|
Raghu Simha
2011/09/22 21:57:41
This comment still doesn't follow the style guide.
| |
| 1033 print_context('<-') | 1086 print_context('<-') |
| 1034 print 'TRANSIENT_ERROR' | 1087 print 'TRANSIENT_ERROR' |
| 1035 response.store_birthday = self.account.store_birthday | 1088 response.store_birthday = self.account.store_birthday |
| 1036 response.error_code = sync_pb2.ClientToServerResponse.TRANSIENT_ERROR | 1089 response.error_code = sync_pb2.ClientToServerResponse.TRANSIENT_ERROR |
| 1037 return (200, response.SerializeToString()) | 1090 return (200, response.SerializeToString()) |
| 1091 except SyncInducedError, error: | |
| 1092 print_context('<-') | |
| 1093 print 'INDUCED_ERROR' | |
| 1094 response.store_birthday = self.account.store_birthday | |
| 1095 error = self.account.GetInducedError() | |
| 1096 response.error.error_type = error.error_type | |
| 1097 response.error.url = error.url | |
| 1098 response.error.error_description = error.error_description | |
| 1099 response.error.action = error.action | |
| 1100 return (200, response.SerializeToString()) | |
| 1038 finally: | 1101 finally: |
| 1039 self.account_lock.release() | 1102 self.account_lock.release() |
| 1040 | 1103 |
| 1041 def HandleCommit(self, commit_message, commit_response): | 1104 def HandleCommit(self, commit_message, commit_response): |
| 1042 """Respond to a Commit request by updating the user's account state. | 1105 """Respond to a Commit request by updating the user's account state. |
| 1043 | 1106 |
| 1044 Commit attempts stop after the first error, returning a CONFLICT result | 1107 Commit attempts stop after the first error, returning a CONFLICT result |
| 1045 for any unattempted entries. | 1108 for any unattempted entries. |
| 1046 | 1109 |
| 1047 Args: | 1110 Args: |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1102 | 1165 |
| 1103 update_sieve.CheckMigrationState() | 1166 update_sieve.CheckMigrationState() |
| 1104 | 1167 |
| 1105 new_timestamp, entries, remaining = self.account.GetChanges(update_sieve) | 1168 new_timestamp, entries, remaining = self.account.GetChanges(update_sieve) |
| 1106 | 1169 |
| 1107 update_response.changes_remaining = remaining | 1170 update_response.changes_remaining = remaining |
| 1108 for entry in entries: | 1171 for entry in entries: |
| 1109 reply = update_response.entries.add() | 1172 reply = update_response.entries.add() |
| 1110 reply.CopyFrom(entry) | 1173 reply.CopyFrom(entry) |
| 1111 update_sieve.SaveProgress(new_timestamp, update_response) | 1174 update_sieve.SaveProgress(new_timestamp, update_response) |
| OLD | NEW |