// Package api has type definitions for webdav package api import ( "encoding/xml" "regexp" "strconv" "time" ) const ( // Wed, 27 Sep 2017 14:28:34 GMT timeFormat = time.RFC1123 // Fri, 05 Jan 2018 14:14:38 +0000 (as used by mydrive.ch) timeFormatZ = time.RFC1123Z ) // Multistatus contains responses returned from an HTTP 207 return code type Multistatus struct { Responses []Response `xml:"response"` } // Response contains an Href the response it about and its properties type Response struct { Href string `xml:"href"` Props Prop `xml:"propstat"` } // Prop is the properties of a response // // This is a lazy way of decoding the multiple in the // response. // // The response might look like this // // // /remote.php/webdav/Nextcloud%20Manual.pdf // // // Tue, 19 Dec 2017 22:02:36 GMT // 4143665 // // "048d7be4437ff7deeae94db50ff3e209" // application/pdf // // HTTP/1.1 200 OK // // // // // // // HTTP/1.1 404 Not Found // // // // So we elide the array of and within that the array of // into one struct. // // Note that status collects all the status values for which we just // check the first is OK. type Prop struct { Status []string `xml:"DAV: status"` Name string `xml:"DAV: prop>displayname,omitempty"` Type *xml.Name `xml:"DAV: prop>resourcetype>collection,omitempty"` Size int64 `xml:"DAV: prop>getcontentlength,omitempty"` Modified Time `xml:"DAV: prop>getlastmodified,omitempty"` } // Parse a status of the form "HTTP/1.1 200 OK", var parseStatus = regexp.MustCompile(`^HTTP/[0-9.]+\s+(\d+)\s+(.*)$`) // StatusOK examines the Status and returns an OK flag func (p *Prop) StatusOK() bool { // Assume OK if no statuses received if len(p.Status) == 0 { return true } match := parseStatus.FindStringSubmatch(p.Status[0]) if len(match) < 3 { return false } code, err := strconv.Atoi(match[1]) if err != nil { return false } if code >= 200 && code < 300 { return true } return false } // PropValue is a tagged name and value type PropValue struct { XMLName xml.Name `xml:""` Value string `xml:",chardata"` } // Error is used to desribe webdav errors // // // Sabre\DAV\Exception\NotFound // File with name Photo could not be located // type Error struct { Exception string `xml:"exception,omitempty"` Message string `xml:"message,omitempty"` Status string StatusCode int } // Error returns a string for the error and statistifes the error interface func (e *Error) Error() string { if e.Message != "" { return e.Message } if e.Exception != "" { return e.Exception } if e.Status != "" { return e.Status } return "Webdav Error" } // Time represents represents date and time information for the // webdav API marshalling to and from timeFormat type Time time.Time // MarshalXML turns a Time into XML func (t *Time) MarshalXML(e *xml.Encoder, start xml.StartElement) error { timeString := (*time.Time)(t).Format(timeFormat) return e.EncodeElement(timeString, start) } // UnmarshalXML turns XML into a Time func (t *Time) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { var v string err := d.DecodeElement(&v, &start) if err != nil { return err } newT, err := time.Parse(timeFormat, v) if err != nil { newT, err = time.Parse(timeFormatZ, v) if err != nil { return err } } *t = Time(newT) return nil }