@@ -135,7 +135,8 @@ def calculate_etag (node, classname="Missing", id="0"):
135135 etag = md5 (bs2b (repr (sorted (items )))).hexdigest ()
136136 logger .debug ("object=%s%s; tag=%s; repr=%s" , classname , id ,
137137 etag , repr (node .items (protected = True )))
138- return etag
138+ # Quotes are part of ETag spec, normal headers don't have quotes
139+ return '"%s"' % etag
139140
140141def check_etag (node , etags , classname = "Missing" , id = "0" ):
141142 '''Take a list of etags and compare to the etag for the given node.
@@ -151,7 +152,7 @@ def check_etag (node, etags, classname="Missing", id="0"):
151152 node_etag = calculate_etag (node , classname , id )
152153
153154 for etag in etags :
154- if etag != None :
155+ if etag is not None :
155156 if etag != node_etag :
156157 return False
157158 have_etag_match = True
@@ -166,7 +167,7 @@ def obtain_etags(headers,input):
166167 etags = []
167168 if '@etag' in input :
168169 etags .append (input ['@etag' ].value );
169- etags .append (headers .get ("ETag " , None ))
170+ etags .append (headers .get ("If-Match " , None ))
170171 return etags
171172
172173def parse_accept_header (accept ):
@@ -459,6 +460,16 @@ def patch_data(self, op, old_val, new_val):
459460
460461 return result
461462
463+ def raise_if_no_etag (self , class_name , item_id , input ):
464+ class_obj = self .db .getclass (class_name )
465+ if not check_etag (class_obj .getnode (item_id ),
466+ obtain_etags (self .client .request .headers , input ),
467+ class_name ,
468+ item_id ):
469+ raise PreconditionFailed (
470+ "If-Match is missing or does not match."
471+ " Retrieve asset and retry modification if valid." )
472+
462473 @Routing .route ("/data/<:class_name>" , 'GET' )
463474 @_data_decorator
464475 def get_collection (self , class_name , input ):
@@ -669,7 +680,7 @@ def get_element(self, class_name, item_id, input):
669680 '@etag' : etag
670681 }
671682
672- self .client .setHeader ("ETag" , '"%s"' % etag )
683+ self .client .setHeader ("ETag" , etag )
673684 return 200 , result
674685
675686 @Routing .route ("/data/<:class_name>/<:item_id>/<:attr_name>" , 'GET' )
@@ -717,7 +728,7 @@ def get_attribute(self, class_name, item_id, attr_name, input):
717728 '@etag' : etag
718729 }
719730
720- self .client .setHeader ("ETag" , '"%s"' % etag )
731+ self .client .setHeader ("ETag" , etag )
721732 return 200 , result
722733
723734 @Routing .route ("/data/<:class_name>" , 'POST' )
@@ -818,12 +829,7 @@ def put_element(self, class_name, item_id, input):
818829 (p , class_name , item_id )
819830 )
820831 try :
821- if not check_etag (class_obj .getnode (item_id ),
822- obtain_etags (self .client .request .headers , input ),
823- class_name ,
824- item_id ):
825- raise PreconditionFailed ("Etag is missing or does not match."
826- " Retrieve asset and retry modification if valid." )
832+ self .raise_if_no_etag (class_name , item_id , input )
827833 result = class_obj .set (item_id , ** props )
828834 self .db .commit ()
829835 except (TypeError , IndexError , ValueError ) as message :
@@ -874,11 +880,7 @@ def put_attribute(self, class_name, item_id, attr_name, input):
874880 }
875881
876882 try :
877- if not check_etag (class_obj .getnode (item_id ),
878- obtain_etags (self .client .request .headers , input ),
879- class_name , item_id ):
880- raise PreconditionFailed ("Etag is missing or does not match."
881- " Retrieve asset and retry modification if valid." )
883+ self .raise_if_no_etag (class_name , item_id , input )
882884 result = class_obj .set (item_id , ** props )
883885 self .db .commit ()
884886 except (TypeError , IndexError , ValueError ) as message :
@@ -964,13 +966,7 @@ def delete_element(self, class_name, item_id, input):
964966 'Permission to retire %s %s denied' % (class_name , item_id )
965967 )
966968
967- if not check_etag (class_obj .getnode (item_id ),
968- obtain_etags (self .client .request .headers , input ),
969- class_name ,
970- item_id ):
971- raise PreconditionFailed ("Etag is missing or does not match."
972- " Retrieve asset and retry modification if valid." )
973-
969+ self .raise_if_no_etag (class_name , item_id , input )
974970 class_obj .retire (item_id )
975971 self .db .commit ()
976972 result = {
@@ -1014,13 +1010,7 @@ def delete_attribute(self, class_name, item_id, attr_name, input):
10141010 props [attr_name ] = None
10151011
10161012 try :
1017- if not check_etag (class_obj .getnode (item_id ),
1018- obtain_etags (self .client .request .headers , input ),
1019- class_name ,
1020- item_id ):
1021- raise PreconditionFailed ("Etag is missing or does not match."
1022- " Retrieve asset and retry modification if valid." )
1023-
1013+ self .raise_if_no_etag (class_name , item_id , input )
10241014 class_obj .set (item_id , ** props )
10251015 self .db .commit ()
10261016 except (TypeError , IndexError , ValueError ) as message :
@@ -1064,12 +1054,7 @@ def patch_element(self, class_name, item_id, input):
10641054 op = self .__default_patch_op
10651055 class_obj = self .db .getclass (class_name )
10661056
1067- if not check_etag (class_obj .getnode (item_id ),
1068- obtain_etags (self .client .request .headers , input ),
1069- class_name ,
1070- item_id ):
1071- raise PreconditionFailed ("Etag is missing or does not match."
1072- " Retrieve asset and retry modification if valid." )
1057+ self .raise_if_no_etag (class_name , item_id , input )
10731058
10741059 # if patch operation is action, call the action handler
10751060 action_args = [class_name + item_id ]
@@ -1173,12 +1158,7 @@ def patch_attribute(self, class_name, item_id, attr_name, input):
11731158 prop = attr_name
11741159 class_obj = self .db .getclass (class_name )
11751160
1176- if not check_etag (class_obj .getnode (item_id ),
1177- obtain_etags (self .client .request .headers , input ),
1178- class_name ,
1179- item_id ):
1180- raise PreconditionFailed ("Etag is missing or does not match."
1181- " Retrieve asset and retry modification if valid." )
1161+ self .raise_if_no_etag (class_name , item_id , input )
11821162
11831163 props = {
11841164 prop : self .prop_from_arg (
0 commit comments