Skip to main content

io_webdav/rfc4918/
mkcol.rs

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