webdav: add ServePrincipal

This commit is contained in:
Simon Ser 2022-05-03 17:53:06 +02:00
parent 95a4ae783b
commit 4cc86a1225
3 changed files with 100 additions and 0 deletions

32
elements.go Normal file
View File

@ -0,0 +1,32 @@
package webdav
import (
"encoding/xml"
"github.com/emersion/go-webdav/internal"
)
var (
principalName = xml.Name{"DAV:", "principal"}
principalAlternateURISetName = xml.Name{"DAV:", "alternate-URI-set"}
principalURLName = xml.Name{"DAV:", "principal-URL"}
groupMembershipName = xml.Name{"DAV:", "group-membership"}
)
// https://datatracker.ietf.org/doc/html/rfc3744#section-4.1
type principalAlternateURISet struct {
XMLName xml.Name `xml:"DAV: alternate-URI-set"`
Hrefs []internal.Href `xml:"href"`
}
// https://datatracker.ietf.org/doc/html/rfc3744#section-4.2
type principalURL struct {
XMLName xml.Name `xml:"DAV: principal-URL"`
Href internal.Href `xml:"href"`
}
// https://datatracker.ietf.org/doc/html/rfc3744#section-4.4
type groupMembership struct {
XMLName xml.Name `xml:"DAV: group-membership"`
Hrefs []internal.Href `xml:"href"`
}

View File

@ -6,6 +6,7 @@ import (
"net/http"
"os"
"strconv"
"strings"
"github.com/emersion/go-webdav/internal"
)
@ -234,3 +235,64 @@ func (b *backend) Move(r *http.Request, dest *internal.Href, overwrite bool) (cr
}
return created, err
}
// ServePrincipal replies to a request on a principal URI.
func ServePrincipal(w http.ResponseWriter, r *http.Request, principal *Principal) {
switch r.Method {
case http.MethodOptions:
caps := append([]string{"1", "3"})
allow := []string{http.MethodOptions, "PROPFIND"}
w.Header().Add("DAV", strings.Join(caps, ", "))
w.Header().Add("Allow", strings.Join(allow, ", "))
w.WriteHeader(http.StatusNoContent)
case "PROPFIND":
if err := servePrincipalPropfind(w, r, principal); err != nil {
internal.ServeError(w, err)
}
default:
http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
}
}
func servePrincipalPropfind(w http.ResponseWriter, r *http.Request, principal *Principal) error {
var propfind internal.Propfind
if err := internal.DecodeXMLRequest(r, &propfind); err != nil {
return err
}
// TODO: handle Depth
props := map[xml.Name]internal.PropfindFunc{
internal.ResourceTypeName: func(*internal.RawXMLValue) (interface{}, error) {
return internal.NewResourceType(principalName), nil
},
internal.DisplayNameName: func(*internal.RawXMLValue) (interface{}, error) {
return &internal.DisplayName{Name: principal.Name}, nil
},
internal.CurrentUserPrincipalName: func(*internal.RawXMLValue) (interface{}, error) {
// TODO: allow serving a principal different from the current user's
return &internal.CurrentUserPrincipal{Href: internal.Href{Path: principal.Path}}, nil
},
principalAlternateURISetName: func(*internal.RawXMLValue) (interface{}, error) {
return &principalAlternateURISet{}, nil // TODO: allow customizing
},
principalURLName: func(*internal.RawXMLValue) (interface{}, error) {
return &principalURL{
Href: internal.Href{Path: principal.Path},
}, nil
},
groupMembershipName: func(*internal.RawXMLValue) (interface{}, error) {
return &groupMembership{}, nil // TODO: allow customizing
},
}
// TODO: allow adding more props such as CardDAV/CalDAV home sets
resp, err := internal.NewPropfindResponse(r.URL.Path, &propfind, props)
if err != nil {
return err
}
ms := internal.NewMultistatus(*resp)
return internal.ServeMultistatus(w, ms)
}

View File

@ -7,6 +7,12 @@ import (
"time"
)
// Principal is a DAV principal as defined in RFC 3744 section 2.
type Principal struct {
Path string
Name string
}
type FileInfo struct {
Path string
Size int64