Compare commits

...

3 Commits

Author SHA1 Message Date
Lennart
99287f85f4 version 0.12.0 2026-01-19 15:48:56 +01:00
Lennart
df3143cd4c Fix status code for failed preconditions 2026-01-19 15:37:41 +01:00
Lennart Kämmle
92a3418f8e Merge pull request #164 from lennart-k/feat/ical-rewrite
ical-rs overhaul
2026-01-19 15:14:14 +01:00
6 changed files with 26 additions and 29 deletions

24
Cargo.lock generated
View File

@@ -3317,7 +3317,7 @@ dependencies = [
[[package]]
name = "rustical"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"anyhow",
"argon2",
@@ -3364,7 +3364,7 @@ dependencies = [
[[package]]
name = "rustical_caldav"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"async-std",
"async-trait",
@@ -3406,7 +3406,7 @@ dependencies = [
[[package]]
name = "rustical_carddav"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"async-trait",
"axum",
@@ -3440,7 +3440,7 @@ dependencies = [
[[package]]
name = "rustical_dav"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"async-trait",
"axum",
@@ -3466,7 +3466,7 @@ dependencies = [
[[package]]
name = "rustical_dav_push"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"async-trait",
"axum",
@@ -3491,7 +3491,7 @@ dependencies = [
[[package]]
name = "rustical_frontend"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"askama",
"askama_web",
@@ -3527,7 +3527,7 @@ dependencies = [
[[package]]
name = "rustical_ical"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"axum",
"chrono",
@@ -3546,7 +3546,7 @@ dependencies = [
[[package]]
name = "rustical_oidc"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"async-trait",
"axum",
@@ -3562,7 +3562,7 @@ dependencies = [
[[package]]
name = "rustical_store"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"anyhow",
"async-trait",
@@ -3595,7 +3595,7 @@ dependencies = [
[[package]]
name = "rustical_store_sqlite"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"async-trait",
"chrono",
@@ -3620,7 +3620,7 @@ dependencies = [
[[package]]
name = "rustical_xml"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"quick-xml",
"thiserror 2.0.18",
@@ -5442,7 +5442,7 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
[[package]]
name = "xml_derive"
version = "0.11.17"
version = "0.12.0"
dependencies = [
"darling 0.23.0",
"heck",

View File

@@ -2,7 +2,7 @@
members = ["crates/*"]
[workspace.package]
version = "0.11.17"
version = "0.12.0"
rust-version = "1.92"
edition = "2024"
description = "A CalDAV server"

View File

@@ -23,7 +23,7 @@ impl IntoResponse for Precondition {
if let Err(err) = error.serialize_root(&mut writer) {
return rustical_dav::Error::from(err).into_response();
}
let mut res = Response::builder().status(StatusCode::PRECONDITION_FAILED);
let mut res = Response::builder().status(StatusCode::FORBIDDEN);
res.headers_mut().unwrap().typed_insert(ContentType::xml());
res.body(Body::from(output)).unwrap()
}
@@ -72,7 +72,10 @@ impl Error {
Self::XmlDecodeError(_) => StatusCode::BAD_REQUEST,
Self::ChronoParseError(_) | Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR,
Self::NotFound => StatusCode::NOT_FOUND,
Self::PreconditionFailed(_err) => StatusCode::PRECONDITION_FAILED,
// The correct status code for a failed precondition is not PreconditionFailed but
// Forbidden (or Conflict):
// https://datatracker.ietf.org/doc/html/rfc4791#section-1.3
Self::PreconditionFailed(_err) => StatusCode::FORBIDDEN,
}
}
}
@@ -82,10 +85,7 @@ impl IntoResponse for Error {
if let Self::PreconditionFailed(precondition) = self {
return precondition.into_response();
}
if matches!(
self.status_code(),
StatusCode::INTERNAL_SERVER_ERROR | StatusCode::PRECONDITION_FAILED
) {
if matches!(self.status_code(), StatusCode::INTERNAL_SERVER_ERROR) {
error!("{self}");
}
(self.status_code(), self.to_string()).into_response()

View File

@@ -51,19 +51,18 @@ impl Error {
_ => StatusCode::BAD_REQUEST,
},
Self::PropReadOnly => StatusCode::CONFLICT,
Self::PreconditionFailed => StatusCode::PRECONDITION_FAILED,
Self::InternalError | Self::IOError(_) => StatusCode::INTERNAL_SERVER_ERROR,
Self::Forbidden => StatusCode::FORBIDDEN,
// The correct status code for a failed precondition is not PreconditionFailed but
// Forbidden (or Conflict):
// https://datatracker.ietf.org/doc/html/rfc4791#section-1.3
Self::PreconditionFailed | Self::Forbidden => StatusCode::FORBIDDEN,
}
}
}
impl axum::response::IntoResponse for Error {
fn into_response(self) -> axum::response::Response {
if matches!(
self.status_code(),
StatusCode::INTERNAL_SERVER_ERROR | StatusCode::PRECONDITION_FAILED
) {
if matches!(self.status_code(), StatusCode::INTERNAL_SERVER_ERROR) {
error!("{self}");
}

View File

@@ -53,9 +53,7 @@ impl IntoResponse for Error {
fn into_response(self) -> axum::response::Response {
if matches!(
self.status_code(),
StatusCode::INTERNAL_SERVER_ERROR
| StatusCode::PRECONDITION_FAILED
| StatusCode::CONFLICT
StatusCode::INTERNAL_SERVER_ERROR | StatusCode::CONFLICT
) {
error!("{self}");
}

View File

@@ -66,7 +66,7 @@ END:VCALENDAR";
.typed_insert(Authorization::basic("user", "pass"));
let response = app.clone().oneshot(request).await.unwrap();
assert_eq!(response.status(), StatusCode::PRECONDITION_FAILED);
assert_eq!(response.status(), StatusCode::FORBIDDEN);
let body = response.extract_string().await;
insta::assert_snapshot!(body, @r#"
<?xml version="1.0" encoding="utf-8"?>