mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-09 11:26:00 +00:00
DAV: Fix behavior when PUT doesn't return ETag (#476)
Thanks to @evert for pointing this out in the #sabredav IRC channel.
This commit is contained in:
parent
5b87dcceeb
commit
3228e22621
2 changed files with 27 additions and 10 deletions
|
|
@ -404,8 +404,11 @@ class SyncMachine(RuleBasedStateMachine):
|
|||
def _get_items(storage):
|
||||
return sorted(item.raw for etag, item in storage.items.values())
|
||||
|
||||
@rule(target=Storage, read_only=st.booleans(), flaky_etags=st.booleans())
|
||||
def newstorage(self, read_only, flaky_etags):
|
||||
@rule(target=Storage,
|
||||
read_only=st.booleans(),
|
||||
flaky_etags=st.booleans(),
|
||||
null_etag_on_upload=st.booleans())
|
||||
def newstorage(self, read_only, flaky_etags, null_etag_on_upload):
|
||||
s = MemoryStorage()
|
||||
s.read_only = read_only
|
||||
if flaky_etags:
|
||||
|
|
@ -416,6 +419,12 @@ class SyncMachine(RuleBasedStateMachine):
|
|||
return item, etag
|
||||
s.get = get
|
||||
|
||||
if null_etag_on_upload:
|
||||
_old_upload = s.upload
|
||||
_old_update = s.update
|
||||
s.upload = lambda item: (_old_upload(item)[0], None)
|
||||
s.update = lambda h, i, e: _old_update(h, i, e) and None
|
||||
|
||||
return s
|
||||
|
||||
@rule(target=Status)
|
||||
|
|
|
|||
|
|
@ -465,16 +465,24 @@ class DavStorage(Storage):
|
|||
data=item.raw.encode('utf-8'),
|
||||
headers=headers
|
||||
)
|
||||
|
||||
# The server may not return an etag under certain conditions:
|
||||
#
|
||||
# An origin server MUST NOT send a validator header field (Section
|
||||
# 7.2), such as an ETag or Last-Modified field, in a successful
|
||||
# response to PUT unless the request's representation data was saved
|
||||
# without any transformation applied to the body (i.e., the
|
||||
# resource's new representation data is identical to the
|
||||
# representation data received in the PUT request) and the validator
|
||||
# field value reflects the new representation.
|
||||
#
|
||||
# -- https://tools.ietf.org/html/rfc7231#section-4.3.4
|
||||
#
|
||||
# In such cases we return None as etag. The next synchronization will
|
||||
# then detect an etag change (None != some string) and will download
|
||||
# the new item.
|
||||
etag = response.headers.get('etag', None)
|
||||
href = self._normalize_href(response.url)
|
||||
if not etag:
|
||||
# The server violated the RFC and didn't send an etag. This is
|
||||
# technically a race-condition, but too many popular servers do it.
|
||||
#
|
||||
# ownCloud: https://github.com/owncloud/contacts/issues/920
|
||||
dav_logger.debug('Server did not send etag, fetching {!r}'
|
||||
.format(href))
|
||||
item2, etag = self.get(href)
|
||||
return href, etag
|
||||
|
||||
def update(self, href, item, etag):
|
||||
|
|
|
|||
Loading…
Reference in a new issue