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.
This commit is contained in:
Vincent Untz 2013-03-18 18:14:53 +01:00
parent 0dbf71f57f
commit 74590cfd0c
3 changed files with 31 additions and 13 deletions

3
config
View File

@ -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

View File

@ -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"},

View File

@ -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"))