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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 self.datatypes = datatypes | 97 self.datatypes = datatypes |
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 class SyncError(Error): | |
108 """The client would be sent an error.""" | |
109 | |
107 | 110 |
108 def GetEntryType(entry): | 111 def GetEntryType(entry): |
109 """Extract the sync type from a SyncEntry. | 112 """Extract the sync type from a SyncEntry. |
110 | 113 |
111 Args: | 114 Args: |
112 entry: A SyncEntity protobuf object whose type to determine. | 115 entry: A SyncEntity protobuf object whose type to determine. |
113 Returns: | 116 Returns: |
114 An enum value from ALL_TYPES if the entry's type can be determined, or None | 117 An enum value from ALL_TYPES if the entry's type can be determined, or None |
115 if the type cannot be determined. | 118 if the type cannot be determined. |
116 Raises: | 119 Raises: |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
408 self._version = 0 | 411 self._version = 0 |
409 | 412 |
410 # The definitive copy of this client's items: a map from ID string to a | 413 # The definitive copy of this client's items: a map from ID string to a |
411 # SyncEntity protocol buffer. | 414 # SyncEntity protocol buffer. |
412 self._entries = {} | 415 self._entries = {} |
413 | 416 |
414 self.ResetStoreBirthday() | 417 self.ResetStoreBirthday() |
415 | 418 |
416 self.migration_history = MigrationHistory() | 419 self.migration_history = MigrationHistory() |
417 | 420 |
421 self.error = sync_pb2.ClientToServerResponse.Error() | |
422 | |
423 self.send_error = False | |
424 | |
418 def _SaveEntry(self, entry): | 425 def _SaveEntry(self, entry): |
419 """Insert or update an entry in the change log, and give it a new version. | 426 """Insert or update an entry in the change log, and give it a new version. |
420 | 427 |
421 The ID fields of this entry are assumed to be valid server IDs. This | 428 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. | 429 entry will be updated with a new version number and sync_timestamp. |
423 | 430 |
424 Args: | 431 Args: |
425 entry: The entry to be added or updated. | 432 entry: The entry to be added or updated. |
426 """ | 433 """ |
427 self._version += 1 | 434 self._version += 1 |
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
915 if not request.HasField('store_birthday'): | 922 if not request.HasField('store_birthday'): |
916 return | 923 return |
917 if self.account.StoreBirthday() != request.store_birthday: | 924 if self.account.StoreBirthday() != request.store_birthday: |
918 raise StoreBirthdayError | 925 raise StoreBirthdayError |
919 | 926 |
920 def CheckTransientError(self): | 927 def CheckTransientError(self): |
921 """Raises TransientError if transient_error variable is set.""" | 928 """Raises TransientError if transient_error variable is set.""" |
922 if self.transient_error: | 929 if self.transient_error: |
923 raise TransientError | 930 raise TransientError |
924 | 931 |
932 def CheckSendError(self): | |
933 """Raises SyncError if the variable is set.""" | |
934 if self.account.send_error: | |
935 raise SyncError | |
936 | |
925 def HandleMigrate(self, path): | 937 def HandleMigrate(self, path): |
926 query = urlparse.urlparse(path)[4] | 938 query = urlparse.urlparse(path)[4] |
927 code = 200 | 939 code = 200 |
928 self.account_lock.acquire() | 940 self.account_lock.acquire() |
929 try: | 941 try: |
930 datatypes = [DataTypeStringToSyncTypeLoose(x) | 942 datatypes = [DataTypeStringToSyncTypeLoose(x) |
931 for x in urlparse.parse_qs(query).get('type',[])] | 943 for x in urlparse.parse_qs(query).get('type',[])] |
932 if datatypes: | 944 if datatypes: |
933 self.account.TriggerMigration(datatypes) | 945 self.account.TriggerMigration(datatypes) |
934 response = 'Migrated datatypes %s' % ( | 946 response = 'Migrated datatypes %s' % ( |
935 ' and '.join(SyncTypeToString(x).upper() for x in datatypes)) | 947 ' and '.join(SyncTypeToString(x).upper() for x in datatypes)) |
936 else: | 948 else: |
937 response = 'Please specify one or more <i>type=name</i> parameters' | 949 response = 'Please specify one or more <i>type=name</i> parameters' |
938 code = 400 | 950 code = 400 |
939 except DataTypeIdNotRecognized, error: | 951 except DataTypeIdNotRecognized, error: |
940 response = 'Could not interpret datatype name' | 952 response = 'Could not interpret datatype name' |
941 code = 400 | 953 code = 400 |
942 finally: | 954 finally: |
943 self.account_lock.release() | 955 self.account_lock.release() |
944 return (code, '<html><title>Migration: %d</title><H1>%d %s</H1></html>' % | 956 return (code, '<html><title>Migration: %d</title><H1>%d %s</H1></html>' % |
945 (code, code, response)) | 957 (code, code, response)) |
946 | 958 |
959 def HandleSetError(self, path): | |
960 query = urlparse.urlparse(path)[4] | |
961 self.account_lock.acquire() | |
962 code = 200; | |
963 response = 'Success' | |
964 try: | |
965 error_type = urlparse.parse_qs(query)['error'] | |
966 action = urlparse.parse_qs(query)['action'] | |
967 self.account.error.error_type = int(error_type[0]) | |
968 self.account.error.action = int(action[0]) | |
969 self.account.send_error = True | |
970 try: | |
971 self.account.error.url = (urlparse.parse_qs(query)['url'])[0] | |
972 except KeyError: | |
973 self.account.error.url = '' | |
974 try: | |
975 self.account.error.error_description = \ | |
976 (urlparse.parse_qs(query)['error_description'])[0] | |
977 except KeyError: | |
978 self.account.error.error_description = '' | |
979 response = ('Error = %d, action = %d, url = %s, description = %s' % | |
980 (self.account.error.error_type, self.account.error.action, | |
981 self.account.error.url, | |
982 self.account.error.error_description)) | |
983 except error: | |
984 response = 'Could not parse url' | |
985 code = 400 | |
986 finally: | |
987 self.account_lock.release() | |
988 return (code, '<html><title>SetError: %d</title><H1>%d %s</H1></html>' % | |
989 (code, code, response)) | |
990 | |
947 def HandleCreateBirthdayError(self): | 991 def HandleCreateBirthdayError(self): |
948 self.account.ResetStoreBirthday() | 992 self.account.ResetStoreBirthday() |
949 return ( | 993 return ( |
950 200, | 994 200, |
951 '<html><title>Birthday error</title><H1>Birthday error</H1></html>') | 995 '<html><title>Birthday error</title><H1>Birthday error</H1></html>') |
952 | 996 |
953 def HandleSetTransientError(self): | 997 def HandleSetTransientError(self): |
954 self.transient_error = True | 998 self.transient_error = True |
955 return ( | 999 return ( |
956 200, | 1000 200, |
(...skipping 28 matching lines...) Expand all Loading... | |
985 try: | 1029 try: |
986 request = sync_pb2.ClientToServerMessage() | 1030 request = sync_pb2.ClientToServerMessage() |
987 request.MergeFromString(raw_request) | 1031 request.MergeFromString(raw_request) |
988 contents = request.message_contents | 1032 contents = request.message_contents |
989 | 1033 |
990 response = sync_pb2.ClientToServerResponse() | 1034 response = sync_pb2.ClientToServerResponse() |
991 response.error_code = sync_pb2.ClientToServerResponse.SUCCESS | 1035 response.error_code = sync_pb2.ClientToServerResponse.SUCCESS |
992 self.CheckStoreBirthday(request) | 1036 self.CheckStoreBirthday(request) |
993 response.store_birthday = self.account.store_birthday | 1037 response.store_birthday = self.account.store_birthday |
994 self.CheckTransientError(); | 1038 self.CheckTransientError(); |
1039 self.CheckSendError(); | |
995 | 1040 |
996 print_context('->') | 1041 print_context('->') |
997 | 1042 |
998 if contents == sync_pb2.ClientToServerMessage.AUTHENTICATE: | 1043 if contents == sync_pb2.ClientToServerMessage.AUTHENTICATE: |
999 print 'Authenticate' | 1044 print 'Authenticate' |
1000 # We accept any authentication token, and support only one account. | 1045 # We accept any authentication token, and support only one account. |
1001 # TODO(nick): Mock out the GAIA authentication as well; hook up here. | 1046 # TODO(nick): Mock out the GAIA authentication as well; hook up here. |
1002 response.authenticate.user.email = 'syncjuser@chromium' | 1047 response.authenticate.user.email = 'syncjuser@chromium' |
1003 response.authenticate.user.display_name = 'Sync J User' | 1048 response.authenticate.user.display_name = 'Sync J User' |
1004 elif contents == sync_pb2.ClientToServerMessage.COMMIT: | 1049 elif contents == sync_pb2.ClientToServerMessage.COMMIT: |
(...skipping 18 matching lines...) Expand all Loading... | |
1023 SyncTypeToProtocolDataTypeId(x) for x in error.datatypes] | 1068 SyncTypeToProtocolDataTypeId(x) for x in error.datatypes] |
1024 return (200, response.SerializeToString()) | 1069 return (200, response.SerializeToString()) |
1025 except StoreBirthdayError, error: | 1070 except StoreBirthdayError, error: |
1026 print_context('<-') | 1071 print_context('<-') |
1027 print 'NOT_MY_BIRTHDAY' | 1072 print 'NOT_MY_BIRTHDAY' |
1028 response = sync_pb2.ClientToServerResponse() | 1073 response = sync_pb2.ClientToServerResponse() |
1029 response.store_birthday = self.account.store_birthday | 1074 response.store_birthday = self.account.store_birthday |
1030 response.error_code = sync_pb2.ClientToServerResponse.NOT_MY_BIRTHDAY | 1075 response.error_code = sync_pb2.ClientToServerResponse.NOT_MY_BIRTHDAY |
1031 return (200, response.SerializeToString()) | 1076 return (200, response.SerializeToString()) |
1032 except TransientError, error: | 1077 except TransientError, error: |
1078 ### This is deprecated now. Would be remvoved once test cases are removed. | |
Raghu Simha
2011/09/19 22:25:02
I think the Python style guide recommends a single
lipalani1
2011/09/22 20:42:46
Incorrectly ended up in this cl. removed.
On 2011/
Raghu Simha
2011/09/22 21:15:10
My bad -- looks like this came in from a different
| |
1033 print_context('<-') | 1079 print_context('<-') |
1034 print 'TRANSIENT_ERROR' | 1080 print 'TRANSIENT_ERROR' |
1035 response.store_birthday = self.account.store_birthday | 1081 response.store_birthday = self.account.store_birthday |
1036 response.error_code = sync_pb2.ClientToServerResponse.TRANSIENT_ERROR | 1082 response.error_code = sync_pb2.ClientToServerResponse.TRANSIENT_ERROR |
1037 return (200, response.SerializeToString()) | 1083 return (200, response.SerializeToString()) |
1084 except SyncError, error: | |
1085 print_context('<-') | |
1086 print 'ERROR' | |
1087 response.store_birthday = self.account.store_birthday | |
1088 response.error.error_type = self.account.error.error_type | |
1089 response.error.url = self.account.error.url | |
1090 response.error.error_description = self.account.error.error_description | |
1091 response.error.action = self.account.error.action | |
1092 return (200, response.SerializeToString()) | |
1038 finally: | 1093 finally: |
1039 self.account_lock.release() | 1094 self.account_lock.release() |
1040 | 1095 |
1041 def HandleCommit(self, commit_message, commit_response): | 1096 def HandleCommit(self, commit_message, commit_response): |
1042 """Respond to a Commit request by updating the user's account state. | 1097 """Respond to a Commit request by updating the user's account state. |
1043 | 1098 |
1044 Commit attempts stop after the first error, returning a CONFLICT result | 1099 Commit attempts stop after the first error, returning a CONFLICT result |
1045 for any unattempted entries. | 1100 for any unattempted entries. |
1046 | 1101 |
1047 Args: | 1102 Args: |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1102 | 1157 |
1103 update_sieve.CheckMigrationState() | 1158 update_sieve.CheckMigrationState() |
1104 | 1159 |
1105 new_timestamp, entries, remaining = self.account.GetChanges(update_sieve) | 1160 new_timestamp, entries, remaining = self.account.GetChanges(update_sieve) |
1106 | 1161 |
1107 update_response.changes_remaining = remaining | 1162 update_response.changes_remaining = remaining |
1108 for entry in entries: | 1163 for entry in entries: |
1109 reply = update_response.entries.add() | 1164 reply = update_response.entries.add() |
1110 reply.CopyFrom(entry) | 1165 reply.CopyFrom(entry) |
1111 update_sieve.SaveProgress(new_timestamp, update_response) | 1166 update_sieve.SaveProgress(new_timestamp, update_response) |
OLD | NEW |