Skip to content

Commit 1760b88

Browse files
committed
A few internet references report that etags for the same underlying
resource but with different representation (xml, json ...) should have different etags. That is currently not the case. Added code to allow incorporation of representation info into the etag. By default the representation is "json", but future patches can pass the representation down and modify flow to match requested representation.
1 parent 49f2b23 commit 1760b88

File tree

2 files changed

+15
-11
lines changed

2 files changed

+15
-11
lines changed

roundup/rest.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ def format_object(self, *args, **kwargs):
118118
return result
119119
return format_object
120120

121-
def calculate_etag (node, key, classname="Missing", id="0"):
121+
def calculate_etag (node, key, classname="Missing", id="0",
122+
repr_format="json"):
122123
'''given a hyperdb node generate a hashed representation of it to be
123124
used as an etag.
124125
@@ -142,13 +143,15 @@ def calculate_etag (node, key, classname="Missing", id="0"):
142143
'''
143144

144145
items = node.items(protected=True) # include every item
145-
etag = hmac.new(bs2b(key),bs2b(repr(sorted(items)))).hexdigest()
146+
etag = hmac.new(bs2b(key),bs2b(repr_format +
147+
repr(sorted(items)))).hexdigest()
146148
logger.debug("object=%s%s; tag=%s; repr=%s", classname, id,
147149
etag, repr(node.items(protected=True)))
148150
# Quotes are part of ETag spec, normal headers don't have quotes
149151
return '"%s"' % etag
150152

151-
def check_etag (node, key, etags, classname="Missing", id="0"):
153+
def check_etag (node, key, etags, classname="Missing", id="0",
154+
repr_format="json"):
152155
'''Take a list of etags and compare to the etag for the given node.
153156
154157
Iterate over all supplied etags,
@@ -159,7 +162,8 @@ def check_etag (node, key, etags, classname="Missing", id="0"):
159162
'''
160163
have_etag_match=False
161164

162-
node_etag = calculate_etag(node, key, classname, id)
165+
node_etag = calculate_etag(node, key, classname, id,
166+
repr_format=repr_format)
163167

164168
for etag in etags:
165169
if etag is not None:
@@ -508,13 +512,13 @@ def patch_data(self, op, old_val, new_val):
508512

509513
return result
510514

511-
def raise_if_no_etag(self, class_name, item_id, input):
515+
def raise_if_no_etag(self, class_name, item_id, input, repr_format="json"):
512516
class_obj = self.db.getclass(class_name)
513517
if not check_etag(class_obj.getnode(item_id),
514518
self.db.config.WEB_SECRET_KEY,
515519
obtain_etags(self.client.request.headers, input),
516520
class_name,
517-
item_id):
521+
item_id, repr_format=repr_format):
518522
raise PreconditionFailed(
519523
"If-Match is missing or does not match."
520524
" Retrieve asset and retry modification if valid.")
@@ -789,7 +793,7 @@ def get_element(self, class_name, item_id, input):
789793

790794
node = class_obj.getnode(itemid)
791795
etag = calculate_etag(node, self.db.config.WEB_SECRET_KEY,
792-
class_name, itemid)
796+
class_name, itemid, repr_format="json")
793797
props = None
794798
protected=False
795799
verbose=1
@@ -871,7 +875,7 @@ def get_attribute(self, class_name, item_id, attr_name, input):
871875
class_obj = self.db.getclass(class_name)
872876
node = class_obj.getnode(item_id)
873877
etag = calculate_etag(node, self.db.config.WEB_SECRET_KEY,
874-
class_name, item_id)
878+
class_name, item_id, repr_format="json")
875879
data = node.__getattr__(attr_name)
876880
result = {
877881
'id': item_id,

test/rest_common.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -655,22 +655,22 @@ def dummyClosure(adate=None, translator=None):
655655
items = node.items(protected=True) # include every item
656656
print(repr(sorted(items)))
657657
print(etag)
658-
self.assertEqual(etag, '"f2901b2653b813eeb277c0dc84c03ba3"')
658+
self.assertEqual(etag, '"0433784660a141e8262835171e70fd2f"')
659659

660660
# modify key and verify we have a different etag
661661
etag = calculate_etag(node, self.db.config['WEB_SECRET_KEY'] + "a")
662662
items = node.items(protected=True) # include every item
663663
print(repr(sorted(items)))
664664
print(etag)
665-
self.assertNotEqual(etag, '"f2901b2653b813eeb277c0dc84c03ba3"')
665+
self.assertNotEqual(etag, '"0433784660a141e8262835171e70fd2f"')
666666

667667
# change data and verify we have a different etag
668668
node.username="Paul"
669669
etag = calculate_etag(node, self.db.config['WEB_SECRET_KEY'])
670670
items = node.items(protected=True) # include every item
671671
print(repr(sorted(items)))
672672
print(etag)
673-
self.assertEqual(etag, '"98f8052193220afdb649c6caaaa80e40"')
673+
self.assertEqual(etag, '"8abeacd284d58655c620d60389e29d4d"')
674674
finally:
675675
date.Date = originalDate
676676

0 commit comments

Comments
 (0)