At least it compiles
This commit is contained in:
parent
9146537aaf
commit
1e3737a590
6 changed files with 369 additions and 47 deletions
100
src/dav/calencoder.rs
Normal file
100
src/dav/calencoder.rs
Normal file
|
@ -0,0 +1,100 @@
|
|||
use super::encoder::{QuickWritable, Context};
|
||||
use super::caltypes::*;
|
||||
use super::types::Extension;
|
||||
|
||||
use quick_xml::Error as QError;
|
||||
use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText};
|
||||
use quick_xml::writer::{ElementWriter, Writer};
|
||||
use quick_xml::name::PrefixDeclaration;
|
||||
use tokio::io::AsyncWrite;
|
||||
|
||||
/*pub trait CalWriter<E: Extension>: DavWriter<E> {
|
||||
fn create_cal_element(&mut self, name: &str) -> ElementWriter<impl AsyncWrite + Unpin>;
|
||||
}
|
||||
|
||||
impl<'a, W: AsyncWrite+Unpin> DavWriter<CalExtension> for Writer<'a, W, CalExtension> {
|
||||
fn create_dav_element(&mut self, name: &str) -> ElementWriter<impl AsyncWrite + Unpin> {
|
||||
self.create_ns_element(name, Namespace::Dav)
|
||||
}
|
||||
fn child(w: &'a mut QWriter<W>) -> impl DavWriter<CalExtension> {
|
||||
Self::child(w)
|
||||
}
|
||||
async fn error(&mut self, err: &Violation) -> Result<(), QError> {
|
||||
err.write(self).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, W: AsyncWrite+Unpin> CalWriter<CalExtension> for Writer<'a, W, CalExtension> {
|
||||
fn create_cal_element(&mut self, name: &str) -> ElementWriter<impl AsyncWrite + Unpin> {
|
||||
self.create_ns_element(name, Namespace::CalDav)
|
||||
}
|
||||
}*/
|
||||
|
||||
pub struct CalCtx {
|
||||
root: bool
|
||||
}
|
||||
impl Context<CalExtension> for CalCtx {
|
||||
fn child(&self) -> Self {
|
||||
Self { root: false }
|
||||
}
|
||||
fn create_dav_element(&self, name: &str) -> BytesStart {
|
||||
let mut start = BytesStart::new(format!("D:{}", name));
|
||||
if self.root {
|
||||
start.push_attribute(("xmlns:D", "DAV:"));
|
||||
start.push_attribute(("xmlns:C", "urn:ietf:params:xml:ns:caldav"));
|
||||
}
|
||||
start
|
||||
}
|
||||
|
||||
async fn hook_error(&self, err: &Violation, xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError> {
|
||||
err.write(xml, self.child()).await
|
||||
}
|
||||
}
|
||||
|
||||
impl QuickWritable<CalExtension, CalCtx> for Violation {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, _ctx: CalCtx) -> Result<(), QError> {
|
||||
match self {
|
||||
Self::SupportedFilter => xml
|
||||
.create_element("supported-filter")
|
||||
.write_empty_async().await?,
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<D:error>
|
||||
<C:supported-filter>
|
||||
<C:prop-filter name="X-ABC-GUID"/>
|
||||
</C:supported-filter>
|
||||
</D:error>
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::dav::types::{Error, Violation as DavViolation};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_violation() {
|
||||
let mut buffer = Vec::new();
|
||||
let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer);
|
||||
let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
|
||||
|
||||
let res: Error<CalExtension> = Error(vec![
|
||||
DavViolation::Extension(Violation::SupportedFilter),
|
||||
]);
|
||||
|
||||
res.write(&mut writer, CalCtx{ root: true }).await.expect("xml serialization");
|
||||
tokio_buffer.flush().await.expect("tokio buffer flush");
|
||||
|
||||
let expected = r#"<D:error xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<C:supported-filter/>
|
||||
</D:error>"#;
|
||||
let got = std::str::from_utf8(buffer.as_slice()).unwrap();
|
||||
|
||||
assert_eq!(got, expected);
|
||||
}
|
||||
}
|
41
src/dav/caltypes.rs
Normal file
41
src/dav/caltypes.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use super::types::*;
|
||||
|
||||
pub enum Namespace {
|
||||
Dav,
|
||||
CalDav,
|
||||
}
|
||||
|
||||
pub struct CalExtension {}
|
||||
impl Extension for CalExtension {
|
||||
type Error = Violation;
|
||||
type Namespace = Namespace;
|
||||
|
||||
fn namespaces() -> &'static [(&'static str, &'static str)] {
|
||||
return &[ ("D", "DAV:"), ("C", "urn:ietf:params:xml:ns:caldav") ][..]
|
||||
}
|
||||
|
||||
fn short_ns(ns: Self::Namespace) -> &'static str {
|
||||
match ns {
|
||||
Namespace::Dav => "D",
|
||||
Namespace::CalDav => "C",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Violation {
|
||||
/// (CALDAV:supported-filter): The CALDAV:comp-filter (see
|
||||
/// Section 9.7.1), CALDAV:prop-filter (see Section 9.7.2), and
|
||||
/// CALDAV:param-filter (see Section 9.7.3) XML elements used in the
|
||||
/// CALDAV:filter XML element (see Section 9.7) in the REPORT request
|
||||
/// only make reference to components, properties, and parameters for
|
||||
/// which queries are supported by the server, i.e., if the CALDAV:
|
||||
/// filter element attempts to reference an unsupported component,
|
||||
/// property, or parameter, this precondition is violated. Servers
|
||||
/// SHOULD report the CALDAV:comp-filter, CALDAV:prop-filter, or
|
||||
/// CALDAV:param-filter for which it does not provide support.
|
||||
///
|
||||
/// <!ELEMENT supported-filter (comp-filter*,
|
||||
/// prop-filter*,
|
||||
/// param-filter*)>
|
||||
SupportedFilter,
|
||||
}
|
|
@ -1,61 +1,205 @@
|
|||
use std::io::Cursor;
|
||||
|
||||
use futures::stream::{StreamExt, TryStreamExt};
|
||||
use quick_xml::Error;
|
||||
use quick_xml::Error as QError;
|
||||
use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText};
|
||||
use quick_xml::writer::{ElementWriter, Writer};
|
||||
use quick_xml::name::PrefixDeclaration;
|
||||
use tokio::io::AsyncWrite;
|
||||
use super::types::*;
|
||||
|
||||
//@FIXME a cleaner way to manager namespace would be great
|
||||
//but at the same time, the quick-xml library is not cooperating.
|
||||
//So instead of writing many cursed workarounds - I tried, I am just hardcoding the namespaces...
|
||||
|
||||
pub trait Encode {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite + Unpin>) -> Result<(), Error>;
|
||||
//-------------- TRAITS ----------------------
|
||||
/*pub trait DavWriter<E: Extension> {
|
||||
fn create_dav_element(&mut self, name: &str) -> ElementWriter<impl AsyncWrite + Unpin>;
|
||||
fn child(w: &mut QWriter<impl AsyncWrite + Unpin>) -> impl DavWriter<E>;
|
||||
async fn error(&mut self, err: &E::Error) -> Result<(), QError>;
|
||||
}*/
|
||||
|
||||
/// Basic encode trait to make a type encodable
|
||||
pub trait QuickWritable<E: Extension, C: Context<E>> {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError>;
|
||||
}
|
||||
|
||||
impl Encode for Href {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite + Unpin>) -> Result<(), Error> {
|
||||
xml.create_element("D:href")
|
||||
pub trait Context<E: Extension> {
|
||||
fn child(&self) -> Self;
|
||||
fn create_dav_element(&self, name: &str) -> BytesStart;
|
||||
async fn hook_error(&self, err: &E::Error, xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError>;
|
||||
}
|
||||
|
||||
pub struct NoExtCtx {
|
||||
root: bool
|
||||
}
|
||||
impl Context<NoExtension> for NoExtCtx {
|
||||
fn child(&self) -> Self {
|
||||
Self { root: false }
|
||||
}
|
||||
fn create_dav_element(&self, name: &str) -> BytesStart {
|
||||
let mut start = BytesStart::new(format!("D:{}", name));
|
||||
if self.root {
|
||||
start.push_attribute(("xmlns:D", "DAV:"));
|
||||
}
|
||||
start
|
||||
}
|
||||
async fn hook_error(&self, err: &Disabled, xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError> {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------- ENCODING --------------------
|
||||
|
||||
// --- XML ROOTS
|
||||
impl<E: Extension, C: Context<E>> QuickWritable<E,C> for Multistatus<E> {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
|
||||
let start = ctx.create_dav_element("multistatus");
|
||||
let end = start.to_end();
|
||||
|
||||
xml.write_event_async(Event::Start(start.clone())).await?;
|
||||
for response in self.responses.iter() {
|
||||
response.write(xml, ctx.child()).await?;
|
||||
}
|
||||
if let Some(description) = &self.responsedescription {
|
||||
description.write(xml, ctx.child()).await?;
|
||||
}
|
||||
|
||||
xml.write_event_async(Event::End(end)).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- XML inner elements
|
||||
impl<E: Extension, C: Context<E>> QuickWritable<E,C> for Href {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, _ctx: C) -> Result<(), QError> {
|
||||
xml.create_element("href")
|
||||
.write_text_content_async(BytesText::new(&self.0))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Encode for Multistatus<T> {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite + Unpin>) -> Result<(), Error> {
|
||||
xml.create_element("D:multistatus")
|
||||
.with_attribute(("xmlns:D", "DAV:"))
|
||||
.write_inner_content_async::<_, _, quick_xml::Error>(|inner_xml| async move {
|
||||
for response in self.responses.iter() {
|
||||
response.write(inner_xml).await?;
|
||||
impl<E: Extension, C: Context<E>> QuickWritable<E,C> for Response<E> {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
|
||||
xml.create_element("response")
|
||||
.write_inner_content_async::<_, _, QError>(|inner_xml| async move {
|
||||
self.href.write(inner_xml, ctx.child()).await?;
|
||||
self.status_or_propstat.write(inner_xml, ctx.child()).await?;
|
||||
if let Some(error) = &self.error {
|
||||
error.write(inner_xml, ctx.child()).await?;
|
||||
}
|
||||
|
||||
if let Some(description) = &self.responsedescription {
|
||||
description.write(inner_xml).await?;
|
||||
if let Some(responsedescription) = &self.responsedescription {
|
||||
responsedescription.write(inner_xml, ctx.child()).await?;
|
||||
}
|
||||
if let Some(location) = &self.location {
|
||||
location.write(inner_xml, ctx.child()).await?;
|
||||
}
|
||||
|
||||
Ok(inner_xml)
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Encode for Response<T> {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite + Unpin>) -> Result<(), Error> {
|
||||
impl<E: Extension, C: Context<E>> QuickWritable<E,C> for StatusOrPropstat<E> {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
|
||||
match self {
|
||||
Self::Status(status) => status.write(xml, ctx.child()).await,
|
||||
Self::PropStat(propstat_list) => {
|
||||
for propstat in propstat_list.iter() {
|
||||
propstat.write(xml, ctx.child()).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Extension, C: Context<E>> QuickWritable<E,C> for Status {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
|
||||
xml.create_element("status")
|
||||
.write_text_content_async(
|
||||
BytesText::new(&format!("HTTP/1.1 {} {}", self.0.as_str(), self.0.canonical_reason().unwrap_or("No reason")))
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Extension, C: Context<E>> QuickWritable<E,C> for ResponseDescription {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
|
||||
let start = ctx.create_dav_element("responsedescription");
|
||||
let end = start.to_end();
|
||||
|
||||
xml.write_event_async(Event::Start(start.clone())).await?;
|
||||
xml.write_event_async(Event::Text(BytesText::new(&self.0))).await?;
|
||||
xml.write_event_async(Event::End(end)).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Extension, C: Context<E>> QuickWritable<E,C> for Location {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode for ResponseDescription {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite + Unpin>) -> Result<(), Error> {
|
||||
xml.create_element("D:responsedescription")
|
||||
.write_text_content_async(BytesText::new(&self.0))
|
||||
impl<E: Extension, C: Context<E>> QuickWritable<E,C> for PropStat<E> {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Extension, C: Context<E>> QuickWritable<E,C> for Error<E> {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
|
||||
xml.create_element("error")
|
||||
.write_inner_content_async::<_, _, QError>(|inner_xml| async move {
|
||||
for violation in &self.0 {
|
||||
violation.write(inner_xml, ctx.child()).await?;
|
||||
}
|
||||
|
||||
Ok(inner_xml)
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Extension, C: Context<E>> QuickWritable<E,C> for Violation<E> {
|
||||
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
|
||||
match self {
|
||||
Violation::LockTokenMatchesRequestUri => xml.create_element("lock-token-matches-request-uri").write_empty_async().await?,
|
||||
Violation::LockTokenSubmitted(hrefs) => xml
|
||||
.create_element("lock-token-submitted")
|
||||
.write_inner_content_async::<_, _, QError>(|inner_xml| async move {
|
||||
for href in hrefs {
|
||||
href.write(inner_xml, ctx.child()).await?;
|
||||
}
|
||||
Ok(inner_xml)
|
||||
}
|
||||
).await?,
|
||||
Violation::NoConflictingLock(hrefs) => xml
|
||||
.create_element("no-conflicting-lock")
|
||||
.write_inner_content_async::<_, _, QError>(|inner_xml| async move {
|
||||
for href in hrefs {
|
||||
href.write(inner_xml, ctx.child()).await?;
|
||||
}
|
||||
Ok(inner_xml)
|
||||
}
|
||||
).await?,
|
||||
Violation::NoExternalEntities => xml.create_element("no-external-entities").write_empty_async().await?,
|
||||
Violation::PreservedLiveProperties => xml.create_element("preserved-live-properties").write_empty_async().await?,
|
||||
Violation::PropfindFiniteDepth => xml.create_element("propfind-finite-depth").write_empty_async().await?,
|
||||
Violation::CannotModifyProtectedProperty => xml.create_element("cannot-modify-protected-property").write_empty_async().await?,
|
||||
Violation::Extension(inner) => {
|
||||
ctx.hook_error(inner, xml).await?;
|
||||
xml
|
||||
},
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +218,8 @@ mod tests {
|
|||
let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer);
|
||||
let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
|
||||
|
||||
Href("/SOGo/dav/so/".into()).write(&mut writer).await.expect("xml serialization");
|
||||
let ctx = NoExtCtx{ root: true };
|
||||
Href("/SOGo/dav/so/".into()).write(&mut writer, ctx).await.expect("xml serialization");
|
||||
tokio_buffer.flush().await.expect("tokio buffer flush");
|
||||
|
||||
assert_eq!(buffer.as_slice(), &b"<D:href>/SOGo/dav/so/</D:href>"[..]);
|
||||
|
@ -87,8 +232,9 @@ mod tests {
|
|||
let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer);
|
||||
let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
|
||||
|
||||
let xml: Multistatus<u64> = Multistatus { responses: vec![], responsedescription: Some(ResponseDescription("Hello world".into())) };
|
||||
xml.write(&mut writer).await.expect("xml serialization");
|
||||
let ctx = NoExtCtx{ root: true };
|
||||
let xml: Multistatus<NoExtension> = Multistatus { responses: vec![], responsedescription: Some(ResponseDescription("Hello world".into())) };
|
||||
xml.write(&mut writer, ctx).await.expect("xml serialization");
|
||||
tokio_buffer.flush().await.expect("tokio buffer flush");
|
||||
|
||||
let expected = r#"<D:multistatus xmlns:D="DAV:">
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
mod types;
|
||||
mod caltypes;
|
||||
mod encoder;
|
||||
mod calencoder;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
|
|
|
@ -2,6 +2,34 @@
|
|||
|
||||
use chrono::{DateTime,FixedOffset};
|
||||
|
||||
/// Extension utilities
|
||||
pub struct Disabled(());
|
||||
pub trait Extension {
|
||||
type Error;
|
||||
type Namespace;
|
||||
|
||||
fn namespaces() -> &'static [(&'static str, &'static str)];
|
||||
fn short_ns(ns: Self::Namespace) -> &'static str;
|
||||
}
|
||||
|
||||
/// No extension
|
||||
pub struct NoExtension {}
|
||||
pub enum Namespace {
|
||||
Dav
|
||||
}
|
||||
impl Extension for NoExtension {
|
||||
type Error = Disabled;
|
||||
type Namespace = Namespace;
|
||||
|
||||
fn namespaces() -> &'static [(&'static str, &'static str)] {
|
||||
return &[ ("D", "DAV:") ][..]
|
||||
}
|
||||
|
||||
fn short_ns(ns: Self::Namespace) -> &'static str {
|
||||
"D"
|
||||
}
|
||||
}
|
||||
|
||||
/// 14.1. activelock XML Element
|
||||
///
|
||||
/// Name: activelock
|
||||
|
@ -10,11 +38,11 @@ use chrono::{DateTime,FixedOffset};
|
|||
/// <!ELEMENT activelock (lockscope, locktype, depth, owner?, timeout?,
|
||||
/// locktoken?, lockroot)>
|
||||
pub struct ActiveLock {
|
||||
lockscope: u64,
|
||||
locktype: u64,
|
||||
lockscope: LockScope,
|
||||
locktype: LockType,
|
||||
depth: Depth,
|
||||
owner: Option<u64>,
|
||||
timeout: Option<u64>,
|
||||
owner: Option<Owner>,
|
||||
timeout: Option<Timeout>,
|
||||
}
|
||||
|
||||
/// 14.2 allprop XML Element
|
||||
|
@ -72,7 +100,8 @@ pub enum Depth {
|
|||
/// postcondition code. Unrecognized elements MUST be ignored.
|
||||
///
|
||||
/// <!ELEMENT error ANY >
|
||||
pub enum Error<T> {
|
||||
pub struct Error<T: Extension>(pub Vec<Violation<T>>);
|
||||
pub enum Violation<T: Extension> {
|
||||
/// Name: lock-token-matches-request-uri
|
||||
///
|
||||
/// Use with: 409 Conflict
|
||||
|
@ -156,7 +185,7 @@ pub enum Error<T> {
|
|||
CannotModifyProtectedProperty,
|
||||
|
||||
/// Specific errors
|
||||
Extensions(T),
|
||||
Extension(T::Error),
|
||||
}
|
||||
|
||||
/// 14.6. exclusive XML Element
|
||||
|
@ -312,7 +341,7 @@ pub enum LockType {
|
|||
/// response descriptions contained within the responses.
|
||||
///
|
||||
/// <!ELEMENT multistatus (response*, responsedescription?) >
|
||||
pub struct Multistatus<T> {
|
||||
pub struct Multistatus<T: Extension> {
|
||||
pub responses: Vec<Response<T>>,
|
||||
pub responsedescription: Option<ResponseDescription>,
|
||||
}
|
||||
|
@ -416,7 +445,7 @@ pub struct PropName {}
|
|||
/// the properties named in 'prop'.
|
||||
///
|
||||
/// <!ELEMENT propstat (prop, status, error?, responsedescription?) >
|
||||
pub struct PropStat<T> {
|
||||
pub struct PropStat<T: Extension> {
|
||||
prop: Prop,
|
||||
status: Status,
|
||||
error: Option<Error<T>>,
|
||||
|
@ -460,13 +489,16 @@ pub struct Remove(Prop);
|
|||
///
|
||||
/// <!ELEMENT response (href, ((href*, status)|(propstat+)),
|
||||
/// error?, responsedescription? , location?) >
|
||||
pub struct Response<T> {
|
||||
href: Vec<Href>,
|
||||
status: Status,
|
||||
propstat: Vec<PropStat<T>>,
|
||||
error: Option<Error<T>>,
|
||||
responsedescription: Option<ResponseDescription>,
|
||||
location: Option<u64>,
|
||||
pub enum StatusOrPropstat<T: Extension> {
|
||||
Status(Status),
|
||||
PropStat(Vec<PropStat<T>>),
|
||||
}
|
||||
pub struct Response<T: Extension> {
|
||||
pub href: Href, // It's wrong according to the spec, but I don't understand why there is an href*
|
||||
pub status_or_propstat: StatusOrPropstat<T>,
|
||||
pub error: Option<Error<T>>,
|
||||
pub responsedescription: Option<ResponseDescription>,
|
||||
pub location: Option<Location>,
|
||||
}
|
||||
|
||||
/// 14.25. responsedescription XML Element
|
||||
|
@ -521,7 +553,7 @@ pub struct Shared {}
|
|||
///
|
||||
/// <!ELEMENT status (#PCDATA) >
|
||||
//@FIXME: Better typing is possible with an enum for example
|
||||
pub struct Status(http::status::StatusCode);
|
||||
pub struct Status(pub http::status::StatusCode);
|
||||
|
||||
/// 14.29. timeout XML Element
|
||||
///
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(async_fn_in_trait)]
|
||||
|
||||
mod auth;
|
||||
|
|
Loading…
Reference in a new issue