aboutsummaryrefslogtreecommitdiff
path: root/aero-proto/src/dav
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2024-04-24 11:43:57 +0200
committerQuentin Dufour <quentin@deuxfleurs.fr>2024-04-24 11:43:57 +0200
commit52d767edae38cc0d3effd216152ff2dcf6d19239 (patch)
tree15b32a7bdcb6f12b4c9f1dc875090a5ac7d614d7 /aero-proto/src/dav
parent5d85fd16f2625b6efb7ed70254a275237dfab1eb (diff)
downloadaerogramme-52d767edae38cc0d3effd216152ff2dcf6d19239.tar.gz
aerogramme-52d767edae38cc0d3effd216152ff2dcf6d19239.zip
Parse If-{None-}Match headers
Diffstat (limited to 'aero-proto/src/dav')
-rw-r--r--aero-proto/src/dav/codec.rs25
-rw-r--r--aero-proto/src/dav/controller.rs3
-rw-r--r--aero-proto/src/dav/node.rs3
-rw-r--r--aero-proto/src/dav/resource.rs6
4 files changed, 30 insertions, 7 deletions
diff --git a/aero-proto/src/dav/codec.rs b/aero-proto/src/dav/codec.rs
index 9082d0a..57c3808 100644
--- a/aero-proto/src/dav/codec.rs
+++ b/aero-proto/src/dav/codec.rs
@@ -1,4 +1,4 @@
-use anyhow::Result;
+use anyhow::{bail, Result};
use hyper::{Request, Response, body::Bytes};
use hyper::body::Incoming;
use http_body_util::Full;
@@ -17,6 +17,7 @@ use http_body_util::BodyExt;
use aero_dav::types as dav;
use aero_dav::xml as dxml;
use super::controller::HttpResponse;
+use super::node::PutPolicy;
pub(crate) fn depth(req: &Request<impl hyper::body::Body>) -> dav::Depth {
match req.headers().get("Depth").map(hyper::header::HeaderValue::to_str) {
@@ -27,6 +28,28 @@ pub(crate) fn depth(req: &Request<impl hyper::body::Body>) -> dav::Depth {
}
}
+pub(crate) fn put_policy(req: &Request<impl hyper::body::Body>) -> Result<PutPolicy> {
+ if let Some(maybe_txt_etag) = req.headers().get("If-Match").map(hyper::header::HeaderValue::to_str) {
+ let etag = maybe_txt_etag?;
+ let dquote_count = etag.chars().filter(|c| *c == '"').count();
+ if dquote_count != 2 {
+ bail!("Either If-Match value is invalid or it's not supported (only single etag is supported)");
+ }
+
+ return Ok(PutPolicy::ReplaceEtag(etag.into()))
+ }
+
+ if let Some(maybe_txt_etag) = req.headers().get("If-None-Match").map(hyper::header::HeaderValue::to_str) {
+ let etag = maybe_txt_etag?;
+ if etag == "*" {
+ return Ok(PutPolicy::CreateOnly)
+ }
+ bail!("Either If-None-Match value is invalid or it's not supported (only asterisk is supported)")
+ }
+
+ Ok(PutPolicy::OverwriteAll)
+}
+
pub(crate) fn text_body(txt: &'static str) -> UnsyncBoxBody<Bytes, std::io::Error> {
UnsyncBoxBody::new(Full::new(Bytes::from(txt)).map_err(|e| match e {}))
}
diff --git a/aero-proto/src/dav/controller.rs b/aero-proto/src/dav/controller.rs
index 2dcc7bc..aee86fa 100644
--- a/aero-proto/src/dav/controller.rs
+++ b/aero-proto/src/dav/controller.rs
@@ -180,8 +180,7 @@ impl Controller {
}
async fn put(self) -> Result<HttpResponse> {
- //@FIXME temporary, look at If-None-Match & If-Match headers
- let put_policy = PutPolicy::CreateOnly;
+ let put_policy = codec::put_policy(&self.req)?;
let stream_of_frames = BodyStream::new(self.req.into_body());
let stream_of_bytes = stream_of_frames
diff --git a/aero-proto/src/dav/node.rs b/aero-proto/src/dav/node.rs
index 4d5dd1a..1ed4b0a 100644
--- a/aero-proto/src/dav/node.rs
+++ b/aero-proto/src/dav/node.rs
@@ -1,5 +1,5 @@
use anyhow::Result;
-use futures::stream::{BoxStream, Stream, StreamExt};
+use futures::stream::{BoxStream, StreamExt};
use futures::future::{BoxFuture, FutureExt};
use hyper::body::Bytes;
@@ -13,6 +13,7 @@ pub(crate) type Content<'a> = BoxStream<'a, std::result::Result<Bytes, std::io::
pub(crate) type PropertyStream<'a> = BoxStream<'a, std::result::Result<dav::Property<All>, dav::PropertyRequest<All>>>;
pub(crate) enum PutPolicy {
+ OverwriteAll,
CreateOnly,
ReplaceEtag(String),
}
diff --git a/aero-proto/src/dav/resource.rs b/aero-proto/src/dav/resource.rs
index cb63b71..9e2ce3d 100644
--- a/aero-proto/src/dav/resource.rs
+++ b/aero-proto/src/dav/resource.rs
@@ -1,12 +1,12 @@
use std::sync::Arc;
type ArcUser = std::sync::Arc<User>;
-use anyhow::{anyhow, bail, Result};
-use futures::stream::{TryStream, TryStreamExt, StreamExt};
+use anyhow::{anyhow, Result};
+use futures::stream::{TryStreamExt, StreamExt};
use futures::io::AsyncReadExt;
use futures::{future::BoxFuture, future::FutureExt};
-use aero_collections::{user::User, calendar::Calendar, davdag::{BlobId, IndexEntry, Etag}};
+use aero_collections::{user::User, calendar::Calendar, davdag::{BlobId, Etag}};
use aero_dav::types as dav;
use aero_dav::caltypes as cal;
use aero_dav::acltypes as acl;