From 1f509de4046994dcd7b9436b352bf9fa7d31f008 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 27 Jan 2020 10:30:19 +0100 Subject: [PATCH] carddav: honor address-data in addressbook-query --- carddav/carddav.go | 12 ++++++---- carddav/client.go | 24 ++++--------------- carddav/server.go | 58 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/carddav/carddav.go b/carddav/carddav.go index 32860a8..7d49c19 100644 --- a/carddav/carddav.go +++ b/carddav/carddav.go @@ -17,8 +17,7 @@ type AddressBook struct { } type AddressBookQuery struct { - Props []string - AllProp bool + DataRequest AddressDataRequest PropFilters []PropFilter FilterTest FilterTest // defaults to FilterAnyOf @@ -26,6 +25,11 @@ type AddressBookQuery struct { Limit int // <= 0 means unlimited } +type AddressDataRequest struct { + Props []string + AllProp bool +} + type PropFilter struct { Name string Test FilterTest // defaults to FilterAnyOf @@ -68,9 +72,7 @@ const ( type AddressBookMultiGet struct { Paths []string - - Props []string - AllProp bool + DataRequest AddressDataRequest } type AddressObject struct { diff --git a/carddav/client.go b/carddav/client.go index 011eafe..e89511f 100644 --- a/carddav/client.go +++ b/carddav/client.go @@ -142,12 +142,12 @@ func (c *Client) FindAddressBooks(addressBookHomeSet string) ([]AddressBook, err return l, nil } -func encodeAddressPropReq(props []string, allProp bool) (*internal.Prop, error) { +func encodeAddressPropReq(req *AddressDataRequest) (*internal.Prop, error) { var addrDataReq addressDataReq - if allProp { + if req.AllProp { addrDataReq.Allprop = &struct{}{} } else { - for _, name := range props { + for _, name := range req.Props { addrDataReq.Props = append(addrDataReq.Props, prop{Name: name}) } } @@ -245,14 +245,7 @@ func decodeAddressList(ms *internal.Multistatus) ([]AddressObject, error) { } func (c *Client) QueryAddressBook(addressBook string, query *AddressBookQuery) ([]AddressObject, error) { - var props []string - var allProp bool - if query != nil { - props = query.Props - allProp = query.AllProp - } - - propReq, err := encodeAddressPropReq(props, allProp) + propReq, err := encodeAddressPropReq(&query.DataRequest) if err != nil { return nil, err } @@ -286,14 +279,7 @@ func (c *Client) QueryAddressBook(addressBook string, query *AddressBookQuery) ( } func (c *Client) MultiGetAddressBook(path string, multiGet *AddressBookMultiGet) ([]AddressObject, error) { - var props []string - var allProp bool - if multiGet != nil { - props = multiGet.Props - allProp = multiGet.AllProp - } - - propReq, err := encodeAddressPropReq(props, allProp) + propReq, err := encodeAddressPropReq(&multiGet.DataRequest) if err != nil { return nil, err } diff --git a/carddav/server.go b/carddav/server.go index 003ed6f..c1522f1 100644 --- a/carddav/server.go +++ b/carddav/server.go @@ -16,8 +16,8 @@ import ( // Backend is a CardDAV server backend. type Backend interface { AddressBook() (*AddressBook, error) - GetAddressObject(path string) (*AddressObject, error) - ListAddressObjects() ([]AddressObject, error) + GetAddressObject(path string, req *AddressDataRequest) (*AddressObject, error) + ListAddressObjects(req *AddressDataRequest) ([]AddressObject, error) QueryAddressObjects(query *AddressBookQuery) ([]AddressObject, error) PutAddressObject(path string, card vcard.Card) error DeleteAddressObject(path string) error @@ -108,6 +108,18 @@ func decodeTextMatch(tm *textMatch) *TextMatch { } } +func decodeAddressDataReq(addressData *addressDataReq) (*AddressDataRequest, error) { + if addressData.Allprop != nil && len(addressData.Props) > 0 { + return nil, internal.HTTPErrorf(http.StatusBadRequest, "carddav: only one of allprop or prop can be specified in address-data") + } + + req := &AddressDataRequest{AllProp: addressData.Allprop != nil} + for _, p := range addressData.Props { + req.Props = append(req.Props, p.Name) + } + return req, nil +} + func (h *Handler) handleQuery(w http.ResponseWriter, query *addressbookQuery) error { var q AddressBookQuery if query.Prop != nil { @@ -115,13 +127,11 @@ func (h *Handler) handleQuery(w http.ResponseWriter, query *addressbookQuery) er if err := query.Prop.Decode(&addressData); err != nil && !internal.IsMissingProp(err) { return err } - if addressData.Allprop != nil && len(addressData.Props) > 0 { - return internal.HTTPErrorf(http.StatusBadRequest, "carddav: only one of allprop or prop can be specified in address-data") - } - q.AllProp = addressData.Allprop != nil - for _, p := range addressData.Props { - q.Props = append(q.Props, p.Name) + req, err := decodeAddressDataReq(&addressData) + if err != nil { + return err } + q.DataRequest = *req } q.FilterTest = FilterTest(query.Filter.Test) for _, el := range query.Filter.Props { @@ -163,11 +173,22 @@ func (h *Handler) handleQuery(w http.ResponseWriter, query *addressbookQuery) er } func (h *Handler) handleMultiget(w http.ResponseWriter, multiget *addressbookMultiget) error { + var dataReq AddressDataRequest + if multiget.Prop != nil { + var addressData addressDataReq + if err := multiget.Prop.Decode(&addressData); err != nil && !internal.IsMissingProp(err) { + return err + } + decoded, err := decodeAddressDataReq(&addressData) + if err != nil { + return err + } + dataReq = *decoded + } + var resps []internal.Response for _, href := range multiget.Hrefs { - // TODO: only get a subset of the vCard fields, depending on the - // multiget query - ao, err := h.Backend.GetAddressObject(href.Path) + ao, err := h.Backend.GetAddressObject(href.Path, &dataReq) if err != nil { return err // TODO: create internal.Response with error } @@ -200,7 +221,8 @@ func (b *backend) Options(r *http.Request) ([]string, error) { return []string{http.MethodOptions, "PROPFIND"}, nil } - _, err := b.Backend.GetAddressObject(r.URL.Path) + var dataReq AddressDataRequest + _, err := b.Backend.GetAddressObject(r.URL.Path, &dataReq) if httpErr, ok := err.(*internal.HTTPError); ok && httpErr.Code == http.StatusNotFound { return []string{http.MethodOptions}, nil } else if err != nil { @@ -215,7 +237,11 @@ func (b *backend) HeadGet(w http.ResponseWriter, r *http.Request) error { return &internal.HTTPError{Code: http.StatusMethodNotAllowed} } - ao, err := b.Backend.GetAddressObject(r.URL.Path) + var dataReq AddressDataRequest + if r.Method != http.MethodHead { + dataReq.AllProp = true + } + ao, err := b.Backend.GetAddressObject(r.URL.Path, &dataReq) if err != nil { return err } @@ -230,6 +256,8 @@ func (b *backend) HeadGet(w http.ResponseWriter, r *http.Request) error { } func (b *backend) Propfind(r *http.Request, propfind *internal.Propfind, depth internal.Depth) (*internal.Multistatus, error) { + var dataReq AddressDataRequest + var resps []internal.Response if r.URL.Path == "/" { ab, err := b.Backend.AddressBook() @@ -244,7 +272,7 @@ func (b *backend) Propfind(r *http.Request, propfind *internal.Propfind, depth i resps = append(resps, *resp) if depth != internal.DepthZero { - aos, err := b.Backend.ListAddressObjects() + aos, err := b.Backend.ListAddressObjects(&dataReq) if err != nil { return nil, err } @@ -258,7 +286,7 @@ func (b *backend) Propfind(r *http.Request, propfind *internal.Propfind, depth i } } } else { - ao, err := b.Backend.GetAddressObject(r.URL.Path) + ao, err := b.Backend.GetAddressObject(r.URL.Path, &dataReq) if err != nil { return nil, err }