basic propfind
This commit is contained in:
parent
902d33c434
commit
f372a95b01
5 changed files with 153 additions and 88 deletions
|
@ -108,13 +108,13 @@ pub struct CalendarMultiget<E: dav::Extension> {
|
||||||
pub struct FreeBusyQuery(pub TimeRange);
|
pub struct FreeBusyQuery(pub TimeRange);
|
||||||
|
|
||||||
// ----- Hooks -----
|
// ----- Hooks -----
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum ResourceType {
|
pub enum ResourceType {
|
||||||
Calendar,
|
Calendar,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the matching Property object for documentation
|
/// Check the matching Property object for documentation
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum PropertyRequest {
|
pub enum PropertyRequest {
|
||||||
CalendarDescription,
|
CalendarDescription,
|
||||||
CalendarTimezone,
|
CalendarTimezone,
|
||||||
|
@ -129,7 +129,7 @@ pub enum PropertyRequest {
|
||||||
CalendarData(CalendarDataRequest),
|
CalendarData(CalendarDataRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Property {
|
pub enum Property {
|
||||||
/// Name: calendar-description
|
/// Name: calendar-description
|
||||||
///
|
///
|
||||||
|
@ -609,7 +609,7 @@ pub enum Property {
|
||||||
CalendarData(CalendarDataPayload),
|
CalendarData(CalendarDataPayload),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Violation {
|
pub enum Violation {
|
||||||
/// (DAV:resource-must-be-null): A resource MUST NOT exist at the
|
/// (DAV:resource-must-be-null): A resource MUST NOT exist at the
|
||||||
/// Request-URI;
|
/// Request-URI;
|
||||||
|
@ -780,7 +780,7 @@ pub enum Violation {
|
||||||
/// If the client chooses a collation not supported by the server, the
|
/// If the client chooses a collation not supported by the server, the
|
||||||
/// server MUST respond with a CALDAV:supported-collation precondition
|
/// server MUST respond with a CALDAV:supported-collation precondition
|
||||||
/// error response.
|
/// error response.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct SupportedCollation(pub Collation);
|
pub struct SupportedCollation(pub Collation);
|
||||||
|
|
||||||
/// <!ELEMENT calendar-data (#PCDATA)>
|
/// <!ELEMENT calendar-data (#PCDATA)>
|
||||||
|
@ -789,7 +789,7 @@ pub struct SupportedCollation(pub Collation);
|
||||||
/// when nested in the DAV:prop XML element in a calendaring
|
/// when nested in the DAV:prop XML element in a calendaring
|
||||||
/// REPORT response to specify the content of a returned
|
/// REPORT response to specify the content of a returned
|
||||||
/// calendar object resource.
|
/// calendar object resource.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct CalendarDataPayload {
|
pub struct CalendarDataPayload {
|
||||||
pub mime: Option<CalendarDataSupport>,
|
pub mime: Option<CalendarDataSupport>,
|
||||||
pub payload: String,
|
pub payload: String,
|
||||||
|
@ -802,7 +802,7 @@ pub struct CalendarDataPayload {
|
||||||
/// when nested in the DAV:prop XML element in a calendaring
|
/// when nested in the DAV:prop XML element in a calendaring
|
||||||
/// REPORT request to specify which parts of calendar object
|
/// REPORT request to specify which parts of calendar object
|
||||||
/// resources should be returned in the response;
|
/// resources should be returned in the response;
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct CalendarDataRequest {
|
pub struct CalendarDataRequest {
|
||||||
pub mime: Option<CalendarDataSupport>,
|
pub mime: Option<CalendarDataSupport>,
|
||||||
pub comp: Option<Comp>,
|
pub comp: Option<Comp>,
|
||||||
|
@ -817,7 +817,7 @@ pub struct CalendarDataRequest {
|
||||||
/// when nested in the CALDAV:supported-calendar-data property
|
/// when nested in the CALDAV:supported-calendar-data property
|
||||||
/// to specify a supported media type for calendar object
|
/// to specify a supported media type for calendar object
|
||||||
/// resources;
|
/// resources;
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct CalendarDataEmpty(pub Option<CalendarDataSupport>);
|
pub struct CalendarDataEmpty(pub Option<CalendarDataSupport>);
|
||||||
|
|
||||||
/// <!ATTLIST calendar-data content-type CDATA "text/calendar"
|
/// <!ATTLIST calendar-data content-type CDATA "text/calendar"
|
||||||
|
@ -826,7 +826,7 @@ pub struct CalendarDataEmpty(pub Option<CalendarDataSupport>);
|
||||||
/// version value: a version string
|
/// version value: a version string
|
||||||
/// attributes can be used on all three variants of the
|
/// attributes can be used on all three variants of the
|
||||||
/// CALDAV:calendar-data XML element.
|
/// CALDAV:calendar-data XML element.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct CalendarDataSupport {
|
pub struct CalendarDataSupport {
|
||||||
pub content_type: String,
|
pub content_type: String,
|
||||||
pub version: String,
|
pub version: String,
|
||||||
|
@ -852,7 +852,7 @@ pub struct CalendarDataSupport {
|
||||||
/// However, the CALDAV:prop and CALDAV:allprop elements are defined
|
/// However, the CALDAV:prop and CALDAV:allprop elements are defined
|
||||||
/// in the "urn:ietf:params:xml:ns:caldav" namespace instead of the
|
/// in the "urn:ietf:params:xml:ns:caldav" namespace instead of the
|
||||||
/// "DAV:" namespace.
|
/// "DAV:" namespace.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Comp {
|
pub struct Comp {
|
||||||
pub name: Component,
|
pub name: Component,
|
||||||
pub prop_kind: Option<PropKind>,
|
pub prop_kind: Option<PropKind>,
|
||||||
|
@ -872,7 +872,7 @@ pub struct Comp {
|
||||||
/// <C:comp name="VEVENT"/>
|
/// <C:comp name="VEVENT"/>
|
||||||
/// <C:comp name="VTODO"/>
|
/// <C:comp name="VTODO"/>
|
||||||
/// </C:supported-calendar-component-set>
|
/// </C:supported-calendar-component-set>
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct CompSupport(pub Component);
|
pub struct CompSupport(pub Component);
|
||||||
|
|
||||||
/// Name: allcomp
|
/// Name: allcomp
|
||||||
|
@ -888,7 +888,7 @@ pub struct CompSupport(pub Component);
|
||||||
/// Definition:
|
/// Definition:
|
||||||
///
|
///
|
||||||
/// <!ELEMENT allcomp EMPTY>
|
/// <!ELEMENT allcomp EMPTY>
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum CompKind {
|
pub enum CompKind {
|
||||||
AllComp,
|
AllComp,
|
||||||
Comp(Vec<Comp>),
|
Comp(Vec<Comp>),
|
||||||
|
@ -912,7 +912,7 @@ pub enum CompKind {
|
||||||
/// allprop element defined in [RFC2518]. However, the CALDAV:allprop
|
/// allprop element defined in [RFC2518]. However, the CALDAV:allprop
|
||||||
/// element is defined in the "urn:ietf:params:xml:ns:caldav"
|
/// element is defined in the "urn:ietf:params:xml:ns:caldav"
|
||||||
/// namespace instead of the "DAV:" namespace.
|
/// namespace instead of the "DAV:" namespace.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum PropKind {
|
pub enum PropKind {
|
||||||
AllProp,
|
AllProp,
|
||||||
Prop(Vec<CalProp>),
|
Prop(Vec<CalProp>),
|
||||||
|
@ -942,13 +942,13 @@ pub enum PropKind {
|
||||||
/// element defined in [RFC2518]. However, the CALDAV:prop element is
|
/// element defined in [RFC2518]. However, the CALDAV:prop element is
|
||||||
/// defined in the "urn:ietf:params:xml:ns:caldav" namespace instead
|
/// defined in the "urn:ietf:params:xml:ns:caldav" namespace instead
|
||||||
/// of the "DAV:" namespace.
|
/// of the "DAV:" namespace.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct CalProp {
|
pub struct CalProp {
|
||||||
pub name: ComponentProperty,
|
pub name: ComponentProperty,
|
||||||
pub novalue: Option<bool>,
|
pub novalue: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum RecurrenceModifier {
|
pub enum RecurrenceModifier {
|
||||||
Expand(Expand),
|
Expand(Expand),
|
||||||
LimitRecurrenceSet(LimitRecurrenceSet),
|
LimitRecurrenceSet(LimitRecurrenceSet),
|
||||||
|
@ -994,7 +994,7 @@ pub enum RecurrenceModifier {
|
||||||
/// end CDATA #REQUIRED>
|
/// end CDATA #REQUIRED>
|
||||||
/// start value: an iCalendar "date with UTC time"
|
/// start value: an iCalendar "date with UTC time"
|
||||||
/// end value: an iCalendar "date with UTC time"
|
/// end value: an iCalendar "date with UTC time"
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Expand(pub DateTime<Utc>, pub DateTime<Utc>);
|
pub struct Expand(pub DateTime<Utc>, pub DateTime<Utc>);
|
||||||
|
|
||||||
/// CALDAV:limit-recurrence-set XML Element
|
/// CALDAV:limit-recurrence-set XML Element
|
||||||
|
@ -1042,7 +1042,7 @@ pub struct Expand(pub DateTime<Utc>, pub DateTime<Utc>);
|
||||||
/// end CDATA #REQUIRED>
|
/// end CDATA #REQUIRED>
|
||||||
/// start value: an iCalendar "date with UTC time"
|
/// start value: an iCalendar "date with UTC time"
|
||||||
/// end value: an iCalendar "date with UTC time"
|
/// end value: an iCalendar "date with UTC time"
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct LimitRecurrenceSet(pub DateTime<Utc>, pub DateTime<Utc>);
|
pub struct LimitRecurrenceSet(pub DateTime<Utc>, pub DateTime<Utc>);
|
||||||
|
|
||||||
/// Name: limit-freebusy-set
|
/// Name: limit-freebusy-set
|
||||||
|
@ -1073,11 +1073,11 @@ pub struct LimitRecurrenceSet(pub DateTime<Utc>, pub DateTime<Utc>);
|
||||||
/// end CDATA #REQUIRED>
|
/// end CDATA #REQUIRED>
|
||||||
/// start value: an iCalendar "date with UTC time"
|
/// start value: an iCalendar "date with UTC time"
|
||||||
/// end value: an iCalendar "date with UTC time"
|
/// end value: an iCalendar "date with UTC time"
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct LimitFreebusySet(pub DateTime<Utc>, pub DateTime<Utc>);
|
pub struct LimitFreebusySet(pub DateTime<Utc>, pub DateTime<Utc>);
|
||||||
|
|
||||||
/// Used by CalendarQuery & CalendarMultiget
|
/// Used by CalendarQuery & CalendarMultiget
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum CalendarSelector<E: dav::Extension> {
|
pub enum CalendarSelector<E: dav::Extension> {
|
||||||
AllProp,
|
AllProp,
|
||||||
PropName,
|
PropName,
|
||||||
|
@ -1135,20 +1135,20 @@ pub enum CalendarSelector<E: dav::Extension> {
|
||||||
/// name value: a calendar object or calendar component
|
/// name value: a calendar object or calendar component
|
||||||
/// type (e.g., VEVENT)
|
/// type (e.g., VEVENT)
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct CompFilter {
|
pub struct CompFilter {
|
||||||
pub name: Component,
|
pub name: Component,
|
||||||
// Option 1 = None, Option 2, 3, 4 = Some
|
// Option 1 = None, Option 2, 3, 4 = Some
|
||||||
pub additional_rules: Option<CompFilterRules>,
|
pub additional_rules: Option<CompFilterRules>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum CompFilterRules {
|
pub enum CompFilterRules {
|
||||||
// Option 2
|
// Option 2
|
||||||
IsNotDefined,
|
IsNotDefined,
|
||||||
// Options 3 & 4
|
// Options 3 & 4
|
||||||
Matches(CompFilterMatch),
|
Matches(CompFilterMatch),
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct CompFilterMatch {
|
pub struct CompFilterMatch {
|
||||||
pub time_range: Option<TimeRange>,
|
pub time_range: Option<TimeRange>,
|
||||||
pub prop_filter: Vec<PropFilter>,
|
pub prop_filter: Vec<PropFilter>,
|
||||||
|
@ -1201,26 +1201,26 @@ pub struct CompFilterMatch {
|
||||||
/// <!ATTLIST prop-filter name CDATA #REQUIRED>
|
/// <!ATTLIST prop-filter name CDATA #REQUIRED>
|
||||||
/// name value: a calendar property name (e.g., ATTENDEE)
|
/// name value: a calendar property name (e.g., ATTENDEE)
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct PropFilter {
|
pub struct PropFilter {
|
||||||
pub name: ComponentProperty,
|
pub name: ComponentProperty,
|
||||||
// None = Option 1, Some() = Option 2, 3 & 4
|
// None = Option 1, Some() = Option 2, 3 & 4
|
||||||
pub additional_rules: Option<PropFilterRules>,
|
pub additional_rules: Option<PropFilterRules>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum PropFilterRules {
|
pub enum PropFilterRules {
|
||||||
// Option 2
|
// Option 2
|
||||||
IsNotDefined,
|
IsNotDefined,
|
||||||
// Options 3 & 4
|
// Options 3 & 4
|
||||||
Match(PropFilterMatch),
|
Match(PropFilterMatch),
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct PropFilterMatch {
|
pub struct PropFilterMatch {
|
||||||
pub time_range: Option<TimeRange>,
|
pub time_range: Option<TimeRange>,
|
||||||
pub time_or_text: Option<TimeOrText>,
|
pub time_or_text: Option<TimeOrText>,
|
||||||
pub param_filter: Vec<ParamFilter>,
|
pub param_filter: Vec<ParamFilter>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum TimeOrText {
|
pub enum TimeOrText {
|
||||||
Time(TimeRange),
|
Time(TimeRange),
|
||||||
Text(TextMatch),
|
Text(TextMatch),
|
||||||
|
@ -1254,7 +1254,7 @@ pub enum TimeOrText {
|
||||||
/// PCDATA value: string
|
/// PCDATA value: string
|
||||||
/// <!ATTLIST text-match collation CDATA "i;ascii-casemap"
|
/// <!ATTLIST text-match collation CDATA "i;ascii-casemap"
|
||||||
/// negate-condition (yes | no) "no">
|
/// negate-condition (yes | no) "no">
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct TextMatch {
|
pub struct TextMatch {
|
||||||
pub collation: Option<Collation>,
|
pub collation: Option<Collation>,
|
||||||
pub negate_condition: Option<bool>,
|
pub negate_condition: Option<bool>,
|
||||||
|
@ -1292,12 +1292,12 @@ pub struct TextMatch {
|
||||||
/// <!ATTLIST param-filter name CDATA #REQUIRED>
|
/// <!ATTLIST param-filter name CDATA #REQUIRED>
|
||||||
/// name value: a property parameter name (e.g., PARTSTAT)
|
/// name value: a property parameter name (e.g., PARTSTAT)
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct ParamFilter {
|
pub struct ParamFilter {
|
||||||
pub name: PropertyParameter,
|
pub name: PropertyParameter,
|
||||||
pub additional_rules: Option<ParamFilterMatch>,
|
pub additional_rules: Option<ParamFilterMatch>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum ParamFilterMatch {
|
pub enum ParamFilterMatch {
|
||||||
IsNotDefined,
|
IsNotDefined,
|
||||||
Match(TextMatch),
|
Match(TextMatch),
|
||||||
|
@ -1353,7 +1353,7 @@ pub enum ParamFilterMatch {
|
||||||
///
|
///
|
||||||
/// <!ELEMENT timezone (#PCDATA)>
|
/// <!ELEMENT timezone (#PCDATA)>
|
||||||
/// PCDATA value: an iCalendar object with exactly one VTIMEZONE
|
/// PCDATA value: an iCalendar object with exactly one VTIMEZONE
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct TimeZone(pub String);
|
pub struct TimeZone(pub String);
|
||||||
|
|
||||||
/// Name: filter
|
/// Name: filter
|
||||||
|
@ -1369,7 +1369,7 @@ pub struct TimeZone(pub String);
|
||||||
///
|
///
|
||||||
/// Definition:
|
/// Definition:
|
||||||
/// <!ELEMENT filter (comp-filter)>
|
/// <!ELEMENT filter (comp-filter)>
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Filter(pub CompFilter);
|
pub struct Filter(pub CompFilter);
|
||||||
|
|
||||||
/// Name: time-range
|
/// Name: time-range
|
||||||
|
@ -1381,7 +1381,7 @@ pub struct Filter(pub CompFilter);
|
||||||
/// end CDATA #IMPLIED>
|
/// end CDATA #IMPLIED>
|
||||||
/// start value: an iCalendar "date with UTC time"
|
/// start value: an iCalendar "date with UTC time"
|
||||||
/// end value: an iCalendar "date with UTC time"
|
/// end value: an iCalendar "date with UTC time"
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum TimeRange {
|
pub enum TimeRange {
|
||||||
OnlyStart(DateTime<Utc>),
|
OnlyStart(DateTime<Utc>),
|
||||||
OnlyEnd(DateTime<Utc>),
|
OnlyEnd(DateTime<Utc>),
|
||||||
|
@ -1391,7 +1391,7 @@ pub enum TimeRange {
|
||||||
// ----------------------- ENUM ATTRIBUTES ---------------------
|
// ----------------------- ENUM ATTRIBUTES ---------------------
|
||||||
|
|
||||||
/// Known components
|
/// Known components
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Component {
|
pub enum Component {
|
||||||
VCalendar,
|
VCalendar,
|
||||||
VJournal,
|
VJournal,
|
||||||
|
@ -1432,11 +1432,11 @@ impl Component {
|
||||||
/// name="VERSION", name="SUMMARY", etc.
|
/// name="VERSION", name="SUMMARY", etc.
|
||||||
/// Can be set on different objects: VCalendar, VEvent, etc.
|
/// Can be set on different objects: VCalendar, VEvent, etc.
|
||||||
/// Might be replaced by an enum later
|
/// Might be replaced by an enum later
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct ComponentProperty(pub String);
|
pub struct ComponentProperty(pub String);
|
||||||
|
|
||||||
/// like PARSTAT
|
/// like PARSTAT
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct PropertyParameter(pub String);
|
pub struct PropertyParameter(pub String);
|
||||||
impl PropertyParameter {
|
impl PropertyParameter {
|
||||||
pub fn as_str<'a>(&'a self) -> &'a str {
|
pub fn as_str<'a>(&'a self) -> &'a str {
|
||||||
|
@ -1444,7 +1444,7 @@ impl PropertyParameter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default,Debug,PartialEq)]
|
#[derive(Default,Debug,PartialEq,Clone)]
|
||||||
pub enum Collation {
|
pub enum Collation {
|
||||||
#[default]
|
#[default]
|
||||||
AsciiCaseMap,
|
AsciiCaseMap,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use super::caltypes as cal;
|
||||||
use super::xml;
|
use super::xml;
|
||||||
use super::error;
|
use super::error;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Disabled(());
|
pub struct Disabled(());
|
||||||
impl xml::QRead<Disabled> for Disabled {
|
impl xml::QRead<Disabled> for Disabled {
|
||||||
async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
|
async fn qread(_xml: &mut xml::Reader<impl xml::IRead>) -> Result<Self, error::ParsingError> {
|
||||||
|
@ -20,7 +20,7 @@ impl xml::QWrite for Disabled {
|
||||||
///
|
///
|
||||||
/// Any extension is kooh is disabled through an object we can't build
|
/// Any extension is kooh is disabled through an object we can't build
|
||||||
/// due to a private inner element.
|
/// due to a private inner element.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Core {}
|
pub struct Core {}
|
||||||
impl dav::Extension for Core {
|
impl dav::Extension for Core {
|
||||||
type Error = Disabled;
|
type Error = Disabled;
|
||||||
|
@ -30,7 +30,7 @@ impl dav::Extension for Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebDAV with the base Calendar implementation (RFC4791)
|
// WebDAV with the base Calendar implementation (RFC4791)
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Calendar {}
|
pub struct Calendar {}
|
||||||
impl dav::Extension for Calendar
|
impl dav::Extension for Calendar
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@ use super::xml;
|
||||||
|
|
||||||
/// It's how we implement a DAV extension
|
/// It's how we implement a DAV extension
|
||||||
/// (That's the dark magic part...)
|
/// (That's the dark magic part...)
|
||||||
pub trait Extension: std::fmt::Debug + PartialEq {
|
pub trait Extension: std::fmt::Debug + PartialEq + Clone {
|
||||||
type Error: xml::Node<Self::Error>;
|
type Error: xml::Node<Self::Error>;
|
||||||
type Property: xml::Node<Self::Property>;
|
type Property: xml::Node<Self::Property>;
|
||||||
type PropertyRequest: xml::Node<Self::PropertyRequest>;
|
type PropertyRequest: xml::Node<Self::PropertyRequest>;
|
||||||
|
@ -20,7 +20,7 @@ pub trait Extension: std::fmt::Debug + PartialEq {
|
||||||
/// Purpose: Describes a lock on a resource.
|
/// Purpose: Describes a lock on a resource.
|
||||||
/// <!ELEMENT activelock (lockscope, locktype, depth, owner?, timeout?,
|
/// <!ELEMENT activelock (lockscope, locktype, depth, owner?, timeout?,
|
||||||
/// locktoken?, lockroot)>
|
/// locktoken?, lockroot)>
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct ActiveLock {
|
pub struct ActiveLock {
|
||||||
pub lockscope: LockScope,
|
pub lockscope: LockScope,
|
||||||
pub locktype: LockType,
|
pub locktype: LockType,
|
||||||
|
@ -54,7 +54,7 @@ pub struct Collection{}
|
||||||
/// Value: "0" | "1" | "infinity"
|
/// Value: "0" | "1" | "infinity"
|
||||||
///
|
///
|
||||||
/// <!ELEMENT depth (#PCDATA) >
|
/// <!ELEMENT depth (#PCDATA) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Depth {
|
pub enum Depth {
|
||||||
Zero,
|
Zero,
|
||||||
One,
|
One,
|
||||||
|
@ -77,9 +77,9 @@ pub enum Depth {
|
||||||
/// postcondition code. Unrecognized elements MUST be ignored.
|
/// postcondition code. Unrecognized elements MUST be ignored.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT error ANY >
|
/// <!ELEMENT error ANY >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Error<E: Extension>(pub Vec<Violation<E>>);
|
pub struct Error<E: Extension>(pub Vec<Violation<E>>);
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Violation<E: Extension> {
|
pub enum Violation<E: Extension> {
|
||||||
/// Name: lock-token-matches-request-uri
|
/// Name: lock-token-matches-request-uri
|
||||||
///
|
///
|
||||||
|
@ -190,7 +190,7 @@ pub struct Exclusive {}
|
||||||
/// Value: Simple-ref
|
/// Value: Simple-ref
|
||||||
///
|
///
|
||||||
/// <!ELEMENT href (#PCDATA)>
|
/// <!ELEMENT href (#PCDATA)>
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Href(pub String);
|
pub struct Href(pub String);
|
||||||
|
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ pub struct Href(pub String);
|
||||||
/// standards. This element MUST NOT contain text or mixed content.
|
/// standards. This element MUST NOT contain text or mixed content.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT include ANY >
|
/// <!ELEMENT include ANY >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Include<E: Extension>(pub Vec<PropertyRequest<E>>);
|
pub struct Include<E: Extension>(pub Vec<PropertyRequest<E>>);
|
||||||
|
|
||||||
/// 14.9. location XML Element
|
/// 14.9. location XML Element
|
||||||
|
@ -223,7 +223,7 @@ pub struct Include<E: Extension>(pub Vec<PropertyRequest<E>>);
|
||||||
/// that would be used in a Location header.
|
/// that would be used in a Location header.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT location (href)>
|
/// <!ELEMENT location (href)>
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Location(pub Href);
|
pub struct Location(pub Href);
|
||||||
|
|
||||||
/// 14.10. lockentry XML Element
|
/// 14.10. lockentry XML Element
|
||||||
|
@ -234,7 +234,7 @@ pub struct Location(pub Href);
|
||||||
/// resource.
|
/// resource.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT lockentry (lockscope, locktype) >
|
/// <!ELEMENT lockentry (lockscope, locktype) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct LockEntry {
|
pub struct LockEntry {
|
||||||
pub lockscope: LockScope,
|
pub lockscope: LockScope,
|
||||||
pub locktype: LockType,
|
pub locktype: LockType,
|
||||||
|
@ -248,7 +248,7 @@ pub struct LockEntry {
|
||||||
/// specify the type of lock the client wishes to have created.
|
/// specify the type of lock the client wishes to have created.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT lockinfo (lockscope, locktype, owner?) >
|
/// <!ELEMENT lockinfo (lockscope, locktype, owner?) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct LockInfo {
|
pub struct LockInfo {
|
||||||
pub lockscope: LockScope,
|
pub lockscope: LockScope,
|
||||||
pub locktype: LockType,
|
pub locktype: LockType,
|
||||||
|
@ -267,7 +267,7 @@ pub struct LockInfo {
|
||||||
/// values and the response to LOCK requests.
|
/// values and the response to LOCK requests.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT lockroot (href) >
|
/// <!ELEMENT lockroot (href) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct LockRoot(pub Href);
|
pub struct LockRoot(pub Href);
|
||||||
|
|
||||||
/// 14.13. lockscope XML Element
|
/// 14.13. lockscope XML Element
|
||||||
|
@ -277,7 +277,7 @@ pub struct LockRoot(pub Href);
|
||||||
/// Purpose: Specifies whether a lock is an exclusive lock, or a shared
|
/// Purpose: Specifies whether a lock is an exclusive lock, or a shared
|
||||||
/// lock.
|
/// lock.
|
||||||
/// <!ELEMENT lockscope (exclusive | shared) >
|
/// <!ELEMENT lockscope (exclusive | shared) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum LockScope {
|
pub enum LockScope {
|
||||||
Exclusive,
|
Exclusive,
|
||||||
Shared
|
Shared
|
||||||
|
@ -293,7 +293,7 @@ pub enum LockScope {
|
||||||
/// refers to the lock.
|
/// refers to the lock.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT locktoken (href) >
|
/// <!ELEMENT locktoken (href) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct LockToken(pub Href);
|
pub struct LockToken(pub Href);
|
||||||
|
|
||||||
/// 14.15. locktype XML Element
|
/// 14.15. locktype XML Element
|
||||||
|
@ -304,7 +304,7 @@ pub struct LockToken(pub Href);
|
||||||
/// specification only defines one lock type, the write lock.
|
/// specification only defines one lock type, the write lock.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT locktype (write) >
|
/// <!ELEMENT locktype (write) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum LockType {
|
pub enum LockType {
|
||||||
/// 14.30. write XML Element
|
/// 14.30. write XML Element
|
||||||
///
|
///
|
||||||
|
@ -330,7 +330,7 @@ pub enum LockType {
|
||||||
/// response descriptions contained within the responses.
|
/// response descriptions contained within the responses.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT multistatus (response*, responsedescription?) >
|
/// <!ELEMENT multistatus (response*, responsedescription?) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Multistatus<E: Extension, N: xml::Node<N>> {
|
pub struct Multistatus<E: Extension, N: xml::Node<N>> {
|
||||||
pub responses: Vec<Response<E, N>>,
|
pub responses: Vec<Response<E, N>>,
|
||||||
pub responsedescription: Option<ResponseDescription>,
|
pub responsedescription: Option<ResponseDescription>,
|
||||||
|
@ -360,7 +360,7 @@ pub struct Multistatus<E: Extension, N: xml::Node<N>> {
|
||||||
///
|
///
|
||||||
/// <!ELEMENT owner ANY >
|
/// <!ELEMENT owner ANY >
|
||||||
//@FIXME might need support for an extension
|
//@FIXME might need support for an extension
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Owner {
|
pub enum Owner {
|
||||||
Txt(String),
|
Txt(String),
|
||||||
Href(Href),
|
Href(Href),
|
||||||
|
@ -381,10 +381,10 @@ pub enum Owner {
|
||||||
/// text or mixed content.
|
/// text or mixed content.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT prop ANY >
|
/// <!ELEMENT prop ANY >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct PropName<E: Extension>(pub Vec<PropertyRequest<E>>);
|
pub struct PropName<E: Extension>(pub Vec<PropertyRequest<E>>);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct PropValue<E: Extension>(pub Vec<Property<E>>);
|
pub struct PropValue<E: Extension>(pub Vec<Property<E>>);
|
||||||
|
|
||||||
/// 14.19. propertyupdate XML Element
|
/// 14.19. propertyupdate XML Element
|
||||||
|
@ -397,10 +397,10 @@ pub struct PropValue<E: Extension>(pub Vec<Property<E>>);
|
||||||
/// required to modify the properties on the resource.
|
/// required to modify the properties on the resource.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT propertyupdate (remove | set)+ >
|
/// <!ELEMENT propertyupdate (remove | set)+ >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct PropertyUpdate<E: Extension>(pub Vec<PropertyUpdateItem<E>>);
|
pub struct PropertyUpdate<E: Extension>(pub Vec<PropertyUpdateItem<E>>);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum PropertyUpdateItem<E: Extension> {
|
pub enum PropertyUpdateItem<E: Extension> {
|
||||||
Remove(Remove<E>),
|
Remove(Remove<E>),
|
||||||
Set(Set<E>),
|
Set(Set<E>),
|
||||||
|
@ -440,7 +440,7 @@ pub enum PropertyUpdateItem<E: Extension> {
|
||||||
/// values.
|
/// values.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT propfind ( propname | (allprop, include?) | prop ) >
|
/// <!ELEMENT propfind ( propname | (allprop, include?) | prop ) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum PropFind<E: Extension> {
|
pub enum PropFind<E: Extension> {
|
||||||
PropName,
|
PropName,
|
||||||
AllProp(Option<Include<E>>),
|
AllProp(Option<Include<E>>),
|
||||||
|
@ -462,7 +462,7 @@ pub enum PropFind<E: Extension> {
|
||||||
/// the properties named in 'prop'.
|
/// the properties named in 'prop'.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT propstat (prop, status, error?, responsedescription?) >
|
/// <!ELEMENT propstat (prop, status, error?, responsedescription?) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct PropStat<E: Extension, N: xml::Node<N>> {
|
pub struct PropStat<E: Extension, N: xml::Node<N>> {
|
||||||
pub prop: N,
|
pub prop: N,
|
||||||
pub status: Status,
|
pub status: Status,
|
||||||
|
@ -483,7 +483,7 @@ pub struct PropStat<E: Extension, N: xml::Node<N>> {
|
||||||
/// the names of properties to be removed are required.
|
/// the names of properties to be removed are required.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT remove (prop) >
|
/// <!ELEMENT remove (prop) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Remove<E: Extension>(pub PropName<E>);
|
pub struct Remove<E: Extension>(pub PropName<E>);
|
||||||
|
|
||||||
/// 14.24. response XML Element
|
/// 14.24. response XML Element
|
||||||
|
@ -511,7 +511,7 @@ pub struct Remove<E: Extension>(pub PropName<E>);
|
||||||
///
|
///
|
||||||
/// --- rewritten as ---
|
/// --- rewritten as ---
|
||||||
/// <!ELEMENT response ((href+, status)|(href, propstat+), error?, responsedescription?, location?>
|
/// <!ELEMENT response ((href+, status)|(href, propstat+), error?, responsedescription?, location?>
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum StatusOrPropstat<E: Extension, N: xml::Node<N>> {
|
pub enum StatusOrPropstat<E: Extension, N: xml::Node<N>> {
|
||||||
// One status, multiple hrefs...
|
// One status, multiple hrefs...
|
||||||
Status(Vec<Href>, Status),
|
Status(Vec<Href>, Status),
|
||||||
|
@ -519,7 +519,7 @@ pub enum StatusOrPropstat<E: Extension, N: xml::Node<N>> {
|
||||||
PropStat(Href, Vec<PropStat<E, N>>),
|
PropStat(Href, Vec<PropStat<E, N>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Response<E: Extension, N: xml::Node<N>> {
|
pub struct Response<E: Extension, N: xml::Node<N>> {
|
||||||
pub status_or_propstat: StatusOrPropstat<E, N>,
|
pub status_or_propstat: StatusOrPropstat<E, N>,
|
||||||
pub error: Option<Error<E>>,
|
pub error: Option<Error<E>>,
|
||||||
|
@ -538,7 +538,7 @@ pub struct Response<E: Extension, N: xml::Node<N>> {
|
||||||
/// user.
|
/// user.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT responsedescription (#PCDATA) >
|
/// <!ELEMENT responsedescription (#PCDATA) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct ResponseDescription(pub String);
|
pub struct ResponseDescription(pub String);
|
||||||
|
|
||||||
/// 14.26. set XML Element
|
/// 14.26. set XML Element
|
||||||
|
@ -557,7 +557,7 @@ pub struct ResponseDescription(pub String);
|
||||||
/// property, and MUST be subsequently retrievable using PROPFIND.
|
/// property, and MUST be subsequently retrievable using PROPFIND.
|
||||||
///
|
///
|
||||||
/// <!ELEMENT set (prop) >
|
/// <!ELEMENT set (prop) >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Set<E: Extension>(pub PropValue<E>);
|
pub struct Set<E: Extension>(pub PropValue<E>);
|
||||||
|
|
||||||
/// 14.27. shared XML Element
|
/// 14.27. shared XML Element
|
||||||
|
@ -568,7 +568,7 @@ pub struct Set<E: Extension>(pub PropValue<E>);
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// <!ELEMENT shared EMPTY >
|
/// <!ELEMENT shared EMPTY >
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Shared {}
|
pub struct Shared {}
|
||||||
|
|
||||||
|
|
||||||
|
@ -582,7 +582,7 @@ pub struct Shared {}
|
||||||
///
|
///
|
||||||
/// <!ELEMENT status (#PCDATA) >
|
/// <!ELEMENT status (#PCDATA) >
|
||||||
//@FIXME: Better typing is possible with an enum for example
|
//@FIXME: Better typing is possible with an enum for example
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Status(pub http::status::StatusCode);
|
pub struct Status(pub http::status::StatusCode);
|
||||||
|
|
||||||
/// 14.29. timeout XML Element
|
/// 14.29. timeout XML Element
|
||||||
|
@ -610,7 +610,7 @@ pub struct Status(pub http::status::StatusCode);
|
||||||
/// elapse between granting of the lock at the server, and the automatic
|
/// elapse between granting of the lock at the server, and the automatic
|
||||||
/// removal of the lock. The timeout value for TimeType "Second" MUST
|
/// removal of the lock. The timeout value for TimeType "Second" MUST
|
||||||
/// NOT be greater than 2^32-1.
|
/// NOT be greater than 2^32-1.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Timeout {
|
pub enum Timeout {
|
||||||
Seconds(u32),
|
Seconds(u32),
|
||||||
Infinite,
|
Infinite,
|
||||||
|
@ -644,7 +644,7 @@ pub enum Timeout {
|
||||||
/// the header value could include LWS as defined in [RFC2616], Section
|
/// the header value could include LWS as defined in [RFC2616], Section
|
||||||
/// 4.2. Server implementors SHOULD strip LWS from these values before
|
/// 4.2. Server implementors SHOULD strip LWS from these values before
|
||||||
/// using as WebDAV property values.
|
/// using as WebDAV property values.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum PropertyRequest<E: Extension> {
|
pub enum PropertyRequest<E: Extension> {
|
||||||
CreationDate,
|
CreationDate,
|
||||||
DisplayName,
|
DisplayName,
|
||||||
|
@ -659,7 +659,7 @@ pub enum PropertyRequest<E: Extension> {
|
||||||
Extension(E::PropertyRequest),
|
Extension(E::PropertyRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Property<E: Extension> {
|
pub enum Property<E: Extension> {
|
||||||
/// 15.1. creationdate Property
|
/// 15.1. creationdate Property
|
||||||
///
|
///
|
||||||
|
@ -942,7 +942,7 @@ pub enum Property<E: Extension> {
|
||||||
Extension(E::Property),
|
Extension(E::Property),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum ResourceType<E: Extension> {
|
pub enum ResourceType<E: Extension> {
|
||||||
Collection,
|
Collection,
|
||||||
Extension(E::ResourceType),
|
Extension(E::ResourceType),
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub trait QRead<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The representation of an XML node in Rust
|
// The representation of an XML node in Rust
|
||||||
pub trait Node<T> = QRead<T> + QWrite + std::fmt::Debug + PartialEq + Sync;
|
pub trait Node<T> = QRead<T> + QWrite + std::fmt::Debug + PartialEq + Clone + Sync;
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,9 @@ use rustls_pemfile::{certs, private_key};
|
||||||
use aero_user::config::{DavConfig, DavUnsecureConfig};
|
use aero_user::config::{DavConfig, DavUnsecureConfig};
|
||||||
use aero_user::login::ArcLoginProvider;
|
use aero_user::login::ArcLoginProvider;
|
||||||
use aero_collections::user::User;
|
use aero_collections::user::User;
|
||||||
use aero_dav::types::{PropFind, Multistatus, PropValue, ResponseDescription};
|
use aero_dav::types as dav;
|
||||||
use aero_dav::realization::{Core, Calendar};
|
use aero_dav::realization::Calendar;
|
||||||
use aero_dav::xml as dav;
|
use aero_dav::xml as dxml;
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
bind_addr: SocketAddr,
|
bind_addr: SocketAddr,
|
||||||
|
@ -196,7 +196,13 @@ async fn router(user: std::sync::Arc<User>, req: Request<Incoming>) -> Result<Re
|
||||||
let path_segments: Vec<_> = path.split("/").filter(|s| *s != "").collect();
|
let path_segments: Vec<_> = path.split("/").filter(|s| *s != "").collect();
|
||||||
let method = req.method().as_str().to_uppercase();
|
let method = req.method().as_str().to_uppercase();
|
||||||
|
|
||||||
|
//@FIXME check depth, handle it
|
||||||
|
|
||||||
match (method.as_str(), path_segments.as_slice()) {
|
match (method.as_str(), path_segments.as_slice()) {
|
||||||
|
("OPTIONS", _) => return Ok(Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.header("DAV", "1")
|
||||||
|
.body(text_body(""))?),
|
||||||
("PROPFIND", []) => propfind_root(user, req).await,
|
("PROPFIND", []) => propfind_root(user, req).await,
|
||||||
(_, [ username, ..]) if *username != user.username => return Ok(Response::builder()
|
(_, [ username, ..]) if *username != user.username => return Ok(Response::builder()
|
||||||
.status(403)
|
.status(403)
|
||||||
|
@ -216,14 +222,73 @@ async fn router(user: std::sync::Arc<User>, req: Request<Incoming>) -> Result<Re
|
||||||
/// </D:prop></D:propfind>
|
/// </D:prop></D:propfind>
|
||||||
|
|
||||||
async fn propfind_root(user: std::sync::Arc<User>, req: Request<Incoming>) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
|
async fn propfind_root(user: std::sync::Arc<User>, req: Request<Incoming>) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
|
||||||
tracing::info!("root");
|
let supported_propname = vec![
|
||||||
|
dav::PropertyRequest::DisplayName,
|
||||||
|
dav::PropertyRequest::ResourceType,
|
||||||
|
];
|
||||||
|
|
||||||
let r = deserialize::<PropFind<Core>>(req).await?;
|
// A client may choose not to submit a request body. An empty PROPFIND
|
||||||
println!("r: {:?}", r);
|
// request body MUST be treated as if it were an 'allprop' request.
|
||||||
serialize(Multistatus::<Core, PropValue<Core>> {
|
// @FIXME here we handle any invalid data as an allprop, an empty request is thus correctly
|
||||||
responses: vec![],
|
// handled, but corrupted requests are also silently handled as allprop.
|
||||||
responsedescription: Some(ResponseDescription("hello world".to_string())),
|
let propfind = deserialize::<dav::PropFind<Calendar>>(req).await.unwrap_or_else(|_| dav::PropFind::<Calendar>::AllProp(None));
|
||||||
})
|
tracing::debug!(recv=?propfind, "inferred propfind request");
|
||||||
|
|
||||||
|
if matches!(propfind, dav::PropFind::PropName) {
|
||||||
|
return serialize(dav::Multistatus::<Calendar, dav::PropName<Calendar>> {
|
||||||
|
responses: vec![dav::Response {
|
||||||
|
status_or_propstat: dav::StatusOrPropstat::PropStat(
|
||||||
|
dav::Href(format!("./{}/", user.username)),
|
||||||
|
vec![dav::PropStat {
|
||||||
|
prop: dav::PropName(supported_propname),
|
||||||
|
status: dav::Status(hyper::StatusCode::OK),
|
||||||
|
error: None,
|
||||||
|
responsedescription: None,
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
error: None,
|
||||||
|
location: None,
|
||||||
|
responsedescription: Some(dav::ResponseDescription("user home directory".into())),
|
||||||
|
}],
|
||||||
|
responsedescription: Some(dav::ResponseDescription("propname response".to_string())),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let propname = match propfind {
|
||||||
|
dav::PropFind::PropName => unreachable!(),
|
||||||
|
dav::PropFind::AllProp(None) => supported_propname.clone(),
|
||||||
|
dav::PropFind::AllProp(Some(dav::Include(mut include))) => {
|
||||||
|
include.extend_from_slice(supported_propname.as_slice());
|
||||||
|
include
|
||||||
|
},
|
||||||
|
dav::PropFind::Prop(dav::PropName(inner)) => inner,
|
||||||
|
};
|
||||||
|
|
||||||
|
let values = propname.iter().filter_map(|n| match n {
|
||||||
|
dav::PropertyRequest::DisplayName => Some(dav::Property::DisplayName(format!("{} home", user.username))),
|
||||||
|
dav::PropertyRequest::ResourceType => Some(dav::Property::ResourceType(vec![dav::ResourceType::Collection])),
|
||||||
|
_ => None,
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
let multistatus = dav::Multistatus::<Calendar, dav::PropValue<Calendar>> {
|
||||||
|
responses: vec![ dav::Response {
|
||||||
|
status_or_propstat: dav::StatusOrPropstat::PropStat(
|
||||||
|
dav::Href(format!("./{}/", user.username)),
|
||||||
|
vec![dav::PropStat {
|
||||||
|
prop: dav::PropValue(values),
|
||||||
|
status: dav::Status(hyper::StatusCode::OK),
|
||||||
|
error: None,
|
||||||
|
responsedescription: None,
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
error: None,
|
||||||
|
location: None,
|
||||||
|
responsedescription: Some(dav::ResponseDescription("Root node".into())),
|
||||||
|
} ],
|
||||||
|
responsedescription: Some(dav::ResponseDescription("hello world".to_string())),
|
||||||
|
};
|
||||||
|
|
||||||
|
serialize(multistatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn propfind_home(user: std::sync::Arc<User>, req: &Request<impl hyper::body::Body>) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
|
async fn propfind_home(user: std::sync::Arc<User>, req: &Request<impl hyper::body::Body>) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
|
||||||
|
@ -263,7 +328,7 @@ async fn collections(_user: std::sync::Arc<User>, _req: Request<impl hyper::body
|
||||||
|
|
||||||
|
|
||||||
use futures::stream::TryStreamExt;
|
use futures::stream::TryStreamExt;
|
||||||
use http_body_util::{BodyStream, Empty};
|
use http_body_util::BodyStream;
|
||||||
use http_body_util::StreamBody;
|
use http_body_util::StreamBody;
|
||||||
use http_body_util::combinators::BoxBody;
|
use http_body_util::combinators::BoxBody;
|
||||||
use hyper::body::Frame;
|
use hyper::body::Frame;
|
||||||
|
@ -277,7 +342,7 @@ fn text_body(txt: &'static str) -> BoxBody<Bytes, std::io::Error> {
|
||||||
BoxBody::new(Full::new(Bytes::from(txt)).map_err(|e| match e {}))
|
BoxBody::new(Full::new(Bytes::from(txt)).map_err(|e| match e {}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize<T: dav::QWrite + Send + 'static>(elem: T) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
|
fn serialize<T: dxml::QWrite + Send + 'static>(elem: T) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {
|
||||||
let (tx, rx) = tokio::sync::mpsc::channel::<Bytes>(1);
|
let (tx, rx) = tokio::sync::mpsc::channel::<Bytes>(1);
|
||||||
|
|
||||||
// Build the writer
|
// Build the writer
|
||||||
|
@ -286,7 +351,7 @@ fn serialize<T: dav::QWrite + Send + 'static>(elem: T) -> Result<Response<BoxBod
|
||||||
let mut writer = SinkWriter::new(CopyToBytes::new(sink));
|
let mut writer = SinkWriter::new(CopyToBytes::new(sink));
|
||||||
let q = quick_xml::writer::Writer::new_with_indent(&mut writer, b' ', 4);
|
let q = quick_xml::writer::Writer::new_with_indent(&mut writer, b' ', 4);
|
||||||
let ns_to_apply = vec![ ("xmlns:D".into(), "DAV:".into()) ];
|
let ns_to_apply = vec![ ("xmlns:D".into(), "DAV:".into()) ];
|
||||||
let mut qwriter = dav::Writer { q, ns_to_apply };
|
let mut qwriter = dxml::Writer { q, ns_to_apply };
|
||||||
match elem.qwrite(&mut qwriter).await {
|
match elem.qwrite(&mut qwriter).await {
|
||||||
Ok(_) => tracing::debug!("fully serialized object"),
|
Ok(_) => tracing::debug!("fully serialized object"),
|
||||||
Err(e) => tracing::error!(err=?e, "failed to serialize object"),
|
Err(e) => tracing::error!(err=?e, "failed to serialize object"),
|
||||||
|
@ -308,14 +373,14 @@ fn serialize<T: dav::QWrite + Send + 'static>(elem: T) -> Result<Response<BoxBod
|
||||||
|
|
||||||
|
|
||||||
/// Deserialize a request body to an XML request
|
/// Deserialize a request body to an XML request
|
||||||
async fn deserialize<T: dav::Node<T>>(req: Request<Incoming>) -> Result<T> {
|
async fn deserialize<T: dxml::Node<T>>(req: Request<Incoming>) -> Result<T> {
|
||||||
let stream_of_frames = BodyStream::new(req.into_body());
|
let stream_of_frames = BodyStream::new(req.into_body());
|
||||||
let stream_of_bytes = stream_of_frames
|
let stream_of_bytes = stream_of_frames
|
||||||
.try_filter_map(|frame| async move { Ok(frame.into_data().ok()) })
|
.try_filter_map(|frame| async move { Ok(frame.into_data().ok()) })
|
||||||
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err));
|
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err));
|
||||||
let async_read = tokio_util::io::StreamReader::new(stream_of_bytes);
|
let async_read = tokio_util::io::StreamReader::new(stream_of_bytes);
|
||||||
let async_read = std::pin::pin!(async_read);
|
let async_read = std::pin::pin!(async_read);
|
||||||
let mut rdr = dav::Reader::new(quick_xml::reader::NsReader::from_reader(async_read)).await?;
|
let mut rdr = dxml::Reader::new(quick_xml::reader::NsReader::from_reader(async_read)).await?;
|
||||||
let parsed = rdr.find::<T>().await?;
|
let parsed = rdr.find::<T>().await?;
|
||||||
Ok(parsed)
|
Ok(parsed)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue