cardav working (tm)
This commit is contained in:
@@ -6,7 +6,9 @@ import (
|
||||
"fmt"
|
||||
"context"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"nxcaldav/internal/backend"
|
||||
"regexp"
|
||||
"time"
|
||||
@@ -99,8 +101,87 @@ func AddColorToCalendarPropfind(r *http.Request, ctx context.Context, handler ht
|
||||
return resp
|
||||
})
|
||||
|
||||
// Headers are already set in h.ResponseWriter.Header() by caldav.Handler
|
||||
// But Content-Length might have changed
|
||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(body)))
|
||||
w.WriteHeader(rw.status)
|
||||
w.Write(body)
|
||||
}
|
||||
|
||||
func HandleDiscoveryPropfind(r *http.Request, ctx context.Context, handler http.Handler, w http.ResponseWriter, be *backend.DBBackend) {
|
||||
reqBody, _ := io.ReadAll(r.Body)
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(reqBody))
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
rw := &responseWriter{w, buf, http.StatusOK}
|
||||
handler.ServeHTTP(rw, r.WithContext(ctx))
|
||||
|
||||
body := buf.Bytes()
|
||||
|
||||
// 1. Unconditionally add namespaces to root tag
|
||||
reMultistatus := regexp.MustCompile(`(<[a-zA-Z0-9]*:?multistatus)`)
|
||||
body = reMultistatus.ReplaceAll(body, []byte(`$1 xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:card="urn:ietf:params:xml:ns:carddav"`))
|
||||
|
||||
// 2. Response processing
|
||||
reResponse := regexp.MustCompile(`(?s)<[a-zA-Z0-9]*:?response.*?>.*?</[a-zA-Z0-9]*:?response>`)
|
||||
reHref := regexp.MustCompile(`<[a-zA-Z0-9]*:?href.*?>(.*?)</[a-zA-Z0-9]*:?href>`)
|
||||
rePropstat := regexp.MustCompile(`(?s)<[a-zA-Z0-9]*:?propstat.*?>.*?</[a-zA-Z0-9]*:?propstat>`)
|
||||
reStatusOk := regexp.MustCompile(`(?s)<[a-zA-Z0-9]*:?status.*?>HTTP/1.1 200 OK</[a-zA-Z0-9]*:?status>`)
|
||||
reProp := regexp.MustCompile(`(?s)<[a-zA-Z0-9]*:?prop.*?>.*?</[a-zA-Z0-9]*:?prop>`)
|
||||
rePropClose := regexp.MustCompile(`</[a-zA-Z0-9]*:?prop>`)
|
||||
|
||||
body = reResponse.ReplaceAllFunc(body, func(resp []byte) []byte {
|
||||
hrefMatch := reHref.FindSubmatch(resp)
|
||||
if len(hrefMatch) < 2 {
|
||||
return resp
|
||||
}
|
||||
|
||||
calHome, _ := be.CalendarHomeSetPath(ctx)
|
||||
cardHome, _ := be.AddressBookHomeSetPath(ctx)
|
||||
|
||||
// Strip these tags ONLY from non-200 propstats
|
||||
resp = rePropstat.ReplaceAllFunc(resp, func(ps []byte) []byte {
|
||||
if !reStatusOk.Match(ps) {
|
||||
reTags := regexp.MustCompile(`(?s)<[a-zA-Z0-9:]*(calendar-home-set|addressbook-home-set).*?/>|<[a-zA-Z0-9:]*(calendar-home-set|addressbook-home-set).*?>.*?</[a-zA-Z0-9:]*(calendar-home-set|addressbook-home-set)>`)
|
||||
return reTags.ReplaceAll(ps, []byte(""))
|
||||
}
|
||||
return ps
|
||||
})
|
||||
|
||||
props := ""
|
||||
if calHome != "" && !strings.Contains(string(resp), "calendar-home-set") {
|
||||
props += fmt.Sprintf("<C:calendar-home-set><href xmlns=\"DAV:\">%s</href></C:calendar-home-set>", calHome)
|
||||
}
|
||||
if cardHome != "" && !strings.Contains(string(resp), "addressbook-home-set") {
|
||||
props += fmt.Sprintf("<card:addressbook-home-set><href xmlns=\"DAV:\">%s</href></card:addressbook-home-set>", cardHome)
|
||||
}
|
||||
|
||||
if props == "" {
|
||||
return resp
|
||||
}
|
||||
|
||||
has200 := false
|
||||
resp = rePropstat.ReplaceAllFunc(resp, func(ps []byte) []byte {
|
||||
if reStatusOk.Match(ps) {
|
||||
has200 = true
|
||||
return reProp.ReplaceAllFunc(ps, func(prop []byte) []byte {
|
||||
return rePropClose.ReplaceAllFunc(prop, func(closeTag []byte) []byte {
|
||||
return append([]byte(props), closeTag...)
|
||||
})
|
||||
})
|
||||
}
|
||||
return ps
|
||||
})
|
||||
|
||||
if !has200 {
|
||||
newPropstat := fmt.Sprintf("<propstat xmlns=\"DAV:\"><prop>%s</prop><status>HTTP/1.1 200 OK</status></propstat>", props)
|
||||
reResponseClose := regexp.MustCompile(`</[a-zA-Z0-9]*:?response>`)
|
||||
resp = reResponseClose.ReplaceAllFunc(resp, func(closeTag []byte) []byte {
|
||||
return append([]byte(newPropstat), closeTag...)
|
||||
})
|
||||
}
|
||||
|
||||
return resp
|
||||
})
|
||||
|
||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(body)))
|
||||
w.WriteHeader(rw.status)
|
||||
w.Write(body)
|
||||
|
||||
Reference in New Issue
Block a user