Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make discovery more RFC-conformant #585

Merged
merged 7 commits into from Mar 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Expand Up @@ -14,6 +14,7 @@ Version 0.16.0

- Strip ``METHOD:PUBLISH`` added by some calendar providers.
- Fix crash of Google storages when saving token file.
- Make DAV discovery more RFC-conformant, see :ghpr:`585`.

Version 0.15.0
==============
Expand Down
20 changes: 20 additions & 0 deletions vdirsyncer/http.py
Expand Up @@ -150,6 +150,8 @@ def request(method, url, session=None, latin1_fallback=True,
if verify_fingerprint is not None:
_install_fingerprint_adapter(session, verify_fingerprint)

session.hooks = dict(response=_fix_redirects)

func = session.request

logger.debug(u'{} {}'.format(method, url))
Expand Down Expand Up @@ -180,3 +182,21 @@ def request(method, url, session=None, latin1_fallback=True,

r.raise_for_status()
return r


def _fix_redirects(r, *args, **kwargs):
'''
Requests discards of the body content when it is following a redirect that
is not a 307 or 308. We never want that to happen.

See:
https://github.com/kennethreitz/requests/issues/3915
https://github.com/pimutils/vdirsyncer/pull/585
https://github.com/pimutils/vdirsyncer/issues/586

FIXME: This solution isn't very nice. A new hook in requests would be
better.
'''
if r.is_redirect:
logger.debug('Rewriting status code from %s to 307', r.status_code)
r.status_code = 307
26 changes: 9 additions & 17 deletions vdirsyncer/storage/dav.py
Expand Up @@ -134,23 +134,14 @@ def _get_collection_from_url(url):
_, collection = url.rstrip('/').rsplit('/', 1)
return urlparse.unquote(collection)

def find_dav(self):
def find_principal(self):
try:
response = self.session.request(
'GET', self._well_known_uri, allow_redirects=True,
headers=self.session.get_default_headers()
)
return response.url
return self._find_principal_impl('')
except (HTTPError, exceptions.Error):
# The user might not have well-known URLs set up and instead points
# vdirsyncer directly to the DAV server.
dav_logger.debug('Server does not support well-known URIs.')
return ''

def find_principal(self, url=None):
if url is None:
url = self.find_dav()
dav_logger.debug('Trying out well-known URI')
return self._find_principal_impl(self._well_known_uri)

def _find_principal_impl(self, url):
headers = self.session.get_default_headers()
headers['Depth'] = '0'
body = b"""
Expand All @@ -160,8 +151,10 @@ def find_principal(self, url=None):
</d:prop>
</d:propfind>
"""

response = self.session.request('PROPFIND', url, headers=headers,
data=body)

root = _parse_xml(response.content)
rv = root.find('.//{DAV:}current-user-principal/{DAV:}href')
if rv is None:
Expand All @@ -174,9 +167,8 @@ def find_principal(self, url=None):
return response.url
return urlparse.urljoin(response.url, rv.text)

def find_home(self, url=None):
if url is None:
url = self.find_principal()
def find_home(self):
url = self.find_principal()
headers = self.session.get_default_headers()
headers['Depth'] = '0'
response = self.session.request('PROPFIND', url,
Expand Down
9 changes: 7 additions & 2 deletions vdirsyncer/storage/google.py
Expand Up @@ -159,8 +159,13 @@ class GoogleContactsStorage(dav.CardDAVStorage):
''' + GOOGLE_PARAMS_DOCS

class session_class(GoogleSession):
# Apparently Google wants us to submit a PROPFIND to the well-known
# URL, instead of looking for a redirect.
# Google CardDAV is completely bonkers. Collection discovery doesn't
# work properly, well-known URI takes us directly to single collection
# from where we can't discover principal or homeset URIs (the PROPFINDs
# 404).
#
# So we configure the well-known URI here again, such that discovery
# tries collection enumeration on it directly. That appears to work.
url = 'https://www.googleapis.com/.well-known/carddav'
scope = ['https://www.googleapis.com/auth/carddav']

Expand Down