Browse Source

webdav: delete the PropSystem and MemPS types.

Change-Id: I569993723942f71599411a25ff31e97c1bc8875c
Reviewed-on: https://go-review.googlesource.com/10305
Reviewed-by: Robert Stepanek <robert.stepanek@gmail.com>
Reviewed-by: Nigel Tao <nigeltao@golang.org>
Nigel Tao 10 years ago
parent
commit
ad9eb3904a
4 changed files with 104 additions and 157 deletions
  1. 2 5
      webdav/litmus_test_server.go
  2. 52 94
      webdav/prop.go
  3. 43 44
      webdav/prop_test.go
  4. 7 14
      webdav/webdav.go

+ 2 - 5
webdav/litmus_test_server.go

@@ -32,12 +32,9 @@ var port = flag.Int("port", 9999, "server port")
 func main() {
 	flag.Parse()
 	log.SetFlags(0)
-	fs := webdav.NewMemFS()
-	ls := webdav.NewMemLS()
 	h := &webdav.Handler{
-		FileSystem: fs,
-		LockSystem: ls,
-		PropSystem: webdav.NewMemPS(fs, ls),
+		FileSystem: webdav.NewMemFS(),
+		LockSystem: webdav.NewMemLS(),
 		Logger: func(r *http.Request, err error) {
 			litmus := r.Header.Get("X-Litmus")
 			if len(litmus) > 19 {

+ 52 - 94
webdav/prop.go

@@ -15,50 +15,6 @@ import (
 	"strconv"
 )
 
-// TODO(nigeltao): eliminate the concept of a configurable PropSystem, and the
-// MemPS implementation. Properties are now the responsibility of a File
-// implementation, not a PropSystem implementation.
-
-// PropSystem manages the properties of named resources. It allows finding
-// and setting properties as defined in RFC 4918.
-//
-// The elements in a resource name are separated by slash ('/', U+002F)
-// characters, regardless of host operating system convention.
-type PropSystem interface {
-	// Find returns the status of properties named propnames for resource name.
-	//
-	// Each Propstat must have a unique status and each property name must
-	// only be part of one Propstat element.
-	Find(name string, propnames []xml.Name) ([]Propstat, error)
-
-	// TODO(nigeltao) merge Find and Allprop?
-
-	// Allprop returns the properties defined for resource name and the
-	// properties named in include. The returned Propstats are handled
-	// as in Find.
-	//
-	// Note that RFC 4918 defines 'allprop' to return the DAV: properties
-	// defined within the RFC plus dead properties. Other live properties
-	// should only be returned if they are named in 'include'.
-	//
-	// See http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND
-	Allprop(name string, include []xml.Name) ([]Propstat, error)
-
-	// Propnames returns the property names defined for resource name.
-	Propnames(name string) ([]xml.Name, error)
-
-	// Patch patches the properties of resource name.
-	//
-	// If all patches can be applied without conflict, Patch returns a slice
-	// of length one and a Propstat element of status 200, naming all patched
-	// properties. In case of conflict, Patch returns an arbitrary long slice
-	// and no Propstat element must have status 200. In either case, properties
-	// in Propstat must not have values.
-	//
-	// Note that the WebDAV RFC requires either all patches to succeed or none.
-	Patch(name string, patches []Proppatch) ([]Propstat, error)
-}
-
 // Proppatch describes a property update instruction as defined in RFC 4918.
 // See http://www.webdav.org/specs/rfc4918.html#METHOD_PROPPATCH
 type Proppatch struct {
@@ -140,43 +96,28 @@ type DeadPropsHolder interface {
 	Patch([]Proppatch) ([]Propstat, error)
 }
 
-// memPS implements an in-memory PropSystem. It supports all of the mandatory
-// live properties of RFC 4918.
-type memPS struct {
-	fs FileSystem
-	ls LockSystem
-}
-
-// NewMemPS returns a new in-memory PropSystem implementation.
-func NewMemPS(fs FileSystem, ls LockSystem) PropSystem {
-	return &memPS{
-		fs: fs,
-		ls: ls,
-	}
-}
-
 // liveProps contains all supported, protected DAV: properties.
 var liveProps = map[xml.Name]struct {
 	// findFn implements the propfind function of this property. If nil,
 	// it indicates a hidden property.
-	findFn func(*memPS, string, os.FileInfo) (string, error)
+	findFn func(FileSystem, LockSystem, string, os.FileInfo) (string, error)
 	// dir is true if the property applies to directories.
 	dir bool
 }{
 	xml.Name{Space: "DAV:", Local: "resourcetype"}: {
-		findFn: (*memPS).findResourceType,
+		findFn: findResourceType,
 		dir:    true,
 	},
 	xml.Name{Space: "DAV:", Local: "displayname"}: {
-		findFn: (*memPS).findDisplayName,
+		findFn: findDisplayName,
 		dir:    true,
 	},
 	xml.Name{Space: "DAV:", Local: "getcontentlength"}: {
-		findFn: (*memPS).findContentLength,
+		findFn: findContentLength,
 		dir:    true,
 	},
 	xml.Name{Space: "DAV:", Local: "getlastmodified"}: {
-		findFn: (*memPS).findLastModified,
+		findFn: findLastModified,
 		dir:    true,
 	},
 	xml.Name{Space: "DAV:", Local: "creationdate"}: {
@@ -188,15 +129,15 @@ var liveProps = map[xml.Name]struct {
 		dir:    true,
 	},
 	xml.Name{Space: "DAV:", Local: "getcontenttype"}: {
-		findFn: (*memPS).findContentType,
+		findFn: findContentType,
 		dir:    true,
 	},
 	xml.Name{Space: "DAV:", Local: "getetag"}: {
-		findFn: (*memPS).findETag,
-		// memPS implements ETag as the concatenated hex values of a file's
+		findFn: findETag,
+		// findETag implements ETag as the concatenated hex values of a file's
 		// modification time and size. This is not a reliable synchronization
-		// mechanism for directories, so we do not advertise getetag for
-		// DAV collections.
+		// mechanism for directories, so we do not advertise getetag for DAV
+		// collections.
 		dir: false,
 	},
 
@@ -205,8 +146,14 @@ var liveProps = map[xml.Name]struct {
 	xml.Name{Space: "DAV:", Local: "supportedlock"}: {},
 }
 
-func (ps *memPS) Find(name string, propnames []xml.Name) ([]Propstat, error) {
-	f, err := ps.fs.OpenFile(name, os.O_RDONLY, 0)
+// TODO(nigeltao) merge props and allprop?
+
+// Props returns the status of the properties named pnames for resource name.
+//
+// Each Propstat has a unique status and each property name will only be part
+// of one Propstat element.
+func props(fs FileSystem, ls LockSystem, name string, pnames []xml.Name) ([]Propstat, error) {
+	f, err := fs.OpenFile(name, os.O_RDONLY, 0)
 	if err != nil {
 		return nil, err
 	}
@@ -224,7 +171,7 @@ func (ps *memPS) Find(name string, propnames []xml.Name) ([]Propstat, error) {
 
 	pstatOK := Propstat{Status: http.StatusOK}
 	pstatNotFound := Propstat{Status: http.StatusNotFound}
-	for _, pn := range propnames {
+	for _, pn := range pnames {
 		// If this file has dead properties, check if they contain pn.
 		if dp, ok := deadProps[pn]; ok {
 			pstatOK.Props = append(pstatOK.Props, dp)
@@ -232,7 +179,7 @@ func (ps *memPS) Find(name string, propnames []xml.Name) ([]Propstat, error) {
 		}
 		// Otherwise, it must either be a live property or we don't know it.
 		if prop := liveProps[pn]; prop.findFn != nil && (prop.dir || !isDir) {
-			innerXML, err := prop.findFn(ps, name, fi)
+			innerXML, err := prop.findFn(fs, ls, name, fi)
 			if err != nil {
 				return nil, err
 			}
@@ -249,8 +196,9 @@ func (ps *memPS) Find(name string, propnames []xml.Name) ([]Propstat, error) {
 	return makePropstats(pstatOK, pstatNotFound), nil
 }
 
-func (ps *memPS) Propnames(name string) ([]xml.Name, error) {
-	f, err := ps.fs.OpenFile(name, os.O_RDONLY, 0)
+// Propnames returns the property names defined for resource name.
+func propnames(fs FileSystem, ls LockSystem, name string) ([]xml.Name, error) {
+	f, err := fs.OpenFile(name, os.O_RDONLY, 0)
 	if err != nil {
 		return nil, err
 	}
@@ -266,37 +214,47 @@ func (ps *memPS) Propnames(name string) ([]xml.Name, error) {
 		deadProps = dph.DeadProps()
 	}
 
-	propnames := make([]xml.Name, 0, len(liveProps)+len(deadProps))
+	pnames := make([]xml.Name, 0, len(liveProps)+len(deadProps))
 	for pn, prop := range liveProps {
 		if prop.findFn != nil && (prop.dir || !isDir) {
-			propnames = append(propnames, pn)
+			pnames = append(pnames, pn)
 		}
 	}
 	for pn := range deadProps {
-		propnames = append(propnames, pn)
+		pnames = append(pnames, pn)
 	}
-	return propnames, nil
+	return pnames, nil
 }
 
-func (ps *memPS) Allprop(name string, include []xml.Name) ([]Propstat, error) {
-	propnames, err := ps.Propnames(name)
+// Allprop returns the properties defined for resource name and the properties
+// named in include.
+//
+// Note that RFC 4918 defines 'allprop' to return the DAV: properties defined
+// within the RFC plus dead properties. Other live properties should only be
+// returned if they are named in 'include'.
+//
+// See http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND
+func allprop(fs FileSystem, ls LockSystem, name string, include []xml.Name) ([]Propstat, error) {
+	pnames, err := propnames(fs, ls, name)
 	if err != nil {
 		return nil, err
 	}
-	// Add names from include if they are not already covered in propnames.
+	// Add names from include if they are not already covered in pnames.
 	nameset := make(map[xml.Name]bool)
-	for _, pn := range propnames {
+	for _, pn := range pnames {
 		nameset[pn] = true
 	}
 	for _, pn := range include {
 		if !nameset[pn] {
-			propnames = append(propnames, pn)
+			pnames = append(pnames, pn)
 		}
 	}
-	return ps.Find(name, propnames)
+	return props(fs, ls, name, pnames)
 }
 
-func (ps *memPS) Patch(name string, patches []Proppatch) ([]Propstat, error) {
+// Patch patches the properties of resource name. The return values are
+// constrained in the same manner as DeadPropsHolder.Patch.
+func patch(fs FileSystem, ls LockSystem, name string, patches []Proppatch) ([]Propstat, error) {
 	conflict := false
 loop:
 	for _, patch := range patches {
@@ -327,7 +285,7 @@ loop:
 		return makePropstats(pstatForbidden, pstatFailedDep), nil
 	}
 
-	f, err := ps.fs.OpenFile(name, os.O_RDWR, 0)
+	f, err := fs.OpenFile(name, os.O_RDWR, 0)
 	if err != nil {
 		return nil, err
 	}
@@ -358,14 +316,14 @@ loop:
 	return []Propstat{pstat}, nil
 }
 
-func (ps *memPS) findResourceType(name string, fi os.FileInfo) (string, error) {
+func findResourceType(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
 	if fi.IsDir() {
 		return `<collection xmlns="DAV:"/>`, nil
 	}
 	return "", nil
 }
 
-func (ps *memPS) findDisplayName(name string, fi os.FileInfo) (string, error) {
+func findDisplayName(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
 	if slashClean(name) == "/" {
 		// Hide the real name of a possibly prefixed root directory.
 		return "", nil
@@ -373,16 +331,16 @@ func (ps *memPS) findDisplayName(name string, fi os.FileInfo) (string, error) {
 	return fi.Name(), nil
 }
 
-func (ps *memPS) findContentLength(name string, fi os.FileInfo) (string, error) {
+func findContentLength(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
 	return strconv.FormatInt(fi.Size(), 10), nil
 }
 
-func (ps *memPS) findLastModified(name string, fi os.FileInfo) (string, error) {
+func findLastModified(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
 	return fi.ModTime().Format(http.TimeFormat), nil
 }
 
-func (ps *memPS) findContentType(name string, fi os.FileInfo) (string, error) {
-	f, err := ps.fs.OpenFile(name, os.O_RDONLY, 0)
+func findContentType(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
+	f, err := fs.OpenFile(name, os.O_RDONLY, 0)
 	if err != nil {
 		return "", err
 	}
@@ -400,7 +358,7 @@ func (ps *memPS) findContentType(name string, fi os.FileInfo) (string, error) {
 	return ctype, err
 }
 
-func (ps *memPS) findETag(name string, fi os.FileInfo) (string, error) {
+func findETag(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
 	return detectETag(fi), nil
 }
 

+ 43 - 44
webdav/prop_test.go

@@ -43,9 +43,9 @@ func TestMemPS(t *testing.T) {
 	type propOp struct {
 		op            string
 		name          string
-		propnames     []xml.Name
+		pnames        []xml.Name
 		patches       []Proppatch
-		wantNames     []xml.Name
+		wantPnames    []xml.Name
 		wantPropstats []Propstat
 	}
 
@@ -60,7 +60,7 @@ func TestMemPS(t *testing.T) {
 		propOp: []propOp{{
 			op:   "propname",
 			name: "/dir",
-			wantNames: []xml.Name{
+			wantPnames: []xml.Name{
 				xml.Name{Space: "DAV:", Local: "resourcetype"},
 				xml.Name{Space: "DAV:", Local: "displayname"},
 				xml.Name{Space: "DAV:", Local: "getcontentlength"},
@@ -70,7 +70,7 @@ func TestMemPS(t *testing.T) {
 		}, {
 			op:   "propname",
 			name: "/file",
-			wantNames: []xml.Name{
+			wantPnames: []xml.Name{
 				xml.Name{Space: "DAV:", Local: "resourcetype"},
 				xml.Name{Space: "DAV:", Local: "displayname"},
 				xml.Name{Space: "DAV:", Local: "getcontentlength"},
@@ -132,7 +132,7 @@ func TestMemPS(t *testing.T) {
 		}, {
 			op:   "allprop",
 			name: "/file",
-			propnames: []xml.Name{
+			pnames: []xml.Name{
 				{"DAV:", "resourcetype"},
 				{"foo", "bar"},
 			},
@@ -167,9 +167,9 @@ func TestMemPS(t *testing.T) {
 		desc:    "propfind DAV:resourcetype",
 		buildfs: []string{"mkdir /dir", "touch /file"},
 		propOp: []propOp{{
-			op:        "propfind",
-			name:      "/dir",
-			propnames: []xml.Name{{"DAV:", "resourcetype"}},
+			op:     "propfind",
+			name:   "/dir",
+			pnames: []xml.Name{{"DAV:", "resourcetype"}},
 			wantPropstats: []Propstat{{
 				Status: http.StatusOK,
 				Props: []Property{{
@@ -178,9 +178,9 @@ func TestMemPS(t *testing.T) {
 				}},
 			}},
 		}, {
-			op:        "propfind",
-			name:      "/file",
-			propnames: []xml.Name{{"DAV:", "resourcetype"}},
+			op:     "propfind",
+			name:   "/file",
+			pnames: []xml.Name{{"DAV:", "resourcetype"}},
 			wantPropstats: []Propstat{{
 				Status: http.StatusOK,
 				Props: []Property{{
@@ -193,9 +193,9 @@ func TestMemPS(t *testing.T) {
 		desc:    "propfind unsupported DAV properties",
 		buildfs: []string{"mkdir /dir"},
 		propOp: []propOp{{
-			op:        "propfind",
-			name:      "/dir",
-			propnames: []xml.Name{{"DAV:", "getcontentlanguage"}},
+			op:     "propfind",
+			name:   "/dir",
+			pnames: []xml.Name{{"DAV:", "getcontentlanguage"}},
 			wantPropstats: []Propstat{{
 				Status: http.StatusNotFound,
 				Props: []Property{{
@@ -203,9 +203,9 @@ func TestMemPS(t *testing.T) {
 				}},
 			}},
 		}, {
-			op:        "propfind",
-			name:      "/dir",
-			propnames: []xml.Name{{"DAV:", "creationdate"}},
+			op:     "propfind",
+			name:   "/dir",
+			pnames: []xml.Name{{"DAV:", "creationdate"}},
 			wantPropstats: []Propstat{{
 				Status: http.StatusNotFound,
 				Props: []Property{{
@@ -217,9 +217,9 @@ func TestMemPS(t *testing.T) {
 		desc:    "propfind getetag for files but not for directories",
 		buildfs: []string{"mkdir /dir", "touch /file"},
 		propOp: []propOp{{
-			op:        "propfind",
-			name:      "/dir",
-			propnames: []xml.Name{{"DAV:", "getetag"}},
+			op:     "propfind",
+			name:   "/dir",
+			pnames: []xml.Name{{"DAV:", "getetag"}},
 			wantPropstats: []Propstat{{
 				Status: http.StatusNotFound,
 				Props: []Property{{
@@ -227,9 +227,9 @@ func TestMemPS(t *testing.T) {
 				}},
 			}},
 		}, {
-			op:        "propfind",
-			name:      "/file",
-			propnames: []xml.Name{{"DAV:", "getetag"}},
+			op:     "propfind",
+			name:   "/file",
+			pnames: []xml.Name{{"DAV:", "getetag"}},
 			wantPropstats: []Propstat{{
 				Status: http.StatusOK,
 				Props: []Property{{
@@ -291,9 +291,9 @@ func TestMemPS(t *testing.T) {
 				}},
 			}},
 		}, {
-			op:        "propfind",
-			name:      "/dir",
-			propnames: []xml.Name{{Space: "foo", Local: "bar"}},
+			op:     "propfind",
+			name:   "/dir",
+			pnames: []xml.Name{{Space: "foo", Local: "bar"}},
 			wantPropstats: []Propstat{{
 				Status: http.StatusOK,
 				Props: []Property{{
@@ -332,9 +332,9 @@ func TestMemPS(t *testing.T) {
 				}},
 			}},
 		}, {
-			op:        "propfind",
-			name:      "/dir",
-			propnames: []xml.Name{{Space: "foo", Local: "bar"}},
+			op:     "propfind",
+			name:   "/dir",
+			pnames: []xml.Name{{Space: "foo", Local: "bar"}},
 			wantPropstats: []Propstat{{
 				Status: http.StatusNotFound,
 				Props: []Property{{
@@ -368,7 +368,7 @@ func TestMemPS(t *testing.T) {
 		}, {
 			op:   "propfind",
 			name: "/dir",
-			propnames: []xml.Name{
+			pnames: []xml.Name{
 				{Space: "foo", Local: "bar"},
 				{Space: "spam", Local: "ham"},
 			},
@@ -400,7 +400,7 @@ func TestMemPS(t *testing.T) {
 		}, {
 			op:   "propfind",
 			name: "/dir",
-			propnames: []xml.Name{
+			pnames: []xml.Name{
 				{Space: "foo", Local: "bar"},
 				{Space: "spam", Local: "ham"},
 			},
@@ -438,7 +438,7 @@ func TestMemPS(t *testing.T) {
 		}, {
 			op:   "propname",
 			name: "/file",
-			wantNames: []xml.Name{
+			wantPnames: []xml.Name{
 				xml.Name{Space: "DAV:", Local: "resourcetype"},
 				xml.Name{Space: "DAV:", Local: "displayname"},
 				xml.Name{Space: "DAV:", Local: "getcontentlength"},
@@ -471,9 +471,9 @@ func TestMemPS(t *testing.T) {
 		desc:    "bad: propfind unknown property",
 		buildfs: []string{"mkdir /dir"},
 		propOp: []propOp{{
-			op:        "propfind",
-			name:      "/dir",
-			propnames: []xml.Name{{"foo:", "bar"}},
+			op:     "propfind",
+			name:   "/dir",
+			pnames: []xml.Name{{"foo:", "bar"}},
 			wantPropstats: []Propstat{{
 				Status: http.StatusNotFound,
 				Props: []Property{{
@@ -492,7 +492,6 @@ func TestMemPS(t *testing.T) {
 			fs = noDeadPropsFS{fs}
 		}
 		ls := NewMemLS()
-		ps := NewMemPS(fs, ls)
 		for _, op := range tc.propOp {
 			desc := fmt.Sprintf("%s: %s %s", tc.desc, op.op, op.name)
 			if err = calcProps(op.name, fs, op.wantPropstats); err != nil {
@@ -503,23 +502,23 @@ func TestMemPS(t *testing.T) {
 			var propstats []Propstat
 			switch op.op {
 			case "propname":
-				names, err := ps.Propnames(op.name)
+				pnames, err := propnames(fs, ls, op.name)
 				if err != nil {
 					t.Errorf("%s: got error %v, want nil", desc, err)
 					continue
 				}
-				sort.Sort(byXMLName(names))
-				sort.Sort(byXMLName(op.wantNames))
-				if !reflect.DeepEqual(names, op.wantNames) {
-					t.Errorf("%s: names\ngot  %q\nwant %q", desc, names, op.wantNames)
+				sort.Sort(byXMLName(pnames))
+				sort.Sort(byXMLName(op.wantPnames))
+				if !reflect.DeepEqual(pnames, op.wantPnames) {
+					t.Errorf("%s: pnames\ngot  %q\nwant %q", desc, pnames, op.wantPnames)
 				}
 				continue
 			case "allprop":
-				propstats, err = ps.Allprop(op.name, op.propnames)
+				propstats, err = allprop(fs, ls, op.name, op.pnames)
 			case "propfind":
-				propstats, err = ps.Find(op.name, op.propnames)
+				propstats, err = props(fs, ls, op.name, op.pnames)
 			case "proppatch":
-				propstats, err = ps.Patch(op.name, op.patches)
+				propstats, err = patch(fs, ls, op.name, op.patches)
 			default:
 				t.Fatalf("%s: %s not implemented", desc, op.op)
 			}

+ 7 - 14
webdav/webdav.go

@@ -5,8 +5,6 @@
 // Package webdav etc etc TODO.
 package webdav // import "golang.org/x/net/webdav"
 
-// TODO: ETag, properties.
-
 import (
 	"encoding/xml"
 	"errors"
@@ -45,8 +43,6 @@ type Handler struct {
 	FileSystem FileSystem
 	// LockSystem is the lock management system.
 	LockSystem LockSystem
-	// PropSystem is the property management system.
-	PropSystem PropSystem
 	// Logger is an optional error logger. If non-nil, it will be called
 	// for all HTTP requests.
 	Logger func(*http.Request, error)
@@ -58,8 +54,6 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		status, err = http.StatusInternalServerError, errNoFileSystem
 	} else if h.LockSystem == nil {
 		status, err = http.StatusInternalServerError, errNoLockSystem
-	} else if h.PropSystem == nil {
-		status, err = http.StatusInternalServerError, errNoPropSystem
 	} else {
 		switch r.Method {
 		case "OPTIONS":
@@ -209,7 +203,7 @@ func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (sta
 	if err != nil {
 		return http.StatusNotFound, err
 	}
-	pstats, err := h.PropSystem.Find(r.URL.Path, []xml.Name{
+	pstats, err := props(h.FileSystem, h.LockSystem, r.URL.Path, []xml.Name{
 		{Space: "DAV:", Local: "getetag"},
 		{Space: "DAV:", Local: "getcontenttype"},
 	})
@@ -264,7 +258,7 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int,
 	if closeErr != nil {
 		return http.StatusMethodNotAllowed, closeErr
 	}
-	pstats, err := h.PropSystem.Find(r.URL.Path, []xml.Name{
+	pstats, err := props(h.FileSystem, h.LockSystem, r.URL.Path, []xml.Name{
 		{Space: "DAV:", Local: "getetag"},
 	})
 	if err != nil {
@@ -502,19 +496,19 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status
 		}
 		var pstats []Propstat
 		if pf.Propname != nil {
-			propnames, err := h.PropSystem.Propnames(path)
+			pnames, err := propnames(h.FileSystem, h.LockSystem, path)
 			if err != nil {
 				return err
 			}
 			pstat := Propstat{Status: http.StatusOK}
-			for _, xmlname := range propnames {
+			for _, xmlname := range pnames {
 				pstat.Props = append(pstat.Props, Property{XMLName: xmlname})
 			}
 			pstats = append(pstats, pstat)
 		} else if pf.Allprop != nil {
-			pstats, err = h.PropSystem.Allprop(path, pf.Prop)
+			pstats, err = allprop(h.FileSystem, h.LockSystem, path, pf.Prop)
 		} else {
-			pstats, err = h.PropSystem.Find(path, pf.Prop)
+			pstats, err = props(h.FileSystem, h.LockSystem, path, pf.Prop)
 		}
 		if err != nil {
 			return err
@@ -550,7 +544,7 @@ func (h *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (statu
 	if err != nil {
 		return status, err
 	}
-	pstats, err := h.PropSystem.Patch(r.URL.Path, patches)
+	pstats, err := patch(h.FileSystem, h.LockSystem, r.URL.Path, patches)
 	if err != nil {
 		return http.StatusInternalServerError, err
 	}
@@ -671,7 +665,6 @@ var (
 	errInvalidTimeout          = errors.New("webdav: invalid timeout")
 	errNoFileSystem            = errors.New("webdav: no file system")
 	errNoLockSystem            = errors.New("webdav: no lock system")
-	errNoPropSystem            = errors.New("webdav: no property system")
 	errNotADirectory           = errors.New("webdav: not a directory")
 	errRecursionTooDeep        = errors.New("webdav: recursion too deep")
 	errUnsupportedLockInfo     = errors.New("webdav: unsupported lock info")