Skip to content

Commit ee2d1dd

Browse files
committed
webdav: return forbidden on failed proppatch
Some file systems do not allow opening directories with a write flag. The PROPPATCH implementation always opens all files it tries to patch with O_RDWR. When running on Linux with the Dir implementation of FileSystem, this leads to all PROPPATCH calls to a directory failing with an Internal Server Error. Some clients, such as git via the Microsoft Mini Redirector try to patch directories' properties. A server using a Dir FileSystem fails in this situation, which makes it unusable for that entire class of clients. Rather than failing with a Internal Server Error we can instead return Forbidden, which indicates to the client that it's not allowed to patch properties on that file. This patch does so if we fail to open the file, and the error is because of a lack of permission, or because the file is a directory. We don't unconditionally return Forbidden in this case because other errors are more likey to be ephemeral: a client retrying could possibly succeed in a subsequent patch. Fixes golang/go#43929
1 parent 5f4716e commit ee2d1dd

File tree

1 file changed

+12
-1
lines changed

1 file changed

+12
-1
lines changed

webdav/prop.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,13 @@ loop:
307307

308308
f, err := fs.OpenFile(ctx, name, os.O_RDWR, 0)
309309
if err != nil {
310+
stat, statErr := fs.Stat(ctx, name)
311+
// If the error is a permission error or the file is a directory, return permission
312+
// denied. We check the directory case because some file systems do not support
313+
// writing to directories.
314+
if errors.Is(err, os.ErrPermission) || (statErr == nil && stat.IsDir()) {
315+
return patchesForbidden(patches), nil
316+
}
310317
return nil, err
311318
}
312319
defer f.Close()
@@ -327,13 +334,17 @@ loop:
327334
}
328335
// The file doesn't implement the optional DeadPropsHolder interface, so
329336
// all patches are forbidden.
337+
return patchesForbidden(patches), nil
338+
}
339+
340+
func patchesForbidden(patches []Proppatch) []Propstat {
330341
pstat := Propstat{Status: http.StatusForbidden}
331342
for _, patch := range patches {
332343
for _, p := range patch.Props {
333344
pstat.Props = append(pstat.Props, Property{XMLName: p.XMLName})
334345
}
335346
}
336-
return []Propstat{pstat}, nil
347+
return []Propstat{pstat}
337348
}
338349

339350
func escapeXML(s string) string {

0 commit comments

Comments
 (0)