mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 22:52:22 +00:00
dav: Implement HEAD method
This commit is contained in:
@@ -4,7 +4,7 @@ use axum::body::Body;
|
|||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use axum::{extract::Path, response::Response};
|
use axum::{extract::Path, response::Response};
|
||||||
use headers::{ContentType, HeaderMapExt};
|
use headers::{ContentType, HeaderMapExt};
|
||||||
use http::{HeaderValue, StatusCode, header};
|
use http::{HeaderValue, Method, StatusCode, header};
|
||||||
use ical::generator::{Emitter, IcalCalendarBuilder};
|
use ical::generator::{Emitter, IcalCalendarBuilder};
|
||||||
use ical::property::Property;
|
use ical::property::Property;
|
||||||
use percent_encoding::{CONTROLS, utf8_percent_encode};
|
use percent_encoding::{CONTROLS, utf8_percent_encode};
|
||||||
@@ -19,6 +19,7 @@ pub async fn route_get<C: CalendarStore, S: SubscriptionStore>(
|
|||||||
Path((principal, calendar_id)): Path<(String, String)>,
|
Path((principal, calendar_id)): Path<(String, String)>,
|
||||||
State(CalendarResourceService { cal_store, .. }): State<CalendarResourceService<C, S>>,
|
State(CalendarResourceService { cal_store, .. }): State<CalendarResourceService<C, S>>,
|
||||||
user: Principal,
|
user: Principal,
|
||||||
|
method: Method,
|
||||||
) -> Result<Response, Error> {
|
) -> Result<Response, Error> {
|
||||||
if !user.is_principal(&principal) {
|
if !user.is_principal(&principal) {
|
||||||
return Err(crate::Error::Unauthorized);
|
return Err(crate::Error::Unauthorized);
|
||||||
@@ -96,5 +97,9 @@ pub async fn route_get<C: CalendarStore, S: SubscriptionStore>(
|
|||||||
))
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
Ok(resp.body(Body::new(ical_calendar.generate())).unwrap())
|
if matches!(method, Method::HEAD) {
|
||||||
|
Ok(resp.body(Body::empty()).unwrap())
|
||||||
|
} else {
|
||||||
|
Ok(resp.body(Body::new(ical_calendar.generate())).unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use axum::extract::{Path, State};
|
|||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use axum_extra::TypedHeader;
|
use axum_extra::TypedHeader;
|
||||||
use headers::{ContentType, ETag, HeaderMapExt, IfNoneMatch};
|
use headers::{ContentType, ETag, HeaderMapExt, IfNoneMatch};
|
||||||
use http::{HeaderMap, StatusCode};
|
use http::{HeaderMap, Method, StatusCode};
|
||||||
use rustical_ical::CalendarObject;
|
use rustical_ical::CalendarObject;
|
||||||
use rustical_store::CalendarStore;
|
use rustical_store::CalendarStore;
|
||||||
use rustical_store::auth::Principal;
|
use rustical_store::auth::Principal;
|
||||||
@@ -22,6 +22,7 @@ pub async fn get_event<C: CalendarStore>(
|
|||||||
}): Path<CalendarObjectPathComponents>,
|
}): Path<CalendarObjectPathComponents>,
|
||||||
State(CalendarObjectResourceService { cal_store }): State<CalendarObjectResourceService<C>>,
|
State(CalendarObjectResourceService { cal_store }): State<CalendarObjectResourceService<C>>,
|
||||||
user: Principal,
|
user: Principal,
|
||||||
|
method: Method,
|
||||||
) -> Result<Response, Error> {
|
) -> Result<Response, Error> {
|
||||||
if !user.is_principal(&principal) {
|
if !user.is_principal(&principal) {
|
||||||
return Err(crate::Error::Unauthorized);
|
return Err(crate::Error::Unauthorized);
|
||||||
@@ -42,7 +43,11 @@ pub async fn get_event<C: CalendarStore>(
|
|||||||
let hdrs = resp.headers_mut().unwrap();
|
let hdrs = resp.headers_mut().unwrap();
|
||||||
hdrs.typed_insert(ETag::from_str(&event.get_etag()).unwrap());
|
hdrs.typed_insert(ETag::from_str(&event.get_etag()).unwrap());
|
||||||
hdrs.typed_insert(ContentType::from_str("text/calendar").unwrap());
|
hdrs.typed_insert(ContentType::from_str("text/calendar").unwrap());
|
||||||
Ok(resp.body(Body::new(event.get_ics().to_owned())).unwrap())
|
if matches!(method, Method::HEAD) {
|
||||||
|
Ok(resp.body(Body::empty()).unwrap())
|
||||||
|
} else {
|
||||||
|
Ok(resp.body(Body::new(event.get_ics().to_owned())).unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(cal_store))]
|
#[instrument(skip(cal_store))]
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use axum::extract::{Path, State};
|
|||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use axum_extra::TypedHeader;
|
use axum_extra::TypedHeader;
|
||||||
use axum_extra::headers::{ContentType, ETag, HeaderMapExt, IfNoneMatch};
|
use axum_extra::headers::{ContentType, ETag, HeaderMapExt, IfNoneMatch};
|
||||||
|
use http::Method;
|
||||||
use http::{HeaderMap, StatusCode};
|
use http::{HeaderMap, StatusCode};
|
||||||
use rustical_dav::privileges::UserPrivilege;
|
use rustical_dav::privileges::UserPrivilege;
|
||||||
use rustical_dav::resource::Resource;
|
use rustical_dav::resource::Resource;
|
||||||
@@ -25,6 +26,7 @@ pub async fn get_object<AS: AddressbookStore>(
|
|||||||
}): Path<AddressObjectPathComponents>,
|
}): Path<AddressObjectPathComponents>,
|
||||||
State(AddressObjectResourceService { addr_store }): State<AddressObjectResourceService<AS>>,
|
State(AddressObjectResourceService { addr_store }): State<AddressObjectResourceService<AS>>,
|
||||||
user: Principal,
|
user: Principal,
|
||||||
|
method: Method,
|
||||||
) -> Result<Response, Error> {
|
) -> Result<Response, Error> {
|
||||||
if !user.is_principal(&principal) {
|
if !user.is_principal(&principal) {
|
||||||
return Err(Error::Unauthorized);
|
return Err(Error::Unauthorized);
|
||||||
@@ -49,7 +51,11 @@ pub async fn get_object<AS: AddressbookStore>(
|
|||||||
let hdrs = resp.headers_mut().unwrap();
|
let hdrs = resp.headers_mut().unwrap();
|
||||||
hdrs.typed_insert(ETag::from_str(&object.get_etag()).unwrap());
|
hdrs.typed_insert(ETag::from_str(&object.get_etag()).unwrap());
|
||||||
hdrs.typed_insert(ContentType::from_str("text/vcard").unwrap());
|
hdrs.typed_insert(ContentType::from_str("text/vcard").unwrap());
|
||||||
Ok(resp.body(Body::new(object.get_vcf().to_owned())).unwrap())
|
if matches!(method, Method::HEAD) {
|
||||||
|
Ok(resp.body(Body::empty()).unwrap())
|
||||||
|
} else {
|
||||||
|
Ok(resp.body(Body::new(object.get_vcf().to_owned())).unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(addr_store, body))]
|
#[instrument(skip(addr_store, body))]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use axum::body::Body;
|
|||||||
use axum::extract::{Path, State};
|
use axum::extract::{Path, State};
|
||||||
use axum::response::Response;
|
use axum::response::Response;
|
||||||
use axum_extra::headers::{ContentType, HeaderMapExt};
|
use axum_extra::headers::{ContentType, HeaderMapExt};
|
||||||
use http::{HeaderValue, StatusCode, header};
|
use http::{HeaderValue, Method, StatusCode, header};
|
||||||
use percent_encoding::{CONTROLS, utf8_percent_encode};
|
use percent_encoding::{CONTROLS, utf8_percent_encode};
|
||||||
use rustical_dav::privileges::UserPrivilege;
|
use rustical_dav::privileges::UserPrivilege;
|
||||||
use rustical_dav::resource::Resource;
|
use rustical_dav::resource::Resource;
|
||||||
@@ -20,6 +20,7 @@ pub async fn route_get<AS: AddressbookStore, S: SubscriptionStore>(
|
|||||||
Path((principal, addressbook_id)): Path<(String, String)>,
|
Path((principal, addressbook_id)): Path<(String, String)>,
|
||||||
State(AddressbookResourceService { addr_store, .. }): State<AddressbookResourceService<AS, S>>,
|
State(AddressbookResourceService { addr_store, .. }): State<AddressbookResourceService<AS, S>>,
|
||||||
user: Principal,
|
user: Principal,
|
||||||
|
method: Method,
|
||||||
) -> Result<Response, Error> {
|
) -> Result<Response, Error> {
|
||||||
if !user.is_principal(&principal) {
|
if !user.is_principal(&principal) {
|
||||||
return Err(Error::Unauthorized);
|
return Err(Error::Unauthorized);
|
||||||
@@ -55,5 +56,9 @@ pub async fn route_get<AS: AddressbookStore, S: SubscriptionStore>(
|
|||||||
))
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
Ok(resp.body(Body::new(vcf)).unwrap())
|
if matches!(method, Method::HEAD) {
|
||||||
|
Ok(resp.body(Body::empty()).unwrap())
|
||||||
|
} else {
|
||||||
|
Ok(resp.body(Body::new(vcf)).unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,6 @@ pub trait AxumMethods: Sized + Send + Sync + 'static {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn head() -> Option<MethodFunction<Self>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn post() -> Option<MethodFunction<Self>> {
|
fn post() -> Option<MethodFunction<Self>> {
|
||||||
None
|
None
|
||||||
@@ -58,8 +53,6 @@ pub trait AxumMethods: Sized + Send + Sync + 'static {
|
|||||||
}
|
}
|
||||||
if Self::get().is_some() {
|
if Self::get().is_some() {
|
||||||
allow.push(Method::GET);
|
allow.push(Method::GET);
|
||||||
}
|
|
||||||
if Self::head().is_some() {
|
|
||||||
allow.push(Method::HEAD);
|
allow.push(Method::HEAD);
|
||||||
}
|
}
|
||||||
if Self::post().is_some() {
|
if Self::post().is_some() {
|
||||||
|
|||||||
@@ -72,16 +72,11 @@ where
|
|||||||
return svc(self.resource_service.clone(), req);
|
return svc(self.resource_service.clone(), req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"GET" => {
|
"GET" | "HEAD" => {
|
||||||
if let Some(svc) = RS::get() {
|
if let Some(svc) = RS::get() {
|
||||||
return svc(self.resource_service.clone(), req);
|
return svc(self.resource_service.clone(), req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"HEAD" => {
|
|
||||||
if let Some(svc) = RS::head() {
|
|
||||||
return svc(self.resource_service.clone(), req);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"POST" => {
|
"POST" => {
|
||||||
if let Some(svc) = RS::post() {
|
if let Some(svc) = RS::post() {
|
||||||
return svc(self.resource_service.clone(), req);
|
return svc(self.resource_service.clone(), req);
|
||||||
|
|||||||
Reference in New Issue
Block a user