Skip to content

Commit

Permalink
webdav: return 409 for PUT without parent collection
Browse files Browse the repository at this point in the history
Aligning with the WebDAV RFC specification,
changes the server response for PUT operations that would
create a resource without an existing parent collection
from HTTP 404 Not Found to HTTP 409 Conflict.

RFC RFC4918, section 9.7.1

Fixes golang/go#67150

Change-Id: I5ce6c5ea147a6a450ef5ae2e0077eb0dce409743
Reviewed-on: https://go-review.googlesource.com/c/net/+/583055
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Damien Neil <dneil@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
  • Loading branch information
vvatanabe authored and gopherbot committed May 10, 2024
1 parent 7fa635b commit ac99879
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 0 deletions.
3 changes: 3 additions & 0 deletions webdav/webdav.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int,

f, err := h.FileSystem.OpenFile(ctx, reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
if os.IsNotExist(err) {
return http.StatusConflict, err
}
return http.StatusNotFound, err
}
_, copyErr := io.Copy(f, r.Body)
Expand Down
60 changes: 60 additions & 0 deletions webdav/webdav_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,3 +347,63 @@ func TestFilenameEscape(t *testing.T) {
}
}
}

func TestPutRequest(t *testing.T) {
h := &Handler{
FileSystem: NewMemFS(),
LockSystem: NewMemLS(),
}
srv := httptest.NewServer(h)
defer srv.Close()

do := func(method, urlStr string, body string) (*http.Response, error) {
bodyReader := strings.NewReader(body)
req, err := http.NewRequest(method, urlStr, bodyReader)
if err != nil {
return nil, err
}
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
return res, nil
}

testCases := []struct {
name string
urlPrefix string
want int
}{{
name: "put",
urlPrefix: "/res",
want: http.StatusCreated,
}, {
name: "put_utf8_segment",
urlPrefix: "/res-%e2%82%ac",
want: http.StatusCreated,
}, {
name: "put_empty_segment",
urlPrefix: "",
want: http.StatusNotFound,
}, {
name: "put_root_segment",
urlPrefix: "/",
want: http.StatusNotFound,
}, {
name: "put_no_parent [RFC4918:S9.7.1]",
urlPrefix: "/409me/noparent.txt",
want: http.StatusConflict,
}}

for _, tc := range testCases {
urlStr := srv.URL + tc.urlPrefix
res, err := do("PUT", urlStr, "ABC\n")
if err != nil {
t.Errorf("name=%q: PUT: %v", tc.name, err)
continue
}
if res.StatusCode != tc.want {
t.Errorf("name=%q: got status code %d, want %d", tc.name, res.StatusCode, tc.want)
}
}
}

0 comments on commit ac99879

Please sign in to comment.