Skip to content

Commit f15817d

Browse files
klarosenigeltao
authored andcommitted
webdav: ignore path and perm errors in PROPFIND
PROPFIND can walk through directories, retrieving information about each file. Unfortunately, the filesystem may deny access to the WebDAV server for various reasons, such as the file truly not being readable (e.g. a broken symlink), or because the server does not have permission to read the file. PROPFIND should ignore these. The current behaviour of the WebDAV server when encountering such issues is to immediately stop its walk, and output an http 500. This leads to poor behaviour with the builtin golang server, since the walk has likely already written out its status header as part of serving the previously walked files' properties. The server closes the response, also emitting an error log. While the error log is noisy, the closed response is truly an issue: the xml returned to the client is invalid, which means that the response is useless. It is not unreasonable to expect that a directory shared using WebDAV has files which cannot be read for the reasons given above. The shared directory becomes useless with the current behavior. Rather than making directories with unreadable files useless, skip over anything that is bad. A more nuanced solution to this problem could likely involve indicating that the requested properties have problems, or buffering the response prior to returning the failure. However, this change is simple and a move in the right direction. Fixes golang/go#16195 Fixes golang/go#43782 Change-Id: I065e4c90f7ef797709e5e81e7318c3eafae6db71 GitHub-Last-Rev: d56917e GitHub-Pull-Request: #91 Reviewed-on: https://go-review.googlesource.com/c/net/+/285752 Reviewed-by: Nigel Tao <nigeltao@golang.org> Reviewed-by: Nigel Tao (INACTIVE; USE @golang.org INSTEAD) <nigeltao@google.com> Run-TryBot: Nigel Tao <nigeltao@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Matthew Holt <matthew.holt@gmail.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
1 parent 0b7e1fb commit f15817d

File tree

1 file changed

+32
-3
lines changed

1 file changed

+32
-3
lines changed

‎webdav/webdav.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"net/url"
1414
"os"
1515
"path"
16+
"path/filepath"
1617
"strings"
1718
"time"
1819
)
@@ -535,13 +536,14 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status
535536

536537
walkFn := func(reqPath string, info os.FileInfo, err error) error {
537538
if err != nil {
538-
return err
539+
return handlePropfindError(err, info)
539540
}
541+
540542
var pstats []Propstat
541543
if pf.Propname != nil {
542544
pnames, err := propnames(ctx, h.FileSystem, h.LockSystem, reqPath)
543545
if err != nil {
544-
return err
546+
return handlePropfindError(err, info)
545547
}
546548
pstat := Propstat{Status: http.StatusOK}
547549
for _, xmlname := range pnames {
@@ -554,7 +556,7 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status
554556
pstats, err = props(ctx, h.FileSystem, h.LockSystem, reqPath, pf.Prop)
555557
}
556558
if err != nil {
557-
return err
559+
return handlePropfindError(err, info)
558560
}
559561
href := path.Join(h.Prefix, reqPath)
560562
if href != "/" && info.IsDir() {
@@ -633,6 +635,33 @@ func makePropstatResponse(href string, pstats []Propstat) *response {
633635
return &resp
634636
}
635637

638+
func handlePropfindError(err error, info os.FileInfo) error {
639+
var skipResp error = nil
640+
if info != nil && info.IsDir() {
641+
skipResp = filepath.SkipDir
642+
}
643+
644+
if errors.Is(err, os.ErrPermission) {
645+
// If the server cannot recurse into a directory because it is not allowed,
646+
// then there is nothing more to say about it. Just skip sending anything.
647+
return skipResp
648+
}
649+
650+
if _, ok := err.(*os.PathError); ok {
651+
// If the file is just bad, it couldn't be a proper WebDAV resource. Skip it.
652+
return skipResp
653+
}
654+
655+
// We need to be careful with other errors: there is no way to abort the xml stream
656+
// part way through while returning a valid PROPFIND response. Returning only half
657+
// the data would be misleading, but so would be returning results tainted by errors.
658+
// The curent behaviour by returning an error here leads to the stream being aborted,
659+
// and the parent http server complaining about writing a spurious header. We should
660+
// consider further enhancing this error handling to more gracefully fail, or perhaps
661+
// buffer the entire response until we've walked the tree.
662+
return err
663+
}
664+
636665
const (
637666
infiniteDepth = -1
638667
invalidDepth = -2

0 commit comments

Comments
 (0)