From 8dc00d36eb6bf3f5b079472557cd484a109a9ef7 Mon Sep 17 00:00:00 2001 From: zicla Date: Sun, 14 Apr 2019 02:20:18 +0800 Subject: [PATCH] Use this. --- rest/dav/webdav.go | 168 +++++++++++++++++++++++---------------------- rest/dav/xml.go | 2 + 2 files changed, 88 insertions(+), 82 deletions(-) diff --git a/rest/dav/webdav.go b/rest/dav/webdav.go index 4b14ab2..c8e44fa 100644 --- a/rest/dav/webdav.go +++ b/rest/dav/webdav.go @@ -29,44 +29,44 @@ type Handler struct { Logger func(*http.Request, error) } -func (h *Handler) stripPrefix(p string) (string, int, error) { - if h.Prefix == "" { +func (this *Handler) stripPrefix(p string) (string, int, error) { + if this.Prefix == "" { return p, http.StatusOK, nil } - if r := strings.TrimPrefix(p, h.Prefix); len(r) < len(p) { + if r := strings.TrimPrefix(p, this.Prefix); len(r) < len(p) { return r, http.StatusOK, nil } return p, http.StatusNotFound, errPrefixMismatch } -func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (this *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { status, err := http.StatusBadRequest, errUnsupportedMethod - if h.FileSystem == nil { + if this.FileSystem == nil { status, err = http.StatusInternalServerError, errNoFileSystem - } else if h.LockSystem == nil { + } else if this.LockSystem == nil { status, err = http.StatusInternalServerError, errNoLockSystem } else { switch r.Method { case "OPTIONS": - status, err = h.handleOptions(w, r) + status, err = this.handleOptions(w, r) case "GET", "HEAD", "POST": - status, err = h.handleGetHeadPost(w, r) + status, err = this.handleGetHeadPost(w, r) case "DELETE": - status, err = h.handleDelete(w, r) + status, err = this.handleDelete(w, r) case "PUT": - status, err = h.handlePut(w, r) + status, err = this.handlePut(w, r) case "MKCOL": - status, err = h.handleMkcol(w, r) + status, err = this.handleMkcol(w, r) case "COPY", "MOVE": - status, err = h.handleCopyMove(w, r) + status, err = this.handleCopyMove(w, r) case "LOCK": - status, err = h.handleLock(w, r) + status, err = this.handleLock(w, r) case "UNLOCK": - status, err = h.handleUnlock(w, r) + status, err = this.handleUnlock(w, r) case "PROPFIND": - status, err = h.handlePropfind(w, r) + status, err = this.handlePropfind(w, r) case "PROPPATCH": - status, err = h.handleProppatch(w, r) + status, err = this.handleProppatch(w, r) } } @@ -76,13 +76,13 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Write([]byte(StatusText(status))) } } - if h.Logger != nil { - h.Logger(r, err) + if this.Logger != nil { + this.Logger(r, err) } } -func (h *Handler) lock(now time.Time, root string) (token string, status int, err error) { - token, err = h.LockSystem.Create(now, LockDetails{ +func (this *Handler) lock(now time.Time, root string) (token string, status int, err error) { + token, err = this.LockSystem.Create(now, LockDetails{ Root: root, Duration: infiniteTimeout, ZeroDepth: true, @@ -96,7 +96,7 @@ func (h *Handler) lock(now time.Time, root string) (token string, status int, er return token, 0, nil } -func (h *Handler) confirmLocks(r *http.Request, src, dst string) (release func(), status int, err error) { +func (this *Handler) confirmLocks(r *http.Request, src, dst string) (release func(), status int, err error) { hdr := r.Header.Get("If") if hdr == "" { // An empty If header means that the client hasn't previously created locks. @@ -106,16 +106,16 @@ func (h *Handler) confirmLocks(r *http.Request, src, dst string) (release func() // locks are unlocked at the end of the HTTP request. now, srcToken, dstToken := time.Now(), "", "" if src != "" { - srcToken, status, err = h.lock(now, src) + srcToken, status, err = this.lock(now, src) if err != nil { return nil, status, err } } if dst != "" { - dstToken, status, err = h.lock(now, dst) + dstToken, status, err = this.lock(now, dst) if err != nil { if srcToken != "" { - h.LockSystem.Unlock(now, srcToken) + this.LockSystem.Unlock(now, srcToken) } return nil, status, err } @@ -123,10 +123,10 @@ func (h *Handler) confirmLocks(r *http.Request, src, dst string) (release func() return func() { if dstToken != "" { - h.LockSystem.Unlock(now, dstToken) + this.LockSystem.Unlock(now, dstToken) } if srcToken != "" { - h.LockSystem.Unlock(now, srcToken) + this.LockSystem.Unlock(now, srcToken) } }, 0, nil } @@ -148,12 +148,12 @@ func (h *Handler) confirmLocks(r *http.Request, src, dst string) (release func() if u.Host != r.Host { continue } - lsrc, status, err = h.stripPrefix(u.Path) + lsrc, status, err = this.stripPrefix(u.Path) if err != nil { return nil, status, err } } - release, err = h.LockSystem.Confirm(time.Now(), lsrc, dst, l.conditions...) + release, err = this.LockSystem.Confirm(time.Now(), lsrc, dst, l.conditions...) if err == ErrConfirmationFailed { continue } @@ -169,14 +169,14 @@ func (h *Handler) confirmLocks(r *http.Request, src, dst string) (release func() return nil, http.StatusPreconditionFailed, ErrLocked } -func (h *Handler) handleOptions(w http.ResponseWriter, r *http.Request) (status int, err error) { - reqPath, status, err := h.stripPrefix(r.URL.Path) +func (this *Handler) handleOptions(w http.ResponseWriter, r *http.Request) (status int, err error) { + reqPath, status, err := this.stripPrefix(r.URL.Path) if err != nil { return status, err } ctx := r.Context() allow := "OPTIONS, LOCK, PUT, MKCOL" - if fi, err := h.FileSystem.Stat(ctx, reqPath); err == nil { + if fi, err := this.FileSystem.Stat(ctx, reqPath); err == nil { if fi.IsDir() { allow = "OPTIONS, LOCK, DELETE, PROPPATCH, COPY, MOVE, UNLOCK, PROPFIND" } else { @@ -191,14 +191,14 @@ func (h *Handler) handleOptions(w http.ResponseWriter, r *http.Request) (status return 0, nil } -func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (status int, err error) { - reqPath, status, err := h.stripPrefix(r.URL.Path) +func (this *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (status int, err error) { + reqPath, status, err := this.stripPrefix(r.URL.Path) if err != nil { return status, err } // TODO: check locks for read-only access?? ctx := r.Context() - f, err := h.FileSystem.OpenFile(ctx, reqPath, os.O_RDONLY, 0) + f, err := this.FileSystem.OpenFile(ctx, reqPath, os.O_RDONLY, 0) if err != nil { return http.StatusNotFound, err } @@ -210,7 +210,7 @@ func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (sta if fi.IsDir() { return http.StatusMethodNotAllowed, nil } - etag, err := findETag(ctx, h.FileSystem, h.LockSystem, reqPath, fi) + etag, err := findETag(ctx, this.FileSystem, this.LockSystem, reqPath, fi) if err != nil { return http.StatusInternalServerError, err } @@ -220,12 +220,12 @@ func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (sta return 0, nil } -func (h *Handler) handleDelete(w http.ResponseWriter, r *http.Request) (status int, err error) { - reqPath, status, err := h.stripPrefix(r.URL.Path) +func (this *Handler) handleDelete(w http.ResponseWriter, r *http.Request) (status int, err error) { + reqPath, status, err := this.stripPrefix(r.URL.Path) if err != nil { return status, err } - release, status, err := h.confirmLocks(r, reqPath, "") + release, status, err := this.confirmLocks(r, reqPath, "") if err != nil { return status, err } @@ -238,24 +238,24 @@ func (h *Handler) handleDelete(w http.ResponseWriter, r *http.Request) (status i // "godoc os RemoveAll" says that "If the path does not exist, RemoveAll // returns nil (no error)." WebDAV semantics are that it should return a // "404 Not Found". We therefore have to Stat before we RemoveAll. - if _, err := h.FileSystem.Stat(ctx, reqPath); err != nil { + if _, err := this.FileSystem.Stat(ctx, reqPath); err != nil { if os.IsNotExist(err) { return http.StatusNotFound, err } return http.StatusMethodNotAllowed, err } - if err := h.FileSystem.RemoveAll(ctx, reqPath); err != nil { + if err := this.FileSystem.RemoveAll(ctx, reqPath); err != nil { return http.StatusMethodNotAllowed, err } return http.StatusNoContent, nil } -func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int, err error) { - reqPath, status, err := h.stripPrefix(r.URL.Path) +func (this *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int, err error) { + reqPath, status, err := this.stripPrefix(r.URL.Path) if err != nil { return status, err } - release, status, err := h.confirmLocks(r, reqPath, "") + release, status, err := this.confirmLocks(r, reqPath, "") if err != nil { return status, err } @@ -264,7 +264,7 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int, // comments in http.checkEtag. ctx := r.Context() - f, err := h.FileSystem.OpenFile(ctx, reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) + f, err := this.FileSystem.OpenFile(ctx, reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { return http.StatusNotFound, err } @@ -281,7 +281,7 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int, if closeErr != nil { return http.StatusMethodNotAllowed, closeErr } - etag, err := findETag(ctx, h.FileSystem, h.LockSystem, reqPath, fi) + etag, err := findETag(ctx, this.FileSystem, this.LockSystem, reqPath, fi) if err != nil { return http.StatusInternalServerError, err } @@ -289,12 +289,12 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int, return http.StatusCreated, nil } -func (h *Handler) handleMkcol(w http.ResponseWriter, r *http.Request) (status int, err error) { - reqPath, status, err := h.stripPrefix(r.URL.Path) +func (this *Handler) handleMkcol(w http.ResponseWriter, r *http.Request) (status int, err error) { + reqPath, status, err := this.stripPrefix(r.URL.Path) if err != nil { return status, err } - release, status, err := h.confirmLocks(r, reqPath, "") + release, status, err := this.confirmLocks(r, reqPath, "") if err != nil { return status, err } @@ -305,7 +305,7 @@ func (h *Handler) handleMkcol(w http.ResponseWriter, r *http.Request) (status in if r.ContentLength > 0 { return http.StatusUnsupportedMediaType, nil } - if err := h.FileSystem.Mkdir(ctx, reqPath, 0777); err != nil { + if err := this.FileSystem.Mkdir(ctx, reqPath, 0777); err != nil { if os.IsNotExist(err) { return http.StatusConflict, err } @@ -314,7 +314,7 @@ func (h *Handler) handleMkcol(w http.ResponseWriter, r *http.Request) (status in return http.StatusCreated, nil } -func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request) (status int, err error) { +func (this *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request) (status int, err error) { hdr := r.Header.Get("Destination") if hdr == "" { return http.StatusBadRequest, errInvalidDestination @@ -327,12 +327,12 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request) (status return http.StatusBadGateway, errInvalidDestination } - src, status, err := h.stripPrefix(r.URL.Path) + src, status, err := this.stripPrefix(r.URL.Path) if err != nil { return status, err } - dst, status, err := h.stripPrefix(u.Path) + dst, status, err := this.stripPrefix(u.Path) if err != nil { return status, err } @@ -352,7 +352,7 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request) (status // even though a COPY doesn't modify the source, if a concurrent // operation modifies the source. However, the litmus test explicitly // checks that COPYing a locked-by-another source is OK. - release, status, err := h.confirmLocks(r, "", dst) + release, status, err := this.confirmLocks(r, "", dst) if err != nil { return status, err } @@ -369,10 +369,10 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request) (status return http.StatusBadRequest, errInvalidDepth } } - return copyFiles(ctx, h.FileSystem, src, dst, r.Header.Get("Overwrite") != "F", depth, 0) + return copyFiles(ctx, this.FileSystem, src, dst, r.Header.Get("Overwrite") != "F", depth, 0) } - release, status, err := h.confirmLocks(r, src, dst) + release, status, err := this.confirmLocks(r, src, dst) if err != nil { return status, err } @@ -386,10 +386,10 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request) (status return http.StatusBadRequest, errInvalidDepth } } - return moveFiles(ctx, h.FileSystem, src, dst, r.Header.Get("Overwrite") == "T") + return moveFiles(ctx, this.FileSystem, src, dst, r.Header.Get("Overwrite") == "T") } -func (h *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStatus int, retErr error) { +func (this *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStatus int, retErr error) { duration, err := parseTimeout(r.Header.Get("Timeout")) if err != nil { return http.StatusBadRequest, err @@ -413,7 +413,7 @@ func (h *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStatus if token == "" { return http.StatusBadRequest, errInvalidLockToken } - ld, err = h.LockSystem.Refresh(now, token, duration) + ld, err = this.LockSystem.Refresh(now, token, duration) if err != nil { if err == ErrNoSuchLock { return http.StatusPreconditionFailed, err @@ -433,7 +433,7 @@ func (h *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStatus return http.StatusBadRequest, errInvalidDepth } } - reqPath, status, err := h.stripPrefix(r.URL.Path) + reqPath, status, err := this.stripPrefix(r.URL.Path) if err != nil { return status, err } @@ -443,7 +443,7 @@ func (h *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStatus OwnerXML: li.Owner.InnerXML, ZeroDepth: depth == 0, } - token, err = h.LockSystem.Create(now, ld) + token, err = this.LockSystem.Create(now, ld) if err != nil { if err == ErrLocked { return StatusLocked, err @@ -452,13 +452,13 @@ func (h *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStatus } defer func() { if retErr != nil { - h.LockSystem.Unlock(now, token) + this.LockSystem.Unlock(now, token) } }() // Create the resource if it didn't previously exist. - if _, err := h.FileSystem.Stat(ctx, reqPath); err != nil { - f, err := h.FileSystem.OpenFile(ctx, reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) + if _, err := this.FileSystem.Stat(ctx, reqPath); err != nil { + f, err := this.FileSystem.OpenFile(ctx, reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { // TODO: detect missing intermediate dirs and return http.StatusConflict? return http.StatusInternalServerError, err @@ -483,7 +483,7 @@ func (h *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStatus return 0, nil } -func (h *Handler) handleUnlock(w http.ResponseWriter, r *http.Request) (status int, err error) { +func (this *Handler) handleUnlock(w http.ResponseWriter, r *http.Request) (status int, err error) { // http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token says that the // Lock-Token value is a Coded-URL. We strip its angle brackets. t := r.Header.Get("Lock-Token") @@ -492,7 +492,7 @@ func (h *Handler) handleUnlock(w http.ResponseWriter, r *http.Request) (status i } t = t[1 : len(t)-1] - switch err = h.LockSystem.Unlock(time.Now(), t); err { + switch err = this.LockSystem.Unlock(time.Now(), t); err { case nil: return http.StatusNoContent, err case ErrForbidden: @@ -506,13 +506,13 @@ func (h *Handler) handleUnlock(w http.ResponseWriter, r *http.Request) (status i } } -func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status int, err error) { - reqPath, status, err := h.stripPrefix(r.URL.Path) +func (this *Handler) handlePropfind(writer http.ResponseWriter, request *http.Request) (status int, err error) { + reqPath, status, err := this.stripPrefix(request.URL.Path) if err != nil { return status, err } - ctx := r.Context() - fi, err := h.FileSystem.Stat(ctx, reqPath) + ctx := request.Context() + fi, err := this.FileSystem.Stat(ctx, reqPath) if err != nil { if os.IsNotExist(err) { return http.StatusNotFound, err @@ -520,26 +520,30 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status return http.StatusMethodNotAllowed, err } depth := infiniteDepth - if hdr := r.Header.Get("Depth"); hdr != "" { + if hdr := request.Header.Get("Depth"); hdr != "" { depth = parseDepth(hdr) if depth == invalidDepth { return http.StatusBadRequest, errInvalidDepth } } - pf, status, err := readPropfind(r.Body) + //读取出request希望获取的文件属性。 + pf, status, err := readPropfind(request.Body) if err != nil { return status, err } - mw := multistatusWriter{w: w} + mw := multistatusWriter{w: writer} walkFn := func(reqPath string, info os.FileInfo, err error) error { if err != nil { return err } + + fmt.Printf("浏览:%s {name=%s,IsDir=%v,Mode=%v,ModTime=%v,Size=%v}\n", + reqPath, info.Name(), info.IsDir(), info.Mode(), info.ModTime(), info.Size()) var pstats []Propstat if pf.Propname != nil { - pnames, err := propnames(ctx, h.FileSystem, h.LockSystem, reqPath) + pnames, err := propnames(ctx, this.FileSystem, this.LockSystem, reqPath) if err != nil { return err } @@ -549,21 +553,21 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status } pstats = append(pstats, pstat) } else if pf.Allprop != nil { - pstats, err = allprop(ctx, h.FileSystem, h.LockSystem, reqPath, pf.Prop) + pstats, err = allprop(ctx, this.FileSystem, this.LockSystem, reqPath, pf.Prop) } else { - pstats, err = props(ctx, h.FileSystem, h.LockSystem, reqPath, pf.Prop) + pstats, err = props(ctx, this.FileSystem, this.LockSystem, reqPath, pf.Prop) } if err != nil { return err } - href := path.Join(h.Prefix, reqPath) + href := path.Join(this.Prefix, reqPath) if info.IsDir() { href += "/" } return mw.write(makePropstatResponse(href, pstats)) } - walkErr := walkFS(ctx, h.FileSystem, depth, reqPath, fi, walkFn) + walkErr := walkFS(ctx, this.FileSystem, depth, reqPath, fi, walkFn) closeErr := mw.close() if walkErr != nil { return http.StatusInternalServerError, walkErr @@ -574,12 +578,12 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status return 0, nil } -func (h *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (status int, err error) { - reqPath, status, err := h.stripPrefix(r.URL.Path) +func (this *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (status int, err error) { + reqPath, status, err := this.stripPrefix(r.URL.Path) if err != nil { return status, err } - release, status, err := h.confirmLocks(r, reqPath, "") + release, status, err := this.confirmLocks(r, reqPath, "") if err != nil { return status, err } @@ -587,7 +591,7 @@ func (h *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (statu ctx := r.Context() - if _, err := h.FileSystem.Stat(ctx, reqPath); err != nil { + if _, err := this.FileSystem.Stat(ctx, reqPath); err != nil { if os.IsNotExist(err) { return http.StatusNotFound, err } @@ -597,7 +601,7 @@ func (h *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (statu if err != nil { return status, err } - pstats, err := patch(ctx, h.FileSystem, h.LockSystem, reqPath, patches) + pstats, err := patch(ctx, this.FileSystem, this.LockSystem, reqPath, patches) if err != nil { return http.StatusInternalServerError, err } diff --git a/rest/dav/xml.go b/rest/dav/xml.go index 06aac0e..c8cae23 100644 --- a/rest/dav/xml.go +++ b/rest/dav/xml.go @@ -70,6 +70,7 @@ func readLockInfo(r io.Reader) (li lockInfo, status int, err error) { return li, 0, nil } +//这是一个带字节计数器的Reader,可以知道总共读取了多少个字节。 type countingReader struct { n int r io.Reader @@ -175,6 +176,7 @@ type propfind struct { Include propfindProps `xml:"DAV: include"` } +//从request中读出需要的属性。比如:getcontentlength 大小 creationdate 创建时间 func readPropfind(r io.Reader) (pf propfind, status int, err error) { c := countingReader{r: r} if err = ixml.NewDecoder(&c).Decode(&pf); err != nil {