Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 0 additions & 26 deletions caldav/compatibility_hints.py
Original file line number Diff line number Diff line change
Expand Up @@ -883,39 +883,13 @@ def dotted_feature_set_list(self, compact=False):

}

## This is for Xandikos 0.2.12.
## Lots of development going on as of summer 2025, so expect the list to become shorter soon!
xandikos_v0_2_12 = {
## this only applies for very simple installations
"auto-connect.url": {"domain": "localhost", "scheme": "http", "basepath": "/"},
'search.recurrences.includes-implicit': {'support': 'unsupported'},
'search.recurrences.expanded': {'support': 'unsupported'},
'search.time-range.todo': {'support': 'unsupported'},
'search.time-range.alarm': {'support': 'ungraceful', 'behaviour': '500 internal server error'},
'search.comp-type.optional': {'support': 'ungraceful'},
"search.text.substring": {"support": "unsupported"},
"search.text.category.substring": {"support": "unsupported"},
'principal-search': {'support': 'unsupported'},
'freebusy-query': {'support': 'ungraceful', 'behaviour': '500 internal server error'},
"scheduling": {"support": "unsupported"},
## https://github.com/jelmer/xandikos/issues/8
'search.time-range.open.start.duration': {'support': 'unsupported'},
'search.time-range.open.start': {'support': 'broken', 'behaviour': 'future tasks are returned when only an end bound is given'},
}

xandikos = {
## Principal property search returns 403 (not implemented)
"principal-search": "ungraceful",

## VTODO RRULE expansion was fixed in xandikos PR #627 (released in 0.3.7).
## Exception expansion (CALDAV:expand with EXDATE/RECURRENCE-ID) is now also supported.

## Open-start time-range searches (no lower bound) crash xandikos 0.3.7 with a
## 500 Internal Server Error (OverflowError: date value out of range in icalendar.py
## _expand_rrule_component when computing adjusted_start = start - duration).
"search.time-range.open.start": {"support": "ungraceful", "behaviour": "500 Internal Server Error (OverflowError in rrule expansion)"},
"search.time-range.open.start.duration": True,

## this only applies for very simple installations
"auto-connect.url": {"domain": "localhost", "scheme": "http", "basepath": "/"},

Expand Down
16 changes: 10 additions & 6 deletions caldav/jmap/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,18 @@ def _parse_session_data(url: str, data: dict) -> Session:
# return a relative path. Resolve it against the session endpoint URL.
api_url = urljoin(url, api_url)

# Some servers (e.g. Stalwart behind a port-remapping proxy) advertise an
# api_url whose host matches ours but whose port reflects the internal
# listener rather than the port we actually connected through. Rewrite to
# match the session endpoint's authority so subsequent calls succeed.
# Some servers (e.g. Stalwart) advertise an api_url whose host matches ours
# but with a different scheme (https vs http) and/or port than the one we
# actually connected through. Rewrite both scheme and netloc to match the
# session endpoint so that subsequent calls succeed without TLS errors.
session_parsed = urlparse(url)
api_parsed = urlparse(api_url)
if api_parsed.hostname == session_parsed.hostname and api_parsed.port != session_parsed.port:
api_url = urlunparse(api_parsed._replace(netloc=session_parsed.netloc))
if api_parsed.hostname == session_parsed.hostname and (
api_parsed.port != session_parsed.port or api_parsed.scheme != session_parsed.scheme
):
api_url = urlunparse(
api_parsed._replace(scheme=session_parsed.scheme, netloc=session_parsed.netloc)
)

state = data.get("state", "")
server_capabilities = data.get("capabilities", {})
Expand Down
5 changes: 3 additions & 2 deletions tests/caldav_test_servers.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,9 @@ test-servers:
enabled: ${TEST_STALWART:-false}
host: ${STALWART_HOST:-localhost}
port: ${STALWART_PORT:-8809}
username: ${STALWART_USERNAME:-testuser}
password: ${STALWART_PASSWORD:-testpass}
# v0.16+: username is a full email address; password must not be in zxcvbn common-word list.
username: ${STALWART_USERNAME:-testuser@example.org}
password: ${STALWART_PASSWORD:-testcaldav}

# OX App Suite requires a locally built Docker image — run build.sh first.
ox:
Expand Down
4 changes: 2 additions & 2 deletions tests/docker-test-servers/cyrus/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ services:
# This fixes iTIP scheduling delivery: with virtdomains: userid the
# caladdress_lookup() function preserves user2@example.com as the
# userid, but mailbox ACLs use the short form user2, causing 403.
- ./imapd.conf:/srv/cyrus-docker-test-server.git/imapd.conf:ro
- ./imapd.conf:/srv/testserver/imapd.conf:ro
# Other data remains ephemeral for testing
# This ensures each start is fresh with newly created users
healthcheck:
test: ["CMD", "curl", "-s", "http://localhost:8080/"]
test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/8080'"]
interval: 10s
timeout: 5s
retries: 5
Expand Down
2 changes: 1 addition & 1 deletion tests/docker-test-servers/davical/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ services:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/davical/"]
test: ["CMD-SHELL", "wget -q --spider http://localhost/"]
interval: 10s
timeout: 5s
retries: 10
Expand Down
2 changes: 1 addition & 1 deletion tests/docker-test-servers/davical/setup_davical.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ TEST_USER="testuser"
TEST_PASSWORD="testpass"

run_sql() {
docker exec "$DB_CONTAINER" psql -U "$DB_USER" "$DB_NAME" -tAc "$1" 2>&1
docker exec "$DB_CONTAINER" psql -U "$DB_USER" "$DB_NAME" -tAc "$1" 2>/dev/null
}

echo "Waiting for DAViCal to be accessible..."
Expand Down
2 changes: 1 addition & 1 deletion tests/docker-test-servers/davis/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ services:
tmpfs:
- /data:size=100m
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/dav/"]
test: ["CMD", "curl", "-s", "http://localhost:9000/dav/"]
interval: 10s
timeout: 5s
retries: 5
Expand Down
2 changes: 1 addition & 1 deletion tests/docker-test-servers/ox/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
- /var/lib/mysql:size=500m
- /ox/store:size=200m
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost/caldav/"]
test: ["CMD", "curl", "-s", "http://localhost/caldav/"]
interval: 10s
timeout: 5s
retries: 30
Expand Down
2 changes: 1 addition & 1 deletion tests/docker-test-servers/sogo/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ services:
# Make the container truly ephemeral - data is lost on restart
- /srv:size=500m
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/SOGo/"]
test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/80'"]
interval: 10s
timeout: 5s
retries: 5
Expand Down
4 changes: 4 additions & 0 deletions tests/docker-test-servers/stalwart/config/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"@type": "Sqlite",
"path": "/opt/stalwart/data/stalwart.db"
}
14 changes: 10 additions & 4 deletions tests/docker-test-servers/stalwart/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@ services:
ports:
- "8809:8080"
environment:
- STALWART_ADMIN_PASSWORD=adminpass
# v0.16.6+: STALWART_ADMIN_PASSWORD is ignored when no config exists (bootstrap mode).
# STALWART_RECOVERY_ADMIN pins a bootstrap credential so setup scripts can authenticate.
- STALWART_RECOVERY_ADMIN=admin:adminpass
volumes:
# config.json tells Stalwart where to store its database (avoids bootstrap mode).
- ./config/config.json:/etc/stalwart/config.json:ro
tmpfs:
- /opt/stalwart/data:size=500m
- /opt/stalwart/logs:size=50m
- /opt/stalwart/etc:size=10m
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/"]
# /admin/ requires a GitHub web-UI download that can be slow; /dav/cal/ (401) is
# available as soon as the database is initialised, so use that instead.
test: ["CMD-SHELL", "curl -s -o /dev/null http://localhost:8080/dav/cal/"]
interval: 5s
timeout: 3s
retries: 15
start_period: 25s
start_period: 30s
Loading
Loading