From 54bda5594c37320ac98af97e678222b42d3622f7 Mon Sep 17 00:00:00 2001 From: Fabrice Bellet Date: Mon, 22 Oct 2012 12:44:42 +0200 Subject: [PATCH 1/3] Handle use in a subdir. Patch from Clint Adams adapted from http://redmine.kozea.fr/issues/996 --- config | 3 ++- radicale/config.py | 3 ++- radicale/xmlutils.py | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/config b/config index 7b5702a..6ddf1ce 100644 --- a/config +++ b/config @@ -27,7 +27,8 @@ certificate = /etc/apache2/ssl/server.crt key = /etc/apache2/ssl/server.key # Reverse DNS to resolve client address in logs dns_lookup = True - +# base URL if / is not the CalDAV root +base_prefix = [encoding] # Encoding for responding requests diff --git a/radicale/config.py b/radicale/config.py index e07132e..14964aa 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -45,7 +45,8 @@ INITIAL_CONFIG = { "ssl": "False", "certificate": "/etc/apache2/ssl/server.crt", "key": "/etc/apache2/ssl/server.key", - "dns_lookup": "True"}, + "dns_lookup": "True", + "base_prefix": ""}, "encoding": { "request": "utf-8", "stock": "utf-8"}, diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 7896a54..29f131e 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -227,6 +227,7 @@ def _propfind_response(path, item, props, user): href = ET.Element(_tag("D", "href")) uri = item.url if is_collection else "%s/%s" % (path, item.name) + uri = "%s/%s" % (config.get("server", "base_prefix"), uri) href.text = uri.replace("//", "/") response.append(href) From 0dbf71f57f474f0eb584e3f5ec05000a3cf84802 Mon Sep 17 00:00:00 2001 From: Vincent Untz Date: Mon, 18 Mar 2013 18:13:28 +0100 Subject: [PATCH 2/3] Fix issues with base_prefix option --- config | 2 +- radicale/xmlutils.py | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/config b/config index 6ddf1ce..531f280 100644 --- a/config +++ b/config @@ -27,7 +27,7 @@ certificate = /etc/apache2/ssl/server.crt key = /etc/apache2/ssl/server.key # Reverse DNS to resolve client address in logs dns_lookup = True -# base URL if / is not the CalDAV root +# base URL if / is not the CalDAV root. If set, must start with / base_prefix = [encoding] diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index 29f131e..bd389b9 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -226,8 +226,10 @@ def _propfind_response(path, item, props, user): response = ET.Element(_tag("D", "response")) href = ET.Element(_tag("D", "href")) - uri = item.url if is_collection else "%s/%s" % (path, item.name) - uri = "%s/%s" % (config.get("server", "base_prefix"), uri) + if is_collection: + uri = "%s%s" % (config.get("server", "base_prefix"), item.url) + else: + uri = "%s/%s" % (path, item.name) href.text = uri.replace("//", "/") response.append(href) @@ -267,7 +269,7 @@ def _propfind_response(path, item, props, user): # pylint: enable=W0511 elif tag == _tag("D", "current-user-principal") and user: tag = ET.Element(_tag("D", "href")) - tag.text = "/%s/" % user + tag.text = "%s/%s/" % (config.get("server", "base_prefix"), user) element.append(tag) elif tag == _tag("D", "current-user-privilege-set"): privilege = ET.Element(_tag("D", "privilege")) @@ -461,9 +463,12 @@ def report(path, xml_request, collection): collection_headers = collection.headers collection_timezones = collection.timezones + base_prefix = config.get("server", "base_prefix") + for hreference in hreferences: + unprefixed_hreference = hreference[len(base_prefix):] # Check if the reference is an item or a collection - name = name_from_path(hreference, collection) + name = name_from_path(unprefixed_hreference, collection) if name: # Reference is an item path = "/".join(hreference.split("/")[:-1]) + "/" From 74590cfd0c40fa1a9f474b9a0a25d21bb744e309 Mon Sep 17 00:00:00 2001 From: Vincent Untz Date: Mon, 18 Mar 2013 18:14:53 +0100 Subject: [PATCH 3/3] Add proxy_base_prefix option to help run in a subdir behind a proxy I have a setup where Radicale is running as the normal process, and nginx is acting as proxy for Radicale for requests under /radicale/. This means that all requests to nginx that go to /radicale/ are sent to a radicale server that expects requests coming at /. Obviously, all the href need to have the /radicale/ prefix to have things work. So a new option proxy_base_prefix is added to allow having such a setup. All href that are sent in the replies will have the proxy_base_prefix prepended. --- config | 3 +++ radicale/config.py | 3 ++- radicale/xmlutils.py | 38 ++++++++++++++++++++++++++------------ 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/config b/config index 531f280..09f6d0d 100644 --- a/config +++ b/config @@ -29,6 +29,9 @@ key = /etc/apache2/ssl/server.key dns_lookup = True # base URL if / is not the CalDAV root. If set, must start with / base_prefix = +# base URL if Radicale is running with / as CalDAV root, but in a subdir behind a proxy (like nginx). If set, must start with / +proxy_base_prefix = + [encoding] # Encoding for responding requests diff --git a/radicale/config.py b/radicale/config.py index 14964aa..bd1cef9 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -46,7 +46,8 @@ INITIAL_CONFIG = { "certificate": "/etc/apache2/ssl/server.crt", "key": "/etc/apache2/ssl/server.key", "dns_lookup": "True", - "base_prefix": ""}, + "base_prefix": "", + "proxy_base_prefix": ""}, "encoding": { "request": "utf-8", "stock": "utf-8"}, diff --git a/radicale/xmlutils.py b/radicale/xmlutils.py index bd389b9..617763c 100644 --- a/radicale/xmlutils.py +++ b/radicale/xmlutils.py @@ -119,6 +119,11 @@ def _response(code): return "HTTP/1.1 %i %s" % (code, client.responses[code]) +def _href_with_proxy_base_prefix(href): + href = "%s%s" % (config.get("server", "proxy_base_prefix"), href) + return href.replace("//", "/") + + def name_from_path(path, collection): """Return Radicale item name from ``path``.""" collection_parts = collection.path.strip("/").split("/") @@ -174,7 +179,7 @@ def delete(path, collection): multistatus.append(response) href = ET.Element(_tag("D", "href")) - href.text = path + href.text = _href_with_proxy_base_prefix(path) response.append(href) status = ET.Element(_tag("D", "status")) @@ -230,7 +235,7 @@ def _propfind_response(path, item, props, user): uri = "%s%s" % (config.get("server", "base_prefix"), item.url) else: uri = "%s/%s" % (path, item.name) - href.text = uri.replace("//", "/") + href.text = _href_with_proxy_base_prefix(uri) response.append(href) propstat404 = ET.Element(_tag("D", "propstat")) @@ -250,14 +255,14 @@ def _propfind_response(path, item, props, user): element.text = item.etag elif tag == _tag("D", "principal-URL"): tag = ET.Element(_tag("D", "href")) - tag.text = path + tag.text = _href_with_proxy_base_prefix(path) element.append(tag) elif tag in (_tag("D", "principal-collection-set"), _tag("C", "calendar-user-address-set"), _tag("CR", "addressbook-home-set"), _tag("C", "calendar-home-set")): tag = ET.Element(_tag("D", "href")) - tag.text = path + tag.text = _href_with_proxy_base_prefix(path) element.append(tag) elif tag == _tag("C", "supported-calendar-component-set"): # This is not a Todo @@ -269,7 +274,8 @@ def _propfind_response(path, item, props, user): # pylint: enable=W0511 elif tag == _tag("D", "current-user-principal") and user: tag = ET.Element(_tag("D", "href")) - tag.text = "%s/%s/" % (config.get("server", "base_prefix"), user) + prefixed_path = "%s/%s/" % (config.get("server", "base_prefix"), user) + tag.text = _href_with_proxy_base_prefix(prefixed_path) element.append(tag) elif tag == _tag("D", "current-user-privilege-set"): privilege = ET.Element(_tag("D", "privilege")) @@ -393,7 +399,7 @@ def proppatch(path, xml_request, collection): multistatus.append(response) href = ET.Element(_tag("D", "href")) - href.text = path + href.text = _href_with_proxy_base_prefix(path) response.append(href) with collection.props as collection_props: @@ -436,13 +442,23 @@ def report(path, xml_request, collection): prop_element = root.find(_tag("D", "prop")) props = [prop.tag for prop in prop_element] + proxy_prefix = config.get("server", "proxy_base_prefix") + base_prefix = config.get("server", "base_prefix") + if collection: if root.tag in (_tag("C", "calendar-multiget"), _tag("CR", "addressbook-multiget")): # Read rfc4791-7.9 for info - hreferences = set( - href_element.text for href_element - in root.findall(_tag("D", "href"))) + hreferences = set() + for href_element in root.findall(_tag("D", "href")): + # skip elements that don't have the correct base prefixes + if not href_element.text.startswith(proxy_prefix): + continue + unprefixed = href_element.text[len(proxy_prefix):] + if not unprefixed.startswith(base_prefix): + continue + # we keep the base prefix here, to be aligned with other paths + hreferences.add(unprefixed) else: hreferences = (path,) # TODO: handle other filters @@ -463,8 +479,6 @@ def report(path, xml_request, collection): collection_headers = collection.headers collection_timezones = collection.timezones - base_prefix = config.get("server", "base_prefix") - for hreference in hreferences: unprefixed_hreference = hreference[len(base_prefix):] # Check if the reference is an item or a collection @@ -486,7 +500,7 @@ def report(path, xml_request, collection): multistatus.append(response) href = ET.Element(_tag("D", "href")) - href.text = "%s/%s" % (path.rstrip("/"), item.name) + href.text = _href_with_proxy_base_prefix("%s/%s" % (path.rstrip("/"), item.name)) response.append(href) propstat = ET.Element(_tag("D", "propstat"))