diff --git a/rest/dav/file.go b/rest/dav/file.go index 6e9c982..afc2cc8 100644 --- a/rest/dav/file.go +++ b/rest/dav/file.go @@ -748,7 +748,7 @@ func copyFiles(ctx context.Context, fs FileSystem, src, dst string, overwrite bo // Allowed values for depth are 0, 1 or infiniteDepth. For each visited node, // walkFS calls walkFn. If a visited file system node is a directory and // walkFn returns filepath.SkipDir, walkFS will skip traversal of this node. -func walkFS(ctx context.Context, fs FileSystem, depth int, name string, info os.FileInfo, walkFn filepath.WalkFunc) error { +func WalkFS(ctx context.Context, fs FileSystem, depth int, name string, info os.FileInfo, walkFn filepath.WalkFunc) error { // This implementation is based on Walk's code in the standard path/filepath package. err := walkFn(name, info, nil) if err != nil { @@ -783,7 +783,7 @@ func walkFS(ctx context.Context, fs FileSystem, depth int, name string, info os. return err } } else { - err = walkFS(ctx, fs, depth, filename, fileInfo, walkFn) + err = WalkFS(ctx, fs, depth, filename, fileInfo, walkFn) if err != nil { if !fileInfo.IsDir() || err != filepath.SkipDir { return err diff --git a/rest/dav/prop.go b/rest/dav/prop.go index 77125ad..cadefca 100644 --- a/rest/dav/prop.go +++ b/rest/dav/prop.go @@ -166,7 +166,7 @@ var liveProps = map[xml.Name]struct { // // Each Propstat has a unique status and each property name will only be part // of one Propstat element. -func props(ctx context.Context, fs FileSystem, ls LockSystem, name string, pnames []xml.Name) ([]Propstat, error) { +func Props(ctx context.Context, fs FileSystem, ls LockSystem, name string, pnames []xml.Name) ([]Propstat, error) { f, err := fs.OpenFile(ctx, name, os.O_RDONLY, 0) if err != nil { return nil, err @@ -214,7 +214,7 @@ func props(ctx context.Context, fs FileSystem, ls LockSystem, name string, pname } // Propnames returns the property names defined for resource name. -func propnames(ctx context.Context, fs FileSystem, ls LockSystem, name string) ([]xml.Name, error) { +func Propnames(ctx context.Context, fs FileSystem, ls LockSystem, name string) ([]xml.Name, error) { f, err := fs.OpenFile(ctx, name, os.O_RDONLY, 0) if err != nil { return nil, err @@ -254,8 +254,8 @@ func propnames(ctx context.Context, fs FileSystem, ls LockSystem, name string) ( // returned if they are named in 'include'. // // See http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND -func allprop(ctx context.Context, fs FileSystem, ls LockSystem, name string, include []xml.Name) ([]Propstat, error) { - pnames, err := propnames(ctx, fs, ls, name) +func Allprop(ctx context.Context, fs FileSystem, ls LockSystem, name string, include []xml.Name) ([]Propstat, error) { + pnames, err := Propnames(ctx, fs, ls, name) if err != nil { return nil, err } @@ -269,7 +269,7 @@ func allprop(ctx context.Context, fs FileSystem, ls LockSystem, name string, inc pnames = append(pnames, pn) } } - return props(ctx, fs, ls, name, pnames) + return Props(ctx, fs, ls, name, pnames) } // Patch patches the properties of resource name. The return values are diff --git a/rest/dav/webdav.go b/rest/dav/webdav.go index a52f187..af21a8f 100644 --- a/rest/dav/webdav.go +++ b/rest/dav/webdav.go @@ -527,12 +527,12 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status return http.StatusBadRequest, errInvalidDepth } } - pf, status, err := readPropfind(r.Body) + pf, status, err := ReadPropfind(r.Body) if err != nil { return status, err } - mw := multistatusWriter{w: w} + mw := MultiStatusWriter{Writer: w} walkFn := func(reqPath string, info os.FileInfo, err error) error { if err != nil { @@ -540,7 +540,7 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status } var pstats []Propstat if pf.Propname != nil { - pnames, err := propnames(ctx, h.FileSystem, h.LockSystem, reqPath) + pnames, err := Propnames(ctx, h.FileSystem, h.LockSystem, reqPath) if err != nil { return err } @@ -550,9 +550,9 @@ 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, h.FileSystem, h.LockSystem, reqPath, pf.Prop) } else { - pstats, err = props(ctx, h.FileSystem, h.LockSystem, reqPath, pf.Prop) + pstats, err = Props(ctx, h.FileSystem, h.LockSystem, reqPath, pf.Prop) } if err != nil { return err @@ -561,11 +561,11 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status if info.IsDir() { href += "/" } - return mw.write(makePropstatResponse(href, pstats)) + return mw.Write(MakePropstatResponse(href, pstats)) } - walkErr := walkFS(ctx, h.FileSystem, depth, reqPath, fi, walkFn) - closeErr := mw.close() + walkErr := WalkFS(ctx, h.FileSystem, depth, reqPath, fi, walkFn) + closeErr := mw.Close() if walkErr != nil { return http.StatusInternalServerError, walkErr } @@ -602,9 +602,9 @@ func (h *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (statu if err != nil { return http.StatusInternalServerError, err } - mw := multistatusWriter{w: w} - writeErr := mw.write(makePropstatResponse(r.URL.Path, pstats)) - closeErr := mw.close() + mw := MultiStatusWriter{Writer: w} + writeErr := mw.Write(MakePropstatResponse(r.URL.Path, pstats)) + closeErr := mw.Close() if writeErr != nil { return http.StatusInternalServerError, writeErr } @@ -614,7 +614,7 @@ func (h *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (statu return 0, nil } -func makePropstatResponse(href string, pstats []Propstat) *response { +func MakePropstatResponse(href string, pstats []Propstat) *response { resp := response{ Href: []string{(&url.URL{Path: href}).EscapedPath()}, Propstat: make([]propstat, 0, len(pstats)), diff --git a/rest/dav/xml.go b/rest/dav/xml.go index 11f7b0f..03ef8a7 100644 --- a/rest/dav/xml.go +++ b/rest/dav/xml.go @@ -50,7 +50,7 @@ type owner struct { } func readLockInfo(r io.Reader) (li lockInfo, status int, err error) { - c := &countingReader{r: r} + c := &CountingReader{r: r} if err = ixml.NewDecoder(c).Decode(&li); err != nil { if err == io.EOF { if c.n == 0 { @@ -70,12 +70,12 @@ func readLockInfo(r io.Reader) (li lockInfo, status int, err error) { return li, 0, nil } -type countingReader struct { +type CountingReader struct { n int r io.Reader } -func (c *countingReader) Read(p []byte) (int, error) { +func (c *CountingReader) Read(p []byte) (int, error) { n, err := c.r.Read(p) c.n += n return n, err @@ -175,8 +175,8 @@ type Propfind struct { Include PropfindProps `xml:"DAV: include"` } -func readPropfind(r io.Reader) (pf Propfind, status int, err error) { - c := countingReader{r: r} +func ReadPropfind(r io.Reader) (pf Propfind, status int, err error) { + c := CountingReader{r: r} if err = ixml.NewDecoder(&c).Decode(&pf); err != nil { if err == io.EOF { if c.n == 0 { @@ -233,14 +233,14 @@ type ixmlProperty struct { } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_error -// See multistatusWriter for the "D:" namespace prefix. +// See MultiStatusWriter for the "D:" namespace prefix. type xmlError struct { XMLName ixml.Name `xml:"D:error"` InnerXML []byte `xml:",innerxml"` } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_propstat -// See multistatusWriter for the "D:" namespace prefix. +// See MultiStatusWriter for the "D:" namespace prefix. type propstat struct { Prop []Property `xml:"D:prop>_ignored_"` Status string `xml:"D:status"` @@ -258,7 +258,7 @@ type ixmlPropstat struct { } // MarshalXML prepends the "D:" namespace prefix on properties in the DAV: namespace -// before encoding. See multistatusWriter. +// before encoding. See MultiStatusWriter. func (ps propstat) MarshalXML(e *ixml.Encoder, start ixml.StartElement) error { // Convert from a propstat to an ixmlPropstat. ixmlPs := ixmlPropstat{ @@ -287,7 +287,7 @@ func (ps propstat) MarshalXML(e *ixml.Encoder, start ixml.StartElement) error { } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_response -// See multistatusWriter for the "D:" namespace prefix. +// See MultiStatusWriter for the "D:" namespace prefix. type response struct { XMLName ixml.Name `xml:"D:response"` Href []string `xml:"D:href"` @@ -306,15 +306,15 @@ type response struct { // well. This is because some versions of Mini-Redirector (on windows 7) ignore // elements with a default namespace (no prefixed namespace). A less intrusive fix // should be possible after golang.org/cl/11074. See https://golang.org/issue/11177 -type multistatusWriter struct { +type MultiStatusWriter struct { // ResponseDescription contains the optional responsedescription // of the multistatus XML element. Only the latest content before // close will be emitted. Empty response descriptions are not // written. responseDescription string - w http.ResponseWriter - enc *ixml.Encoder + Writer http.ResponseWriter + enc *ixml.Encoder } // Write validates and emits a DAV response as part of a multistatus response @@ -325,7 +325,7 @@ type multistatusWriter struct { // first, valid response to be written, Write prepends the XML representation // of r with a multistatus tag. Callers must call close after the last response // has been written. -func (w *multistatusWriter) write(r *response) error { +func (w *MultiStatusWriter) Write(r *response) error { switch len(r.Href) { case 0: return errInvalidResponse @@ -338,7 +338,7 @@ func (w *multistatusWriter) write(r *response) error { return errInvalidResponse } } - err := w.writeHeader() + err := w.WriteHeader() if err != nil { return err } @@ -348,17 +348,17 @@ func (w *multistatusWriter) write(r *response) error { // writeHeader writes a XML multistatus start element on w's underlying // http.ResponseWriter and returns the result of the write operation. // After the first write attempt, writeHeader becomes a no-op. -func (w *multistatusWriter) writeHeader() error { +func (w *MultiStatusWriter) WriteHeader() error { if w.enc != nil { return nil } - w.w.Header().Add("Content-Type", "text/xml; charset=utf-8") - w.w.WriteHeader(StatusMulti) - _, err := fmt.Fprintf(w.w, ``) + w.Writer.Header().Add("Content-Type", "text/xml; charset=utf-8") + w.Writer.WriteHeader(StatusMulti) + _, err := fmt.Fprintf(w.Writer, ``) if err != nil { return err } - w.enc = ixml.NewEncoder(w.w) + w.enc = ixml.NewEncoder(w.Writer) return w.enc.EncodeToken(ixml.StartElement{ Name: ixml.Name{ Space: "DAV:", @@ -375,7 +375,7 @@ func (w *multistatusWriter) writeHeader() error { // an error if the multistatus response could not be completed. If both the // return value and field enc of w are nil, then no multistatus response has // been written. -func (w *multistatusWriter) close() error { +func (w *MultiStatusWriter) Close() error { if w.enc == nil { return nil } diff --git a/rest/dav_service.go b/rest/dav_service.go index 8944e0b..67d4518 100644 --- a/rest/dav_service.go +++ b/rest/dav_service.go @@ -2,6 +2,8 @@ package rest import ( "net/http" + "os" + "tank/rest/dav" ) //@Service @@ -47,74 +49,70 @@ func parseDepth(s string) int { return invalidDepth } - //处理 方法 func (this *DavService) HandlePropfind(w http.ResponseWriter, r *http.Request) { - //basePath := "/Users/fusu/d/group/golang/src/tank/tmp/dav" - // - //reqPath := r.URL.Path - // - //ctx := r.Context() - // - //fi, err := os.Stat(basePath + reqPath) - //if err != nil { - // this.PanicError(err) - //} - // - //depth := infiniteDepth - //if hdr := r.Header.Get("Depth"); hdr != "" { - // depth = parseDepth(hdr) - // if depth == invalidDepth { - // this.PanicBadRequest("Depth指定错误!") - // } - //} - // - //pf, status, err := readPropfind(r.Body) - //if err != nil { - // return status, err - //} - // - //mw := multistatusWriter{w: w} - // - //walkFn := func(reqPath string, info os.FileInfo, err error) error { - // if err != nil { - // return err - // } - // var pstats []Propstat - // if pf.Propname != nil { - // pnames, err := propnames(ctx, h.FileSystem, h.LockSystem, reqPath) - // if err != nil { - // return err - // } - // pstat := Propstat{Status: http.StatusOK} - // for _, xmlname := range pnames { - // pstat.Props = append(pstat.Props, Property{XMLName: xmlname}) - // } - // pstats = append(pstats, pstat) - // } else if pf.Allprop != nil { - // pstats, err = allprop(ctx, h.FileSystem, h.LockSystem, reqPath, pf.Prop) - // } else { - // pstats, err = props(ctx, h.FileSystem, h.LockSystem, reqPath, pf.Prop) - // } - // if err != nil { - // return err - // } - // href := path.Join(h.Prefix, reqPath) - // if info.IsDir() { - // href += "/" - // } - // return mw.write(makePropstatResponse(href, pstats)) - //} - // - //walkErr := walkFS(ctx, h.FileSystem, depth, reqPath, fi, walkFn) - //closeErr := mw.close() - //if walkErr != nil { - // return http.StatusInternalServerError, walkErr - //} - //if closeErr != nil { - // return http.StatusInternalServerError, closeErr - //} - //return 0, nil + basePath := "/Users/fusu/d/group/golang/src/tank/tmp/dav" + + fileSystem := dav.Dir("/Users/fusu/d/group/golang/src/tank/tmp/dav") + lockSystem := dav.NewMemLS() + + reqPath := r.URL.Path + + ctx := r.Context() + + fi, err := os.Stat(basePath + reqPath) + if err != nil { + this.PanicError(err) + } + + depth := infiniteDepth + if hdr := r.Header.Get("Depth"); hdr != "" { + depth = parseDepth(hdr) + if depth == invalidDepth { + this.PanicBadRequest("Depth指定错误!") + } + } + + pf, _, err := dav.ReadPropfind(r.Body) + + this.PanicError(err) + + mw := dav.MultiStatusWriter{Writer: w} + + walkFn := func(reqPath string, info os.FileInfo, err error) error { + if err != nil { + return err + } + var pstats []dav.Propstat + if pf.Propname != nil { + pnames, err := dav.Propnames(ctx, fileSystem, lockSystem, reqPath) + if err != nil { + return err + } + pstat := dav.Propstat{Status: http.StatusOK} + for _, xmlname := range pnames { + pstat.Props = append(pstat.Props, dav.Property{XMLName: xmlname}) + } + pstats = append(pstats, pstat) + } else if pf.Allprop != nil { + pstats, err = dav.Allprop(ctx, fileSystem, lockSystem, reqPath, pf.Prop) + } else { + pstats, err = dav.Props(ctx, fileSystem, lockSystem, reqPath, pf.Prop) + } + if err != nil { + return err + } + href := reqPath + if info.IsDir() { + href += "/" + } + return mw.Write(dav.MakePropstatResponse(href, pstats)) + } + + walkErr := dav.WalkFS(ctx, fileSystem, depth, reqPath, fi, walkFn) + closeErr := mw.Close() + this.PanicError(walkErr) + this.PanicError(closeErr) }