CalDAV and CardDAV checkers sharing a single Go module. Discovery follows RFC 6764 (/.well-known + SRV/TXT), authenticated probes cover principal, home-set, collections and a minimal REPORT query on top of go-webdav. Common shape in internal/dav/; CalDAV adds a scheduling rule. Surfaces its context URL (and each secure-SRV target) as TLS endpoints via the EndpointDiscoverer interface, so the dedicated TLS checker can pick them up without re-parsing observations. HTML report foregrounds common misconfigs (well-known returning 200, missing SRV, plaintext-only SRV, missing DAV capability, skipped auth phase) as action-item callouts before the full phase breakdown.
112 lines
3.4 KiB
Go
112 lines
3.4 KiB
Go
package dav
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestDiscover_wellKnownRedirect walks the happy path: /.well-known/caldav
|
|
// returns a 301 to the real context URL.
|
|
func TestDiscover_wellKnownRedirect(t *testing.T) {
|
|
var hits []string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
hits = append(hits, r.URL.Path)
|
|
if r.URL.Path == "/.well-known/caldav" {
|
|
http.Redirect(w, r, "/dav/", http.StatusMovedPermanently)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
// Route "example.test/.well-known/caldav" through the test server.
|
|
c := srv.Client()
|
|
c.Transport = rewriteTransport{base: srv.URL, next: c.Transport}
|
|
|
|
res := Discover(context.Background(), c, KindCalDAV, "example.test", "")
|
|
if res.Source != "well-known" {
|
|
t.Errorf("source = %q, want well-known", res.Source)
|
|
}
|
|
if !strings.HasSuffix(res.ContextURL, "/dav/") {
|
|
t.Errorf("context URL = %q", res.ContextURL)
|
|
}
|
|
if res.WellKnownCode != 301 {
|
|
t.Errorf("expected 301 captured, got %d", res.WellKnownCode)
|
|
}
|
|
if len(res.WellKnownChain) < 1 {
|
|
t.Error("expected redirect chain to be recorded")
|
|
}
|
|
}
|
|
|
|
// TestDiscover_wellKnownReturns200 reproduces the most common misconfig: the
|
|
// server returns 200 on /.well-known/caldav instead of redirecting. Discover
|
|
// must still set ContextURL (to the well-known URL) but WellKnownCode=200 so
|
|
// the rule can emit the warning callout.
|
|
func TestDiscover_wellKnownReturns200(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
c := srv.Client()
|
|
c.Transport = rewriteTransport{base: srv.URL, next: c.Transport}
|
|
|
|
res := Discover(context.Background(), c, KindCardDAV, "example.test", "")
|
|
if res.WellKnownCode != 200 {
|
|
t.Errorf("well-known code = %d, want 200", res.WellKnownCode)
|
|
}
|
|
if res.ContextURL == "" {
|
|
t.Error("expected ContextURL to fall back to the well-known URL")
|
|
}
|
|
}
|
|
|
|
func TestDiscover_explicitOverride(t *testing.T) {
|
|
res := Discover(context.Background(), http.DefaultClient, KindCalDAV, "example.test", "https://custom.example/dav/")
|
|
if res.Source != "explicit" {
|
|
t.Errorf("source: %q", res.Source)
|
|
}
|
|
if res.ContextURL != "https://custom.example/dav/" {
|
|
t.Errorf("ctx: %q", res.ContextURL)
|
|
}
|
|
if res.WellKnownURL != "" {
|
|
t.Errorf("should not have probed well-known, got %q", res.WellKnownURL)
|
|
}
|
|
}
|
|
|
|
func TestDiscover_redirectLoop(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// Always redirect to itself → triggers "too many redirects".
|
|
http.Redirect(w, r, r.URL.Path, http.StatusFound)
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
c := srv.Client()
|
|
c.Transport = rewriteTransport{base: srv.URL, next: c.Transport}
|
|
|
|
res := Discover(context.Background(), c, KindCalDAV, "example.test", "")
|
|
if res.WellKnownError == "" {
|
|
t.Error("expected well-known error, got none")
|
|
}
|
|
}
|
|
|
|
// rewriteTransport rewrites any request URL's host to point at base so we can
|
|
// exercise Discover() without setting up DNS. It preserves the original path.
|
|
type rewriteTransport struct {
|
|
base string
|
|
next http.RoundTripper
|
|
}
|
|
|
|
func (r rewriteTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
baseURL, _ := url.Parse(r.base)
|
|
req.URL.Scheme = baseURL.Scheme
|
|
req.URL.Host = baseURL.Host
|
|
next := r.next
|
|
if next == nil {
|
|
next = http.DefaultTransport
|
|
}
|
|
return next.RoundTrip(req)
|
|
}
|