Skip to content
This repository has been archived by the owner on Mar 28, 2019. It is now read-only.

Commit

Permalink
Do not always return 412 errors when request header `If-None-Match: *…
Browse files Browse the repository at this point in the history
…`` is sent on ``POST /collection`` (fixes #673)
  • Loading branch information
leplatrem committed Mar 4, 2016
1 parent dfea05a commit 0b51b8c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 6 deletions.
12 changes: 7 additions & 5 deletions cliquet/resource/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,17 +276,19 @@ def collection_post(self):
Add custom behaviour by overriding
:meth:`cliquet.resource.UserResource.process_record`
"""
self._raise_412_if_modified()
existing = None
new_record = self.request.validated['data']

# Since ``id`` does not belong to schema, it can only be found in body.
try:
id_field = self.model.id_field
# Since ``id`` does not belong to schema, look up in body.
new_record[id_field] = _id = self.request.json['data'][id_field]
self._raise_400_if_invalid_id(_id)
except (KeyError, ValueError):
existing = self._get_record_or_404(_id)
except (HTTPNotFound, KeyError, ValueError):
pass

self._raise_412_if_modified(record=existing)

new_record = self.process_record(new_record)
try:
unique_fields = self.mapping.get_option('unique_fields')
Expand Down Expand Up @@ -753,7 +755,7 @@ def _raise_412_if_modified(self, record=None):

if_match = decode_header(if_match) if if_match else None

if if_none_match and decode_header(if_none_match) == '*':
if record and if_none_match and decode_header(if_none_match) == '*':
modified_since = -1 # Always raise.
elif if_match:
try:
Expand Down
26 changes: 25 additions & 1 deletion cliquet/tests/resource/test_preconditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def test_412_on_single_record_has_last_modified_timestamp(self):
self.assertIsNotNone(error.headers.get('Last-Modified'))

def test_create_returns_412_if_changed_meanwhile(self):
self.resource.request.validated = {'data': {'field': 'new'}}
self.assertRaises(httpexceptions.HTTPPreconditionFailed,
self.resource.collection_post)

Expand Down Expand Up @@ -159,16 +160,39 @@ def test_put_returns_412_if_deleted_meanwhile(self):
self.assertRaises(httpexceptions.HTTPPreconditionFailed,
self.resource.put)

def test_if_none_match_star_fails_if_record_exists(self):
def test_put_if_none_match_star_fails_if_record_exists(self):
self.resource.request.headers.pop('If-Match')
self.resource.request.headers['If-None-Match'] = '*'
self.resource.record_id = self.stored['id']
self.assertRaises(httpexceptions.HTTPPreconditionFailed,
self.resource.put)

def test_put_if_none_match_star_succeeds_if_record_does_not_exist(self):
self.resource.request.headers.pop('If-Match')
self.resource.request.headers['If-None-Match'] = '*'
self.resource.request.validated = {'data': {'field': 'new'}}
self.resource.record_id = self.resource.model.id_generator()
self.resource.put() # not raising.

def test_post_if_none_match_star_fails_if_record_exists(self):
self.resource.request.headers.pop('If-Match')
self.resource.request.headers['If-None-Match'] = '*'
self.resource.request.json = self.resource.request.validated = {
'data': {
'id': self.stored['id'],
'field': 'new'}}
self.assertRaises(httpexceptions.HTTPPreconditionFailed,
self.resource.collection_post)

def test_post_if_none_match_star_succeeds_if_record_does_not_exist(self):
self.resource.request.headers.pop('If-Match')
self.resource.request.headers['If-None-Match'] = '*'
self.resource.request.validated = {
'data': {
'id': self.resource.model.id_generator(),
'field': 'new'}}
self.resource.collection_post() # not raising.

def test_patch_returns_412_if_changed_meanwhile(self):
self.resource.record_id = self.stored['id']
self.assertRaises(httpexceptions.HTTPPreconditionFailed,
Expand Down

0 comments on commit 0b51b8c

Please sign in to comment.