Skip to main content

io_webdav/rfc4918/
proppatch.rs

1//! Generic `PROPPATCH` coroutine (RFC 4918 ยง9.2).
2//!
3//! Sets each `(property, value)` pair against `path`; the request body
4//! is generated from the pairs. The multistatus body is not surfaced.
5//!
6//! # Example
7//!
8//! ```rust,no_run
9//! use std::{
10//!     io::{Read, Write},
11//!     net::TcpStream,
12//! };
13//!
14//! use io_webdav::{
15//!     coroutine::{WebdavCoroutine, WebdavCoroutineState, WebdavYield},
16//!     rfc4918::{DISPLAYNAME, WebdavAuth, proppatch::Proppatch},
17//! };
18//! use url::Url;
19//!
20//! // Ready stream needed (TCP-connected, TLS-negociated)
21//! let mut stream = TcpStream::connect("dav.example.org:443").unwrap();
22//! let mut buf = [0u8; 4096];
23//!
24//! let base_url: Url = "https://dav.example.org/".parse().unwrap();
25//! let auth = WebdavAuth::None;
26//! let mut coroutine =
27//!     Proppatch::new(&base_url, &auth, "io-webdav", "/dav/collection/", &[(DISPLAYNAME, "Renamed")]);
28//! let mut arg = None;
29//!
30//! loop {
31//!     match coroutine.resume(arg.take()) {
32//!         WebdavCoroutineState::Yielded(WebdavYield::WantsWrite(bytes)) => {
33//!             stream.write_all(&bytes).unwrap();
34//!         }
35//!         WebdavCoroutineState::Yielded(WebdavYield::WantsRead) => {
36//!             let n = stream.read(&mut buf).unwrap();
37//!             arg = Some(&buf[..n]);
38//!         }
39//!         WebdavCoroutineState::Complete(Ok(())) => break,
40//!         WebdavCoroutineState::Complete(Err(err)) => panic!("{err}"),
41//!     }
42//! }
43//! ```
44
45use log::trace;
46use url::Url;
47
48use crate::{
49    coroutine::*,
50    rfc4918::{
51        Property, WebdavAuth, proppatch_body,
52        request::WebdavRequest,
53        send::{SendError, SendRaw},
54    },
55    webdav_try,
56};
57
58/// Coroutine that runs a `PROPPATCH`.
59#[derive(Debug)]
60pub struct Proppatch {
61    state: State,
62}
63
64impl Proppatch {
65    /// Builds a new `PROPPATCH` coroutine setting each `(property,
66    /// value)` pair against `path`.
67    pub fn new(
68        base_url: &Url,
69        auth: &WebdavAuth,
70        user_agent: &str,
71        path: &str,
72        set: &[(Property, &str)],
73    ) -> Self {
74        let request = WebdavRequest::proppatch(base_url, auth, user_agent, path)
75            .content_type_xml()
76            .body(proppatch_body(set));
77        Self {
78            state: State::Send(SendRaw::new(request)),
79        }
80    }
81}
82
83impl WebdavCoroutine for Proppatch {
84    type Yield = WebdavYield;
85    type Return = Result<(), SendError>;
86
87    fn resume(&mut self, arg: Option<&[u8]>) -> WebdavCoroutineState<Self::Yield, Self::Return> {
88        trace!("sending request");
89        match &mut self.state {
90            State::Send(send) => {
91                webdav_try!(send, arg);
92                WebdavCoroutineState::Complete(Ok(()))
93            }
94        }
95    }
96}
97
98#[derive(Debug)]
99enum State {
100    Send(SendRaw),
101}