diff --git a/SPEC.md b/SPEC.md index 6592a45..78ecec5 100644 --- a/SPEC.md +++ b/SPEC.md @@ -1881,10 +1881,23 @@ image runs it by default (see "Deployment"). - `DELETE` - `PATCH` - `QUERY` +- `PROPFIND` +- `PROPPATCH` +- `MKCOL` +- `COPY` +- `MOVE` +- `REPORT` +- `SEARCH` +- `LOCK` +- `UNLOCK` It answers any other method `405`, with no question and no report. The answer's `Allow` header names these methods. +Nextcloud's Files app and sync client use the last nine, which are WebDAV +methods. The Core Rule Set refuses them except where an app's exclusions allow +them. + `rproxy` answers `400`, with no question and no report, to a request with: - a target that does not start with `/`, such as `x:admin`, diff --git a/internal/rproxy/question_test.go b/internal/rproxy/question_test.go index 5940ab9..02c0cac 100644 --- a/internal/rproxy/question_test.go +++ b/internal/rproxy/question_test.go @@ -331,7 +331,7 @@ func TestAQuestionCarriesItsBodyWhateverTheMethod(t *testing.T) { func TestAMethodNotPassedOnIsAnswered405(t *testing.T) { t.Parallel() - for _, method := range []string{http.MethodTrace, "PROPFIND", "LOCK", "BREW"} { + for _, method := range []string{http.MethodTrace, "MKCALENDAR", "BREW"} { t.Run(method, func(t *testing.T) { t.Parallel() @@ -343,7 +343,8 @@ func TestAMethodNotPassedOnIsAnswered405(t *testing.T) { got := visit(t, newRequest(t, method, addr, "/", http.NoBody)) if got.status != http.StatusMethodNotAllowed || - got.header.Get("Allow") != "GET, HEAD, POST, OPTIONS, PUT, DELETE, PATCH, QUERY" { + got.header.Get("Allow") != "GET, HEAD, POST, OPTIONS, PUT, DELETE, PATCH, QUERY, "+ + "PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, REPORT, SEARCH, LOCK, UNLOCK" { t.Errorf("answered %+v, want 405 naming the methods passed on", got) } @@ -368,6 +369,8 @@ func TestEachMethodPassedOnReachesDiscriminatorAndTheApp(t *testing.T) { for _, method := range []string{ http.MethodGet, http.MethodHead, http.MethodPost, http.MethodOptions, http.MethodPut, http.MethodDelete, http.MethodPatch, "QUERY", + "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "REPORT", "SEARCH", + "LOCK", "UNLOCK", } { t.Run(method, func(t *testing.T) { t.Parallel() diff --git a/internal/rproxy/rproxy.go b/internal/rproxy/rproxy.go index 0a4c9f0..94bf459 100644 --- a/internal/rproxy/rproxy.go +++ b/internal/rproxy/rproxy.go @@ -51,7 +51,9 @@ const ownEndpointPrefix = "/_sww/" // allowedMethods lists the methods rproxy passes on, as an Allow header gives // them. It answers any other method 405 itself. -const allowedMethods = "GET, HEAD, POST, OPTIONS, PUT, DELETE, PATCH, QUERY" +// The WebDAV ones are for Nextcloud. +const allowedMethods = "GET, HEAD, POST, OPTIONS, PUT, DELETE, PATCH, QUERY, " + + "PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, REPORT, SEARCH, LOCK, UNLOCK" // Params are what New needs. type Params struct {