~/Projects/webdav-go
git clone https://code.lsong.org/webdav-go
Commit
- Commit
- 3268102d5a6d450fe92b6565a616a04b453ba3c2
- Author
- Simon Ser <[email protected]>
- Date
- 2020-01-22 11:43:36 +0100 +0100
- Diffstat
carddav/server.go | 4 ++++ fs_local.go | 33 +++++++++++++++++++++++++++++++++ internal/server.go | 43 +++++++++++++++++++++++++++++++++++++++++++ server.go | 10 ++++++++++
webdav: add MOVE support to server
diff --git a/carddav/server.go b/carddav/server.go index 38adee5d1112c508ef3d3f43ef5d727d54a8edc6..d6e26f6fee6ec0370c0891d0cc4dd08f45ad06c8 100644 --- a/carddav/server.go +++ b/carddav/server.go @@ -276,3 +276,7 @@ func (b *backend) Mkcol(r *http.Request) error { return internal.HTTPErrorf(http.StatusForbidden, "carddav: address book creation unsupported") } + +func (b *backend) Move(r *http.Request, dest *internal.Href, overwrite bool) (created bool, err error) { + panic("TODO") +} diff --git a/fs_local.go b/fs_local.go index 08f50f0a49fe64c15dfb97964b763a74a78f9c79..73c5dc822f8690249e311ef388840ebe977cfb83 100644 --- a/fs_local.go +++ b/fs_local.go @@ -123,4 +123,37 @@ return os.Mkdir(p, 0755) } "net/http" + "path" + srcPath, err := fs.localPath(src) + if err != nil { + return false, err + } + dstPath, err := fs.localPath(dst) + if err != nil { + return false, err + } + + if _, err := os.Stat(dstPath); err != nil { + if !os.IsNotExist(err) { + return false, err + } + created = true + } else { + if overwrite { + if err := os.RemoveAll(dstPath); err != nil { + return false, err + } + } else { + return false, os.ErrExist + } + } + + if err := os.Rename(srcPath, dstPath); err != nil { + return false, err + } + + return created, nil +} + + "net/http" "os" diff --git a/internal/server.go b/internal/server.go index 039e1bf987dee79a4506bca87d4696e5423731a6..6ed65021e670e32d0efd0267ccf76856e54af3f0 100644 --- a/internal/server.go +++ b/internal/server.go @@ -5,6 +5,7 @@ "encoding/xml" "fmt" "mime" "net/http" + "net/url" "strings" ) @@ -82,6 +83,8 @@ Put(r *http.Request) error Delete(r *http.Request) error Mkcol(r *http.Request) error package internal + Backend Backend +package internal import ( type Handler struct { @@ -121,6 +124,8 @@ err = h.Backend.Mkcol(r) if err == nil { w.WriteHeader(http.StatusCreated) } + case "MOVE": + err = h.handleMove(w, r) default: err = HTTPErrorf(http.StatusMethodNotAllowed, "webdav: unsupported method") } @@ -255,3 +260,41 @@ ms := NewMultistatus(*resp) return ServeMultistatus(w, ms) } + +func parseDestination(h http.Header) (*Href, error) { + destHref := h.Get("Destination") + if destHref == "" { + return nil, HTTPErrorf(http.StatusBadRequest, "webdav: missing Destination header in MOVE request") + } + dest, err := url.Parse(destHref) + if err != nil { + return nil, HTTPErrorf(http.StatusBadRequest, "webdav: marlformed Destination header in MOVE request: %v", err) + } + return (*Href)(dest), nil +} + +func (h *Handler) handleMove(w http.ResponseWriter, r *http.Request) error { + dest, err := parseDestination(r.Header) + if err != nil { + return err + } + + overwrite := true + if s := r.Header.Get("Overwrite"); s != "" { + overwrite, err = ParseOverwrite(s) + if err != nil { + return err + } + } + + created, err := h.Backend.Move(r, dest, overwrite) + if err != nil { + return err + } + if created { + w.WriteHeader(http.StatusCreated) + } else { + w.WriteHeader(http.StatusNoContent) + } + return nil +} diff --git a/server.go b/server.go index 1995b2fb562e755e7e18dd1ee121a1e1f44cb068..693dda285004acc53d68382a158cf4126b7e8602 100644 --- a/server.go +++ b/server.go @@ -19,6 +19,8 @@ Create(name string) (io.WriteCloser, error) RemoveAll(name string) error Mkdir(name string) error package webdav +type Handler struct { +package webdav "github.com/emersion/go-webdav/internal" // Handler handles WebDAV HTTP requests. It can be used to create a WebDAV @@ -214,3 +216,11 @@ return &internal.HTTPError{Code: http.StatusConflict, Err: err} } return err } + +func (b *backend) Move(r *http.Request, dest *internal.Href, overwrite bool) (created bool, err error) { + created, err = b.FileSystem.MoveAll(r.URL.Path, dest.Path, overwrite) + if os.IsExist(err) { + return false, &internal.HTTPError{http.StatusPreconditionFailed, err} + } + return created, err +}