diff options
author | mpl <mathieu.lonjaret@gmail.com> | 2015-06-11 17:40:24 +0200 |
---|---|---|
committer | Nigel Tao <nigeltao@golang.org> | 2015-06-23 04:55:59 +0000 |
commit | 34ff4cd5e6de00702100a0ab3bb73de8de5ab35d (patch) | |
tree | c5965d44ea5fd747f037c597a36d2c0d39da2e8e | |
parent | 38f3db3860bb1812858610029b0d8188517d8b74 (diff) | |
download | net-34ff4cd5e6de00702100a0ab3bb73de8de5ab35d.tar.gz |
webdav: make it work for Mini-Redirector, emit namespace-prefixed XML.
The default webDAV client for windows explorer, Mini-Redirector,
apparently can not handle XML elements with a default namespace.
This change modifies the emitted XML so that elements are prefixed with
the D: namespace, defined as as "DAV:" in the multistatus tag.
Fixes golang/go#11177
Change-Id: Ib323ca312fa10bd5aa6e6c61d90812d066543bac
Reviewed-on: https://go-review.googlesource.com/10942
Reviewed-by: Nigel Tao <nigeltao@golang.org>
-rw-r--r-- | webdav/prop.go | 12 | ||||
-rw-r--r-- | webdav/prop_test.go | 44 | ||||
-rw-r--r-- | webdav/xml.go | 47 |
3 files changed, 60 insertions, 43 deletions
diff --git a/webdav/prop.go b/webdav/prop.go index 1cd068c..9431f5e 100644 --- a/webdav/prop.go +++ b/webdav/prop.go @@ -278,7 +278,7 @@ loop: if conflict { pstatForbidden := Propstat{ Status: http.StatusForbidden, - XMLError: `<error xmlns="DAV:"><cannot-modify-protected-property/></error>`, + XMLError: `<D:cannot-modify-protected-property xmlns:D="DAV:"/>`, } pstatFailedDep := Propstat{ Status: StatusFailedDependency, @@ -328,7 +328,7 @@ loop: func findResourceType(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) { if fi.IsDir() { - return `<collection xmlns="DAV:"/>`, nil + return `<D:collection xmlns:D="DAV:"/>`, nil } return "", nil } @@ -377,8 +377,8 @@ func findETag(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string func findSupportedLock(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) { return `` + - `<lockentry xmlns="DAV:">` + - `<lockscope><exclusive/></lockscope>` + - `<locktype><write/></locktype>` + - `</lockentry>`, nil + `<D:lockentry xmlns:D="DAV:">` + + `<D:lockscope><D:exclusive/></D:lockscope>` + + `<D:locktype><D:write/></D:locktype>` + + `</D:lockentry>`, nil } diff --git a/webdav/prop_test.go b/webdav/prop_test.go index f588d4f..8bf4aee 100644 --- a/webdav/prop_test.go +++ b/webdav/prop_test.go @@ -44,6 +44,15 @@ func TestMemPS(t *testing.T) { return nil } + const ( + lockEntry = `` + + `<D:lockentry xmlns:D="DAV:">` + + `<D:lockscope><D:exclusive/></D:lockscope>` + + `<D:locktype><D:write/></D:locktype>` + + `</D:lockentry>` + statForbiddenError = `<D:cannot-modify-protected-property xmlns:D="DAV:"/>` + ) + type propOp struct { op string name string @@ -95,7 +104,7 @@ func TestMemPS(t *testing.T) { Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "resourcetype"}, - InnerXML: []byte(`<collection xmlns="DAV:"/>`), + InnerXML: []byte(`<D:collection xmlns:D="DAV:"/>`), }, { XMLName: xml.Name{Space: "DAV:", Local: "displayname"}, InnerXML: []byte("dir"), @@ -109,13 +118,8 @@ func TestMemPS(t *testing.T) { XMLName: xml.Name{Space: "DAV:", Local: "getcontenttype"}, InnerXML: []byte("text/plain; charset=utf-8"), }, { - XMLName: xml.Name{Space: "DAV:", Local: "supportedlock"}, - InnerXML: []byte(`` + - `<lockentry xmlns="DAV:">` + - `<lockscope><exclusive/></lockscope>` + - `<locktype><write/></locktype>` + - `</lockentry>`, - ), + XMLName: xml.Name{Space: "DAV:", Local: "supportedlock"}, + InnerXML: []byte(lockEntry), }}, }}, }, { @@ -142,13 +146,8 @@ func TestMemPS(t *testing.T) { XMLName: xml.Name{Space: "DAV:", Local: "getetag"}, InnerXML: nil, // Calculated during test. }, { - XMLName: xml.Name{Space: "DAV:", Local: "supportedlock"}, - InnerXML: []byte(`` + - `<lockentry xmlns="DAV:">` + - `<lockscope><exclusive/></lockscope>` + - `<locktype><write/></locktype>` + - `</lockentry>`, - ), + XMLName: xml.Name{Space: "DAV:", Local: "supportedlock"}, + InnerXML: []byte(lockEntry), }}, }}, }, { @@ -179,13 +178,8 @@ func TestMemPS(t *testing.T) { XMLName: xml.Name{Space: "DAV:", Local: "getetag"}, InnerXML: nil, // Calculated during test. }, { - XMLName: xml.Name{Space: "DAV:", Local: "supportedlock"}, - InnerXML: []byte(`` + - `<lockentry xmlns="DAV:">` + - `<lockscope><exclusive/></lockscope>` + - `<locktype><write/></locktype>` + - `</lockentry>`, - ), + XMLName: xml.Name{Space: "DAV:", Local: "supportedlock"}, + InnerXML: []byte(lockEntry), }}}, { Status: http.StatusNotFound, Props: []Property{{ @@ -204,7 +198,7 @@ func TestMemPS(t *testing.T) { Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "resourcetype"}, - InnerXML: []byte(`<collection xmlns="DAV:"/>`), + InnerXML: []byte(`<D:collection xmlns:D="DAV:"/>`), }}, }}, }, { @@ -296,7 +290,7 @@ func TestMemPS(t *testing.T) { }}, wantPropstats: []Propstat{{ Status: http.StatusForbidden, - XMLError: `<error xmlns="DAV:"><cannot-modify-protected-property/></error>`, + XMLError: statForbiddenError, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "getetag"}, }}, @@ -351,7 +345,7 @@ func TestMemPS(t *testing.T) { }}, wantPropstats: []Propstat{{ Status: http.StatusForbidden, - XMLError: `<error xmlns="DAV:"><cannot-modify-protected-property/></error>`, + XMLError: statForbiddenError, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "displayname"}, }}, diff --git a/webdav/xml.go b/webdav/xml.go index 71dd921..79e5d07 100644 --- a/webdav/xml.go +++ b/webdav/xml.go @@ -206,32 +206,55 @@ type Property struct { } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_error +// See multistatusWriter for the "D:" namespace prefix. type xmlError struct { - XMLName xml.Name `xml:"DAV: error"` + XMLName xml.Name `xml:"D:error"` InnerXML []byte `xml:",innerxml"` } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_propstat +// See multistatusWriter for the "D:" namespace prefix. type propstat struct { - Prop []Property `xml:"DAV: prop>_ignored_"` - Status string `xml:"DAV: status"` - Error *xmlError `xml:"DAV: error"` - ResponseDescription string `xml:"DAV: responsedescription,omitempty"` + Prop []Property `xml:"D:prop>_ignored_"` + Status string `xml:"D:status"` + Error *xmlError `xml:"D:error"` + ResponseDescription string `xml:"D:responsedescription,omitempty"` +} + +// MarshalXML prepends the "D:" namespace prefix on properties in the DAV: namespace +// before encoding. See multistatusWriter. +func (ps propstat) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + for k, prop := range ps.Prop { + if prop.XMLName.Space == "DAV:" { + prop.XMLName = xml.Name{Space: "", Local: "D:" + prop.XMLName.Local} + ps.Prop[k] = prop + } + } + // Distinct type to avoid infinite recursion of MarshalXML. + type newpropstat propstat + return e.EncodeElement(newpropstat(ps), start) } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_response +// See multistatusWriter for the "D:" namespace prefix. type response struct { - XMLName xml.Name `xml:"DAV: response"` - Href []string `xml:"DAV: href"` - Propstat []propstat `xml:"DAV: propstat"` - Status string `xml:"DAV: status,omitempty"` - Error *xmlError `xml:"DAV: error"` - ResponseDescription string `xml:"DAV: responsedescription,omitempty"` + XMLName xml.Name `xml:"D:response"` + Href []string `xml:"D:href"` + Propstat []propstat `xml:"D:propstat"` + Status string `xml:"D:status,omitempty"` + Error *xmlError `xml:"D:error"` + ResponseDescription string `xml:"D:responsedescription,omitempty"` } // MultistatusWriter marshals one or more Responses into a XML // multistatus response. // See http://www.webdav.org/specs/rfc4918.html#ELEMENT_multistatus +// TODO(rsto, mpl): As a workaround, the "D:" namespace prefix, defined as +// "DAV:" on this element, is prepended on the nested response, as well as on all +// its nested elements. All property names in the DAV: namespace are prefixed as +// 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 { // ResponseDescription contains the optional responsedescription // of the multistatus XML element. Only the latest content before @@ -291,7 +314,7 @@ func (w *multistatusWriter) writeHeader() error { Local: "multistatus", }, Attr: []xml.Attr{{ - Name: xml.Name{Local: "xmlns"}, + Name: xml.Name{Space: "xmlns", Local: "D"}, Value: "DAV:", }}, }) |