diff --git a/client.go b/client.go index 72e8d76..01b750b 100644 --- a/client.go +++ b/client.go @@ -1,9 +1,9 @@ package webdav import ( + "encoding/xml" "fmt" "net/http" - "strings" "github.com/emersion/go-webdav/internal" ) @@ -21,21 +21,15 @@ func NewClient(c *http.Client, endpoint string) (*Client, error) { } func (c *Client) FindCurrentUserPrincipal() (string, error) { - r := strings.NewReader(` - - - - - -`) + name := xml.Name{"DAV:", "current-user-principal"} + propfind := internal.NewPropPropfind(name) - req, err := c.c.NewRequest("PROPFIND", "", r) + req, err := c.c.NewXMLRequest("PROPFIND", "", propfind) if err != nil { return "", err } req.Header.Add("Depth", "0") - req.Header.Add("Content-Type", "text/xml; charset=\"utf-8\"") resps, err := c.c.DoMultiStatus(req) if err != nil { diff --git a/internal/client.go b/internal/client.go index 3a83f74..3fcf3c7 100644 --- a/internal/client.go +++ b/internal/client.go @@ -1,6 +1,7 @@ package internal import ( + "bytes" "encoding/xml" "fmt" "io" @@ -36,6 +37,27 @@ func (c *Client) NewRequest(method string, p string, body io.Reader) (*http.Requ return http.NewRequest(method, u.String(), body) } +func (c *Client) NewXMLRequest(method string, p string, v interface{}) (*http.Request, error) { + var buf bytes.Buffer + buf.WriteString(xml.Header) + enc := xml.NewEncoder(&buf) + if err := enc.Encode(v); err != nil { + return nil, err + } + if err := enc.Flush(); err != nil { + return nil, err + } + + req, err := c.NewRequest(method, p, &buf) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", "text/xml; charset=\"utf-8\"") + + return req, nil +} + func (c *Client) Do(req *http.Request) (*http.Response, error) { // TODO: remove this quirk req.SetBasicAuth("simon", "") diff --git a/internal/elements.go b/internal/elements.go index 7f84e12..8fe41a1 100644 --- a/internal/elements.go +++ b/internal/elements.go @@ -27,3 +27,19 @@ type Propstat struct { Status string `xml:"DAV: status"` // TODO: error?, responsedescription? } + +// https://tools.ietf.org/html/rfc4918#section-14.20 +type Propfind struct { + XMLName xml.Name `xml:"DAV: propfind"` + Prop *RawXMLValue `xml:"DAV: prop,omitempty"` + // TODO: propname | (allprop, include?) +} + +func NewPropPropfind(names ...xml.Name) *Propfind { + children := make([]RawXMLValue, len(names)) + for i, name := range names { + children[i] = *NewRawXMLElement(name, nil, nil) + } + prop := NewRawXMLElement(xml.Name{"DAV:", "prop"}, nil, children) + return &Propfind{Prop: prop} +} diff --git a/internal/xml.go b/internal/xml.go index 81a530e..c5dbc5b 100644 --- a/internal/xml.go +++ b/internal/xml.go @@ -13,6 +13,11 @@ type RawXMLValue struct { children []RawXMLValue } +// NewRawXMLElement creates a new RawXMLValue for an element. +func NewRawXMLElement(name xml.Name, attr []xml.Attr, children []RawXMLValue) *RawXMLValue { + return &RawXMLValue{tok: xml.StartElement{name, attr}, children: children} +} + // UnmarshalXML implements xml.Unmarshaler. func (val *RawXMLValue) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { val.tok = start