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}