aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormpl <mathieu.lonjaret@gmail.com>2015-06-11 17:40:24 +0200
committerNigel Tao <nigeltao@golang.org>2015-06-23 04:55:59 +0000
commit34ff4cd5e6de00702100a0ab3bb73de8de5ab35d (patch)
treec5965d44ea5fd747f037c597a36d2c0d39da2e8e
parent38f3db3860bb1812858610029b0d8188517d8b74 (diff)
downloadnet-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.go12
-rw-r--r--webdav/prop_test.go44
-rw-r--r--webdav/xml.go47
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:",
}},
})