Keep resolve the xml.

This commit is contained in:
zicla 2019-04-18 03:40:57 +08:00
parent ba7b632046
commit 4611735283
6 changed files with 176 additions and 207 deletions

View File

@ -394,14 +394,14 @@ func (this *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStat
if err != nil { if err != nil {
return http.StatusBadRequest, err return http.StatusBadRequest, err
} }
li, status, err := readLockInfo(r.Body) li, status, err := ReadLockInfo(r.Body)
if err != nil { if err != nil {
return status, err return status, err
} }
ctx := r.Context() ctx := r.Context()
token, ld, now, created := "", LockDetails{}, time.Now(), false token, ld, now, created := "", LockDetails{}, time.Now(), false
if li == (lockInfo{}) { if li == (LockInfo{}) {
// An empty lockInfo means to refresh the lock. // An empty lockInfo means to refresh the lock.
ih, ok := parseIfHeader(r.Header.Get("If")) ih, ok := parseIfHeader(r.Header.Get("If"))
if !ok { if !ok {
@ -479,7 +479,7 @@ func (this *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStat
// and Handler.ServeHTTP would otherwise write "Created". // and Handler.ServeHTTP would otherwise write "Created".
w.WriteHeader(http.StatusCreated) w.WriteHeader(http.StatusCreated)
} }
writeLockInfo(w, token, ld) WriteLockInfo(w, token, ld)
return 0, nil return 0, nil
} }
@ -527,12 +527,12 @@ func (this *Handler) handlePropfind(writer http.ResponseWriter, request *http.Re
} }
} }
//读取出request希望获取的文件属性。 //读取出request希望获取的文件属性。
pf, status, err := readPropfind(request.Body) pf, status, err := ReadPropfind(request.Body)
if err != nil { if err != nil {
return status, err return status, err
} }
multiStatusWriter := multistatusWriter{w: writer} multiStatusWriter := MultiStatusWriter{Writer: writer}
walkFn := func(reqPath string, info os.FileInfo, err error) error { walkFn := func(reqPath string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
@ -566,7 +566,7 @@ func (this *Handler) handlePropfind(writer http.ResponseWriter, request *http.Re
} }
propstatResponse := makePropstatResponse(href, propstats) propstatResponse := makePropstatResponse(href, propstats)
return multiStatusWriter.write(propstatResponse) return multiStatusWriter.Write(propstatResponse)
} }
walkErr := walkFS(ctx, this.FileSystem, depth, reqPath, fileInfo, walkFn) walkErr := walkFS(ctx, this.FileSystem, depth, reqPath, fileInfo, walkFn)
@ -599,7 +599,7 @@ func (this *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (st
} }
return http.StatusMethodNotAllowed, err return http.StatusMethodNotAllowed, err
} }
patches, status, err := readProppatch(r.Body) patches, status, err := ReadProppatch(r.Body)
if err != nil { if err != nil {
return status, err return status, err
} }
@ -607,8 +607,8 @@ func (this *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (st
if err != nil { if err != nil {
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
mw := multistatusWriter{w: w} mw := MultiStatusWriter{Writer: w}
writeErr := mw.write(makePropstatResponse(r.URL.Path, pstats)) writeErr := mw.Write(makePropstatResponse(r.URL.Path, pstats))
closeErr := mw.close() closeErr := mw.close()
if writeErr != nil { if writeErr != nil {
return http.StatusInternalServerError, writeErr return http.StatusInternalServerError, writeErr
@ -619,17 +619,17 @@ func (this *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (st
return 0, nil return 0, nil
} }
func makePropstatResponse(href string, pstats []Propstat) *response { func makePropstatResponse(href string, pstats []Propstat) *Response {
resp := response{ resp := Response{
Href: []string{(&url.URL{Path: href}).EscapedPath()}, Href: []string{(&url.URL{Path: href}).EscapedPath()},
Propstat: make([]propstat, 0, len(pstats)), Propstat: make([]SubPropstat, 0, len(pstats)),
} }
for _, p := range pstats { for _, p := range pstats {
var xmlErr *xmlError var xmlErr *XmlError
if p.XMLError != "" { if p.XMLError != "" {
xmlErr = &xmlError{InnerXML: []byte(p.XMLError)} xmlErr = &XmlError{InnerXML: []byte(p.XMLError)}
} }
resp.Propstat = append(resp.Propstat, propstat{ resp.Propstat = append(resp.Propstat, SubPropstat{
Status: fmt.Sprintf("HTTP/1.1 %d %s", p.Status, StatusText(p.Status)), Status: fmt.Sprintf("HTTP/1.1 %d %s", p.Status, StatusText(p.Status)),
Prop: p.Props, Prop: p.Props,
ResponseDescription: p.ResponseDescription, ResponseDescription: p.ResponseDescription,

View File

@ -36,53 +36,53 @@ import (
) )
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_lockinfo // http://www.webdav.org/specs/rfc4918.html#ELEMENT_lockinfo
type lockInfo struct { type LockInfo struct {
XMLName ixml.Name `xml:"lockinfo"` XMLName ixml.Name `xml:"lockinfo"`
Exclusive *struct{} `xml:"lockscope>exclusive"` Exclusive *struct{} `xml:"lockscope>exclusive"`
Shared *struct{} `xml:"lockscope>shared"` Shared *struct{} `xml:"lockscope>shared"`
Write *struct{} `xml:"locktype>write"` Write *struct{} `xml:"locktype>write"`
Owner owner `xml:"owner"` Owner Owner `xml:"owner"`
} }
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_owner // http://www.webdav.org/specs/rfc4918.html#ELEMENT_owner
type owner struct { type Owner struct {
InnerXML string `xml:",innerxml"` InnerXML string `xml:",innerxml"`
} }
func readLockInfo(r io.Reader) (li lockInfo, status int, err error) { func ReadLockInfo(r io.Reader) (li LockInfo, status int, err error) {
c := &countingReader{r: r} c := &CountingReader{r: r}
if err = ixml.NewDecoder(c).Decode(&li); err != nil { if err = ixml.NewDecoder(c).Decode(&li); err != nil {
if err == io.EOF { if err == io.EOF {
if c.n == 0 { if c.n == 0 {
// An empty body means to refresh the lock. // An empty body means to refresh the lock.
// http://www.webdav.org/specs/rfc4918.html#refreshing-locks // http://www.webdav.org/specs/rfc4918.html#refreshing-locks
return lockInfo{}, 0, nil return LockInfo{}, 0, nil
} }
err = errInvalidLockInfo err = errInvalidLockInfo
} }
return lockInfo{}, http.StatusBadRequest, err return LockInfo{}, http.StatusBadRequest, err
} }
// We only support exclusive (non-shared) write locks. In practice, these are // We only support exclusive (non-shared) write locks. In practice, these are
// the only types of locks that seem to matter. // the only types of locks that seem to matter.
if li.Exclusive == nil || li.Shared != nil || li.Write == nil { if li.Exclusive == nil || li.Shared != nil || li.Write == nil {
return lockInfo{}, http.StatusNotImplemented, errUnsupportedLockInfo return LockInfo{}, http.StatusNotImplemented, errUnsupportedLockInfo
} }
return li, 0, nil return li, 0, nil
} }
//这是一个带字节计数器的Reader可以知道总共读取了多少个字节。 //这是一个带字节计数器的Reader可以知道总共读取了多少个字节。
type countingReader struct { type CountingReader struct {
n int n int
r io.Reader r io.Reader
} }
func (c *countingReader) Read(p []byte) (int, error) { func (c *CountingReader) Read(p []byte) (int, error) {
n, err := c.r.Read(p) n, err := c.r.Read(p)
c.n += n c.n += n
return n, err return n, err
} }
func writeLockInfo(w io.Writer, token string, ld LockDetails) (int, error) { func WriteLockInfo(w io.Writer, token string, ld LockDetails) (int, error) {
depth := "infinity" depth := "infinity"
if ld.ZeroDepth { if ld.ZeroDepth {
depth = "0" depth = "0"
@ -135,13 +135,13 @@ func next(d *ixml.Decoder) (ixml.Token, error) {
} }
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_prop (for propfind) // http://www.webdav.org/specs/rfc4918.html#ELEMENT_prop (for propfind)
type propfindProps []xml.Name type PropfindProps []xml.Name
// UnmarshalXML appends the property names enclosed within start to pn. // UnmarshalXML appends the property names enclosed within start to pn.
// //
// It returns an error if start does not contain any properties or if // It returns an error if start does not contain any properties or if
// properties contain values. Character data between properties is ignored. // properties contain values. Character data between properties is ignored.
func (pn *propfindProps) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement) error { func (pn *PropfindProps) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement) error {
for { for {
t, err := next(d) t, err := next(d)
if err != nil { if err != nil {
@ -168,40 +168,40 @@ func (pn *propfindProps) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement)
} }
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_propfind // http://www.webdav.org/specs/rfc4918.html#ELEMENT_propfind
type propfind struct { type Propfind struct {
XMLName ixml.Name `xml:"DAV: propfind"` XMLName ixml.Name `xml:"DAV: propfind"`
Allprop *struct{} `xml:"DAV: allprop"` Allprop *struct{} `xml:"DAV: allprop"`
Propname *struct{} `xml:"DAV: propname"` Propname *struct{} `xml:"DAV: propname"`
Prop propfindProps `xml:"DAV: prop"` Prop PropfindProps `xml:"DAV: prop"`
Include propfindProps `xml:"DAV: include"` Include PropfindProps `xml:"DAV: include"`
} }
//从request中读出需要的属性。比如getcontentlength 大小 creationdate 创建时间 //从request中读出需要的属性。比如getcontentlength 大小 creationdate 创建时间
func readPropfind(r io.Reader) (pf propfind, status int, err error) { func ReadPropfind(r io.Reader) (pf Propfind, status int, err error) {
c := countingReader{r: r} c := CountingReader{r: r}
if err = ixml.NewDecoder(&c).Decode(&pf); err != nil { if err = ixml.NewDecoder(&c).Decode(&pf); err != nil {
if err == io.EOF { if err == io.EOF {
if c.n == 0 { if c.n == 0 {
// An empty body means to propfind allprop. // An empty body means to propfind allprop.
// http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND // http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND
return propfind{Allprop: new(struct{})}, 0, nil return Propfind{Allprop: new(struct{})}, 0, nil
} }
err = errInvalidPropfind err = errInvalidPropfind
} }
return propfind{}, http.StatusBadRequest, err return Propfind{}, http.StatusBadRequest, err
} }
if pf.Allprop == nil && pf.Include != nil { if pf.Allprop == nil && pf.Include != nil {
return propfind{}, http.StatusBadRequest, errInvalidPropfind return Propfind{}, http.StatusBadRequest, errInvalidPropfind
} }
if pf.Allprop != nil && (pf.Prop != nil || pf.Propname != nil) { if pf.Allprop != nil && (pf.Prop != nil || pf.Propname != nil) {
return propfind{}, http.StatusBadRequest, errInvalidPropfind return Propfind{}, http.StatusBadRequest, errInvalidPropfind
} }
if pf.Prop != nil && pf.Propname != nil { if pf.Prop != nil && pf.Propname != nil {
return propfind{}, http.StatusBadRequest, errInvalidPropfind return Propfind{}, http.StatusBadRequest, errInvalidPropfind
} }
if pf.Propname == nil && pf.Allprop == nil && pf.Prop == nil { if pf.Propname == nil && pf.Allprop == nil && pf.Prop == nil {
return propfind{}, http.StatusBadRequest, errInvalidPropfind return Propfind{}, http.StatusBadRequest, errInvalidPropfind
} }
return pf, 0, nil return pf, 0, nil
} }
@ -228,49 +228,49 @@ type Property struct {
// ixmlProperty is the same as the Property type except it holds an ixml.Name // ixmlProperty is the same as the Property type except it holds an ixml.Name
// instead of an xml.Name. // instead of an xml.Name.
type ixmlProperty struct { type IxmlProperty struct {
XMLName ixml.Name XMLName ixml.Name
Lang string `xml:"xml:lang,attr,omitempty"` Lang string `xml:"xml:lang,attr,omitempty"`
InnerXML []byte `xml:",innerxml"` InnerXML []byte `xml:",innerxml"`
} }
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_error // http://www.webdav.org/specs/rfc4918.html#ELEMENT_error
// See multistatusWriter for the "D:" namespace prefix. // See MultiStatusWriter for the "D:" namespace prefix.
type xmlError struct { type XmlError struct {
XMLName ixml.Name `xml:"D:error"` XMLName ixml.Name `xml:"D:error"`
InnerXML []byte `xml:",innerxml"` InnerXML []byte `xml:",innerxml"`
} }
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_propstat // http://www.webdav.org/specs/rfc4918.html#ELEMENT_propstat
// See multistatusWriter for the "D:" namespace prefix. // See MultiStatusWriter for the "D:" namespace prefix.
type propstat struct { type SubPropstat struct {
Prop []Property `xml:"D:prop>_ignored_"` Prop []Property `xml:"D:prop>_ignored_"`
Status string `xml:"D:status"` Status string `xml:"D:status"`
Error *xmlError `xml:"D:error"` Error *XmlError `xml:"D:error"`
ResponseDescription string `xml:"D:responsedescription,omitempty"` ResponseDescription string `xml:"D:responsedescription,omitempty"`
} }
// ixmlPropstat is the same as the propstat type except it holds an ixml.Name // ixmlPropstat is the same as the propstat type except it holds an ixml.Name
// instead of an xml.Name. // instead of an xml.Name.
type ixmlPropstat struct { type IxmlPropstat struct {
Prop []ixmlProperty `xml:"D:prop>_ignored_"` Prop []IxmlProperty `xml:"D:prop>_ignored_"`
Status string `xml:"D:status"` Status string `xml:"D:status"`
Error *xmlError `xml:"D:error"` Error *XmlError `xml:"D:error"`
ResponseDescription string `xml:"D:responsedescription,omitempty"` ResponseDescription string `xml:"D:responsedescription,omitempty"`
} }
// MarshalXML prepends the "D:" namespace prefix on properties in the DAV: namespace // MarshalXML prepends the "D:" namespace prefix on properties in the DAV: namespace
// before encoding. See multistatusWriter. // before encoding. See MultiStatusWriter.
func (ps propstat) MarshalXML(e *ixml.Encoder, start ixml.StartElement) error { func (ps SubPropstat) MarshalXML(e *ixml.Encoder, start ixml.StartElement) error {
// Convert from a propstat to an ixmlPropstat. // Convert from a propstat to an ixmlPropstat.
ixmlPs := ixmlPropstat{ ixmlPs := IxmlPropstat{
Prop: make([]ixmlProperty, len(ps.Prop)), Prop: make([]IxmlProperty, len(ps.Prop)),
Status: ps.Status, Status: ps.Status,
Error: ps.Error, Error: ps.Error,
ResponseDescription: ps.ResponseDescription, ResponseDescription: ps.ResponseDescription,
} }
for k, prop := range ps.Prop { for k, prop := range ps.Prop {
ixmlPs.Prop[k] = ixmlProperty{ ixmlPs.Prop[k] = IxmlProperty{
XMLName: ixml.Name(prop.XMLName), XMLName: ixml.Name(prop.XMLName),
Lang: prop.Lang, Lang: prop.Lang,
InnerXML: prop.InnerXML, InnerXML: prop.InnerXML,
@ -284,19 +284,19 @@ func (ps propstat) MarshalXML(e *ixml.Encoder, start ixml.StartElement) error {
} }
} }
// Distinct type to avoid infinite recursion of MarshalXML. // Distinct type to avoid infinite recursion of MarshalXML.
type newpropstat ixmlPropstat type newpropstat IxmlPropstat
return e.EncodeElement(newpropstat(ixmlPs), start) return e.EncodeElement(newpropstat(ixmlPs), start)
} }
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_response // http://www.webdav.org/specs/rfc4918.html#ELEMENT_response
// See multistatusWriter for the "D:" namespace prefix. // See MultiStatusWriter for the "D:" namespace prefix.
type response struct { type Response struct {
XMLName ixml.Name `xml:"D:response"` XMLName ixml.Name `xml:"D:response"`
Href []string `xml:"D:href"` Href []string `xml:"D:href"`
Propstat []propstat `xml:"D:propstat"` Propstat []SubPropstat `xml:"D:propstat"`
Status string `xml:"D:status,omitempty"` Status string `xml:"D:status,omitempty"`
Error *xmlError `xml:"D:error"` Error *XmlError `xml:"D:error"`
ResponseDescription string `xml:"D:responsedescription,omitempty"` ResponseDescription string `xml:"D:responsedescription,omitempty"`
} }
// MultistatusWriter marshals one or more Responses into a XML // MultistatusWriter marshals one or more Responses into a XML
@ -308,15 +308,15 @@ type response struct {
// well. This is because some versions of Mini-Redirector (on windows 7) ignore // 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 // 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 // should be possible after golang.org/cl/11074. See https://golang.org/issue/11177
type multistatusWriter struct { type MultiStatusWriter struct {
// ResponseDescription contains the optional responsedescription // ResponseDescription contains the optional responsedescription
// of the multistatus XML element. Only the latest content before // of the multistatus XML element. Only the latest content before
// close will be emitted. Empty response descriptions are not // close will be emitted. Empty response descriptions are not
// written. // written.
responseDescription string ResponseDescription string
w http.ResponseWriter Writer http.ResponseWriter
enc *ixml.Encoder Encoder *ixml.Encoder
} }
// Write validates and emits a DAV response as part of a multistatus response // Write validates and emits a DAV response as part of a multistatus response
@ -327,7 +327,7 @@ type multistatusWriter struct {
// first, valid response to be written, Write prepends the XML representation // first, valid response to be written, Write prepends the XML representation
// of r with a multistatus tag. Callers must call close after the last response // of r with a multistatus tag. Callers must call close after the last response
// has been written. // has been written.
func (this *multistatusWriter) write(r *response) error { func (this *MultiStatusWriter) Write(r *Response) error {
switch len(r.Href) { switch len(r.Href) {
case 0: case 0:
return errInvalidResponse return errInvalidResponse
@ -344,24 +344,24 @@ func (this *multistatusWriter) write(r *response) error {
if err != nil { if err != nil {
return err return err
} }
return this.enc.Encode(r) return this.Encoder.Encode(r)
} }
// writeHeader writes a XML multistatus start element on w's underlying // writeHeader writes a XML multistatus start element on w's underlying
// http.ResponseWriter and returns the result of the write operation. // http.ResponseWriter and returns the result of the write operation.
// After the first write attempt, writeHeader becomes a no-op. // After the first write attempt, writeHeader becomes a no-op.
func (this *multistatusWriter) writeHeader() error { func (this *MultiStatusWriter) writeHeader() error {
if this.enc != nil { if this.Encoder != nil {
return nil return nil
} }
this.w.Header().Add("Content-Type", "text/xml; charset=utf-8") this.Writer.Header().Add("Content-Type", "text/xml; charset=utf-8")
this.w.WriteHeader(StatusMulti) this.Writer.WriteHeader(StatusMulti)
_, err := fmt.Fprintf(this.w, `<?xml version="1.0" encoding="UTF-8"?>`) _, err := fmt.Fprintf(this.Writer, `<?xml version="1.0" encoding="UTF-8"?>`)
if err != nil { if err != nil {
return err return err
} }
this.enc = ixml.NewEncoder(this.w) this.Encoder = ixml.NewEncoder(this.Writer)
return this.enc.EncodeToken(ixml.StartElement{ return this.Encoder.EncodeToken(ixml.StartElement{
Name: ixml.Name{ Name: ixml.Name{
Space: "DAV:", Space: "DAV:",
Local: "multistatus", Local: "multistatus",
@ -375,18 +375,18 @@ func (this *multistatusWriter) writeHeader() error {
// Close completes the marshalling of the multistatus response. It returns // Close completes the marshalling of the multistatus response. It returns
// an error if the multistatus response could not be completed. If both the // an error if the multistatus response could not be completed. If both the
// return value and field enc of w are nil, then no multistatus response has // return value and field Encoder of w are nil, then no multistatus response has
// been written. // been written.
func (this *multistatusWriter) close() error { func (this *MultiStatusWriter) close() error {
if this.enc == nil { if this.Encoder == nil {
return nil return nil
} }
var end []ixml.Token var end []ixml.Token
if this.responseDescription != "" { if this.ResponseDescription != "" {
name := ixml.Name{Space: "DAV:", Local: "responsedescription"} name := ixml.Name{Space: "DAV:", Local: "responsedescription"}
end = append(end, end = append(end,
ixml.StartElement{Name: name}, ixml.StartElement{Name: name},
ixml.CharData(this.responseDescription), ixml.CharData(this.ResponseDescription),
ixml.EndElement{Name: name}, ixml.EndElement{Name: name},
) )
} }
@ -394,12 +394,12 @@ func (this *multistatusWriter) close() error {
Name: ixml.Name{Space: "DAV:", Local: "multistatus"}, Name: ixml.Name{Space: "DAV:", Local: "multistatus"},
}) })
for _, t := range end { for _, t := range end {
err := this.enc.EncodeToken(t) err := this.Encoder.EncodeToken(t)
if err != nil { if err != nil {
return err return err
} }
} }
return this.enc.Flush() return this.Encoder.Flush()
} }
var xmlLangName = ixml.Name{Space: "http://www.w3.org/XML/1998/namespace", Local: "lang"} var xmlLangName = ixml.Name{Space: "http://www.w3.org/XML/1998/namespace", Local: "lang"}
@ -413,9 +413,9 @@ func xmlLang(s ixml.StartElement, d string) string {
return d return d
} }
type xmlValue []byte type XmlValue []byte
func (v *xmlValue) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement) error { func (v *XmlValue) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement) error {
// The XML value of a property can be arbitrary, mixed-content XML. // The XML value of a property can be arbitrary, mixed-content XML.
// To make sure that the unmarshalled value contains all required // To make sure that the unmarshalled value contains all required
// namespaces, we encode all the property value XML tokens into a // namespaces, we encode all the property value XML tokens into a
@ -443,7 +443,7 @@ func (v *xmlValue) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement) error
} }
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_prop (for proppatch) // http://www.webdav.org/specs/rfc4918.html#ELEMENT_prop (for proppatch)
type proppatchProps []Property type ProppatchProps []Property
// UnmarshalXML appends the property names and values enclosed within start // UnmarshalXML appends the property names and values enclosed within start
// to ps. // to ps.
@ -453,7 +453,7 @@ type proppatchProps []Property
// //
// UnmarshalXML returns an error if start does not contain any properties or if // UnmarshalXML returns an error if start does not contain any properties or if
// property values contain syntactically incorrect XML. // property values contain syntactically incorrect XML.
func (ps *proppatchProps) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement) error { func (ps *ProppatchProps) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement) error {
lang := xmlLang(start, "") lang := xmlLang(start, "")
for { for {
t, err := next(d) t, err := next(d)
@ -471,7 +471,7 @@ func (ps *proppatchProps) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement)
XMLName: xml.Name(t.(ixml.StartElement).Name), XMLName: xml.Name(t.(ixml.StartElement).Name),
Lang: xmlLang(t.(ixml.StartElement), lang), Lang: xmlLang(t.(ixml.StartElement), lang),
} }
err = d.DecodeElement(((*xmlValue)(&p.InnerXML)), &elem) err = d.DecodeElement(((*XmlValue)(&p.InnerXML)), &elem)
if err != nil { if err != nil {
return err return err
} }
@ -482,21 +482,21 @@ func (ps *proppatchProps) UnmarshalXML(d *ixml.Decoder, start ixml.StartElement)
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_set // http://www.webdav.org/specs/rfc4918.html#ELEMENT_set
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_remove // http://www.webdav.org/specs/rfc4918.html#ELEMENT_remove
type setRemove struct { type SetRemove struct {
XMLName ixml.Name XMLName ixml.Name
Lang string `xml:"xml:lang,attr,omitempty"` Lang string `xml:"xml:lang,attr,omitempty"`
Prop proppatchProps `xml:"DAV: prop"` Prop ProppatchProps `xml:"DAV: prop"`
} }
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_propertyupdate // http://www.webdav.org/specs/rfc4918.html#ELEMENT_propertyupdate
type propertyupdate struct { type PropertyUpdate struct {
XMLName ixml.Name `xml:"DAV: propertyupdate"` XMLName ixml.Name `xml:"DAV: propertyupdate"`
Lang string `xml:"xml:lang,attr,omitempty"` Lang string `xml:"xml:lang,attr,omitempty"`
SetRemove []setRemove `xml:",any"` SetRemove []SetRemove `xml:",any"`
} }
func readProppatch(r io.Reader) (patches []Proppatch, status int, err error) { func ReadProppatch(r io.Reader) (patches []Proppatch, status int, err error) {
var pu propertyupdate var pu PropertyUpdate
if err = ixml.NewDecoder(r).Decode(&pu); err != nil { if err = ixml.NewDecoder(r).Decode(&pu); err != nil {
return nil, http.StatusBadRequest, err return nil, http.StatusBadRequest, err
} }

View File

@ -25,12 +25,12 @@ func TestReadLockInfo(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string
input string input string
wantLI lockInfo wantLI LockInfo
wantStatus int wantStatus int
}{{ }{{
"bad: junk", "bad: junk",
"xxx", "xxx",
lockInfo{}, LockInfo{},
http.StatusBadRequest, http.StatusBadRequest,
}, { }, {
"bad: invalid owner XML", "bad: invalid owner XML",
@ -42,7 +42,7 @@ func TestReadLockInfo(t *testing.T) {
" <D:href> no end tag \n" + " <D:href> no end tag \n" +
" </D:owner>\n" + " </D:owner>\n" +
"</D:lockinfo>", "</D:lockinfo>",
lockInfo{}, LockInfo{},
http.StatusBadRequest, http.StatusBadRequest,
}, { }, {
"bad: invalid UTF-8", "bad: invalid UTF-8",
@ -54,7 +54,7 @@ func TestReadLockInfo(t *testing.T) {
" <D:href> \xff </D:href>\n" + " <D:href> \xff </D:href>\n" +
" </D:owner>\n" + " </D:owner>\n" +
"</D:lockinfo>", "</D:lockinfo>",
lockInfo{}, LockInfo{},
http.StatusBadRequest, http.StatusBadRequest,
}, { }, {
"bad: unfinished XML #1", "bad: unfinished XML #1",
@ -62,7 +62,7 @@ func TestReadLockInfo(t *testing.T) {
"<D:lockinfo xmlns:D='DAV:'>\n" + "<D:lockinfo xmlns:D='DAV:'>\n" +
" <D:lockscope><D:exclusive/></D:lockscope>\n" + " <D:lockscope><D:exclusive/></D:lockscope>\n" +
" <D:locktype><D:write/></D:locktype>\n", " <D:locktype><D:write/></D:locktype>\n",
lockInfo{}, LockInfo{},
http.StatusBadRequest, http.StatusBadRequest,
}, { }, {
"bad: unfinished XML #2", "bad: unfinished XML #2",
@ -71,12 +71,12 @@ func TestReadLockInfo(t *testing.T) {
" <D:lockscope><D:exclusive/></D:lockscope>\n" + " <D:lockscope><D:exclusive/></D:lockscope>\n" +
" <D:locktype><D:write/></D:locktype>\n" + " <D:locktype><D:write/></D:locktype>\n" +
" <D:owner>\n", " <D:owner>\n",
lockInfo{}, LockInfo{},
http.StatusBadRequest, http.StatusBadRequest,
}, { }, {
"good: empty", "good: empty",
"", "",
lockInfo{}, LockInfo{},
0, 0,
}, { }, {
"good: plain-text owner", "good: plain-text owner",
@ -86,11 +86,11 @@ func TestReadLockInfo(t *testing.T) {
" <D:locktype><D:write/></D:locktype>\n" + " <D:locktype><D:write/></D:locktype>\n" +
" <D:owner>gopher</D:owner>\n" + " <D:owner>gopher</D:owner>\n" +
"</D:lockinfo>", "</D:lockinfo>",
lockInfo{ LockInfo{
XMLName: ixml.Name{Space: "DAV:", Local: "lockinfo"}, XMLName: ixml.Name{Space: "DAV:", Local: "lockinfo"},
Exclusive: new(struct{}), Exclusive: new(struct{}),
Write: new(struct{}), Write: new(struct{}),
Owner: owner{ Owner: Owner{
InnerXML: "gopher", InnerXML: "gopher",
}, },
}, },
@ -105,11 +105,11 @@ func TestReadLockInfo(t *testing.T) {
" <D:href>http://example.org/~ejw/contact.html</D:href>\n" + " <D:href>http://example.org/~ejw/contact.html</D:href>\n" +
" </D:owner>\n" + " </D:owner>\n" +
"</D:lockinfo>", "</D:lockinfo>",
lockInfo{ LockInfo{
XMLName: ixml.Name{Space: "DAV:", Local: "lockinfo"}, XMLName: ixml.Name{Space: "DAV:", Local: "lockinfo"},
Exclusive: new(struct{}), Exclusive: new(struct{}),
Write: new(struct{}), Write: new(struct{}),
Owner: owner{ Owner: Owner{
InnerXML: "\n <D:href>http://example.org/~ejw/contact.html</D:href>\n ", InnerXML: "\n <D:href>http://example.org/~ejw/contact.html</D:href>\n ",
}, },
}, },
@ -117,7 +117,7 @@ func TestReadLockInfo(t *testing.T) {
}} }}
for _, tc := range testCases { for _, tc := range testCases {
li, status, err := readLockInfo(strings.NewReader(tc.input)) li, status, err := ReadLockInfo(strings.NewReader(tc.input))
if tc.wantStatus != 0 { if tc.wantStatus != 0 {
if err == nil { if err == nil {
t.Errorf("%s: got nil error, want non-nil", tc.desc) t.Errorf("%s: got nil error, want non-nil", tc.desc)
@ -139,7 +139,7 @@ func TestReadPropfind(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string
input string input string
wantPF propfind wantPF Propfind
wantStatus int wantStatus int
}{{ }{{
desc: "propfind: propname", desc: "propfind: propname",
@ -147,14 +147,14 @@ func TestReadPropfind(t *testing.T) {
"<A:propfind xmlns:A='DAV:'>\n" + "<A:propfind xmlns:A='DAV:'>\n" +
" <A:propname/>\n" + " <A:propname/>\n" +
"</A:propfind>", "</A:propfind>",
wantPF: propfind{ wantPF: Propfind{
XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, XMLName: ixml.Name{Space: "DAV:", Local: "propfind"},
Propname: new(struct{}), Propname: new(struct{}),
}, },
}, { }, {
desc: "propfind: empty body means allprop", desc: "propfind: empty body means allprop",
input: "", input: "",
wantPF: propfind{ wantPF: Propfind{
Allprop: new(struct{}), Allprop: new(struct{}),
}, },
}, { }, {
@ -163,7 +163,7 @@ func TestReadPropfind(t *testing.T) {
"<A:propfind xmlns:A='DAV:'>\n" + "<A:propfind xmlns:A='DAV:'>\n" +
" <A:allprop/>\n" + " <A:allprop/>\n" +
"</A:propfind>", "</A:propfind>",
wantPF: propfind{ wantPF: Propfind{
XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, XMLName: ixml.Name{Space: "DAV:", Local: "propfind"},
Allprop: new(struct{}), Allprop: new(struct{}),
}, },
@ -174,10 +174,10 @@ func TestReadPropfind(t *testing.T) {
" <A:allprop/>\n" + " <A:allprop/>\n" +
" <A:include><A:displayname/></A:include>\n" + " <A:include><A:displayname/></A:include>\n" +
"</A:propfind>", "</A:propfind>",
wantPF: propfind{ wantPF: Propfind{
XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, XMLName: ixml.Name{Space: "DAV:", Local: "propfind"},
Allprop: new(struct{}), Allprop: new(struct{}),
Include: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, Include: PropfindProps{xml.Name{Space: "DAV:", Local: "displayname"}},
}, },
}, { }, {
desc: "propfind: include followed by allprop", desc: "propfind: include followed by allprop",
@ -186,10 +186,10 @@ func TestReadPropfind(t *testing.T) {
" <A:include><A:displayname/></A:include>\n" + " <A:include><A:displayname/></A:include>\n" +
" <A:allprop/>\n" + " <A:allprop/>\n" +
"</A:propfind>", "</A:propfind>",
wantPF: propfind{ wantPF: Propfind{
XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, XMLName: ixml.Name{Space: "DAV:", Local: "propfind"},
Allprop: new(struct{}), Allprop: new(struct{}),
Include: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, Include: PropfindProps{xml.Name{Space: "DAV:", Local: "displayname"}},
}, },
}, { }, {
desc: "propfind: propfind", desc: "propfind: propfind",
@ -197,9 +197,9 @@ func TestReadPropfind(t *testing.T) {
"<A:propfind xmlns:A='DAV:'>\n" + "<A:propfind xmlns:A='DAV:'>\n" +
" <A:prop><A:displayname/></A:prop>\n" + " <A:prop><A:displayname/></A:prop>\n" +
"</A:propfind>", "</A:propfind>",
wantPF: propfind{ wantPF: Propfind{
XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, XMLName: ixml.Name{Space: "DAV:", Local: "propfind"},
Prop: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, Prop: PropfindProps{xml.Name{Space: "DAV:", Local: "displayname"}},
}, },
}, { }, {
desc: "propfind: prop with ignored comments", desc: "propfind: prop with ignored comments",
@ -210,9 +210,9 @@ func TestReadPropfind(t *testing.T) {
" <A:displayname><!-- ignore --></A:displayname>\n" + " <A:displayname><!-- ignore --></A:displayname>\n" +
" </A:prop>\n" + " </A:prop>\n" +
"</A:propfind>", "</A:propfind>",
wantPF: propfind{ wantPF: Propfind{
XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, XMLName: ixml.Name{Space: "DAV:", Local: "propfind"},
Prop: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, Prop: PropfindProps{xml.Name{Space: "DAV:", Local: "displayname"}},
}, },
}, { }, {
desc: "propfind: propfind with ignored whitespace", desc: "propfind: propfind with ignored whitespace",
@ -220,9 +220,9 @@ func TestReadPropfind(t *testing.T) {
"<A:propfind xmlns:A='DAV:'>\n" + "<A:propfind xmlns:A='DAV:'>\n" +
" <A:prop> <A:displayname/></A:prop>\n" + " <A:prop> <A:displayname/></A:prop>\n" +
"</A:propfind>", "</A:propfind>",
wantPF: propfind{ wantPF: Propfind{
XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, XMLName: ixml.Name{Space: "DAV:", Local: "propfind"},
Prop: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, Prop: PropfindProps{xml.Name{Space: "DAV:", Local: "displayname"}},
}, },
}, { }, {
desc: "propfind: propfind with ignored mixed-content", desc: "propfind: propfind with ignored mixed-content",
@ -230,9 +230,9 @@ func TestReadPropfind(t *testing.T) {
"<A:propfind xmlns:A='DAV:'>\n" + "<A:propfind xmlns:A='DAV:'>\n" +
" <A:prop>foo<A:displayname/>bar</A:prop>\n" + " <A:prop>foo<A:displayname/>bar</A:prop>\n" +
"</A:propfind>", "</A:propfind>",
wantPF: propfind{ wantPF: Propfind{
XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, XMLName: ixml.Name{Space: "DAV:", Local: "propfind"},
Prop: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, Prop: PropfindProps{xml.Name{Space: "DAV:", Local: "displayname"}},
}, },
}, { }, {
desc: "propfind: propname with ignored element (section A.4)", desc: "propfind: propname with ignored element (section A.4)",
@ -241,7 +241,7 @@ func TestReadPropfind(t *testing.T) {
" <A:propname/>\n" + " <A:propname/>\n" +
" <E:leave-out xmlns:E='E:'>*boss*</E:leave-out>\n" + " <E:leave-out xmlns:E='E:'>*boss*</E:leave-out>\n" +
"</A:propfind>", "</A:propfind>",
wantPF: propfind{ wantPF: Propfind{
XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, XMLName: ixml.Name{Space: "DAV:", Local: "propfind"},
Propname: new(struct{}), Propname: new(struct{}),
}, },
@ -330,7 +330,7 @@ func TestReadPropfind(t *testing.T) {
}} }}
for _, tc := range testCases { for _, tc := range testCases {
pf, status, err := readPropfind(strings.NewReader(tc.input)) pf, status, err := ReadPropfind(strings.NewReader(tc.input))
if tc.wantStatus != 0 { if tc.wantStatus != 0 {
if err == nil { if err == nil {
t.Errorf("%s: got nil error, want non-nil", tc.desc) t.Errorf("%s: got nil error, want non-nil", tc.desc)
@ -353,7 +353,7 @@ func TestMultistatusWriter(t *testing.T) {
// http://www.webdav.org/specs/rfc4918.html // http://www.webdav.org/specs/rfc4918.html
testCases := []struct { testCases := []struct {
desc string desc string
responses []response responses []Response
respdesc string respdesc string
writeHeader bool writeHeader bool
wantXML string wantXML string
@ -361,9 +361,9 @@ func TestMultistatusWriter(t *testing.T) {
wantErr error wantErr error
}{{ }{{
desc: "section 9.2.2 (failed dependency)", desc: "section 9.2.2 (failed dependency)",
responses: []response{{ responses: []Response{{
Href: []string{"http://example.com/foo"}, Href: []string{"http://example.com/foo"},
Propstat: []propstat{{ Propstat: []SubPropstat{{
Prop: []Property{{ Prop: []Property{{
XMLName: xml.Name{ XMLName: xml.Name{
Space: "http://ns.example.com/", Space: "http://ns.example.com/",
@ -405,10 +405,10 @@ func TestMultistatusWriter(t *testing.T) {
wantCode: StatusMulti, wantCode: StatusMulti,
}, { }, {
desc: "section 9.6.2 (lock-token-submitted)", desc: "section 9.6.2 (lock-token-submitted)",
responses: []response{{ responses: []Response{{
Href: []string{"http://example.com/foo"}, Href: []string{"http://example.com/foo"},
Status: "HTTP/1.1 423 Locked", Status: "HTTP/1.1 423 Locked",
Error: &xmlError{ Error: &XmlError{
InnerXML: []byte(`<lock-token-submitted xmlns="DAV:"/>`), InnerXML: []byte(`<lock-token-submitted xmlns="DAV:"/>`),
}, },
}}, }},
@ -424,9 +424,9 @@ func TestMultistatusWriter(t *testing.T) {
wantCode: StatusMulti, wantCode: StatusMulti,
}, { }, {
desc: "section 9.1.3", desc: "section 9.1.3",
responses: []response{{ responses: []Response{{
Href: []string{"http://example.com/foo"}, Href: []string{"http://example.com/foo"},
Propstat: []propstat{{ Propstat: []SubPropstat{{
Prop: []Property{{ Prop: []Property{{
XMLName: xml.Name{Space: "http://ns.example.com/boxschema/", Local: "bigbox"}, XMLName: xml.Name{Space: "http://ns.example.com/boxschema/", Local: "bigbox"},
InnerXML: []byte(`` + InnerXML: []byte(`` +
@ -492,8 +492,8 @@ func TestMultistatusWriter(t *testing.T) {
wantCode: StatusMulti, wantCode: StatusMulti,
}, { }, {
desc: "bad: no href", desc: "bad: no href",
responses: []response{{ responses: []Response{{
Propstat: []propstat{{ Propstat: []SubPropstat{{
Prop: []Property{{ Prop: []Property{{
XMLName: xml.Name{ XMLName: xml.Name{
Space: "http://example.com/", Space: "http://example.com/",
@ -508,7 +508,7 @@ func TestMultistatusWriter(t *testing.T) {
wantCode: http.StatusOK, wantCode: http.StatusOK,
}, { }, {
desc: "bad: multiple hrefs and no status", desc: "bad: multiple hrefs and no status",
responses: []response{{ responses: []Response{{
Href: []string{"http://example.com/foo", "http://example.com/bar"}, Href: []string{"http://example.com/foo", "http://example.com/bar"},
}}, }},
wantErr: errInvalidResponse, wantErr: errInvalidResponse,
@ -516,7 +516,7 @@ func TestMultistatusWriter(t *testing.T) {
wantCode: http.StatusOK, wantCode: http.StatusOK,
}, { }, {
desc: "bad: one href and no propstat", desc: "bad: one href and no propstat",
responses: []response{{ responses: []Response{{
Href: []string{"http://example.com/foo"}, Href: []string{"http://example.com/foo"},
}}, }},
wantErr: errInvalidResponse, wantErr: errInvalidResponse,
@ -524,9 +524,9 @@ func TestMultistatusWriter(t *testing.T) {
wantCode: http.StatusOK, wantCode: http.StatusOK,
}, { }, {
desc: "bad: status with one href and propstat", desc: "bad: status with one href and propstat",
responses: []response{{ responses: []Response{{
Href: []string{"http://example.com/foo"}, Href: []string{"http://example.com/foo"},
Propstat: []propstat{{ Propstat: []SubPropstat{{
Prop: []Property{{ Prop: []Property{{
XMLName: xml.Name{ XMLName: xml.Name{
Space: "http://example.com/", Space: "http://example.com/",
@ -542,12 +542,12 @@ func TestMultistatusWriter(t *testing.T) {
wantCode: http.StatusOK, wantCode: http.StatusOK,
}, { }, {
desc: "bad: multiple hrefs and propstat", desc: "bad: multiple hrefs and propstat",
responses: []response{{ responses: []Response{{
Href: []string{ Href: []string{
"http://example.com/foo", "http://example.com/foo",
"http://example.com/bar", "http://example.com/bar",
}, },
Propstat: []propstat{{ Propstat: []SubPropstat{{
Prop: []Property{{ Prop: []Property{{
XMLName: xml.Name{ XMLName: xml.Name{
Space: "http://example.com/", Space: "http://example.com/",
@ -566,7 +566,7 @@ func TestMultistatusWriter(t *testing.T) {
loop: loop:
for _, tc := range testCases { for _, tc := range testCases {
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
w := multistatusWriter{w: rec, responseDescription: tc.respdesc} w := MultiStatusWriter{Writer: rec, ResponseDescription: tc.respdesc}
if tc.writeHeader { if tc.writeHeader {
if err := w.writeHeader(); err != nil { if err := w.writeHeader(); err != nil {
t.Errorf("%s: got writeHeader error %v, want nil", tc.desc, err) t.Errorf("%s: got writeHeader error %v, want nil", tc.desc, err)
@ -574,7 +574,7 @@ loop:
} }
} }
for _, r := range tc.responses { for _, r := range tc.responses {
if err := w.write(&r); err != nil { if err := w.Write(&r); err != nil {
if err != tc.wantErr { if err != tc.wantErr {
t.Errorf("%s: got write error %v, want %v", t.Errorf("%s: got write error %v, want %v",
tc.desc, err, tc.wantErr) tc.desc, err, tc.wantErr)
@ -705,7 +705,7 @@ func TestReadProppatch(t *testing.T) {
}} }}
for _, tc := range testCases { for _, tc := range testCases {
pp, status, err := readProppatch(strings.NewReader(tc.input)) pp, status, err := ReadProppatch(strings.NewReader(tc.input))
if tc.wantStatus != 0 { if tc.wantStatus != 0 {
if err == nil { if err == nil {
t.Errorf("%s: got nil error, want non-nil", tc.desc) t.Errorf("%s: got nil error, want non-nil", tc.desc)
@ -800,7 +800,7 @@ func TestUnmarshalXMLValue(t *testing.T) {
var n xmlNormalizer var n xmlNormalizer
for _, tc := range testCases { for _, tc := range testCases {
d := ixml.NewDecoder(strings.NewReader(tc.input)) d := ixml.NewDecoder(strings.NewReader(tc.input))
var v xmlValue var v XmlValue
if err := d.Decode(&v); err != nil { if err := d.Decode(&v); err != nil {
t.Errorf("%s: got error %v, want nil", tc.desc, err) t.Errorf("%s: got error %v, want nil", tc.desc, err)
continue continue

View File

@ -98,7 +98,7 @@ func (this *DavController) Index(writer http.ResponseWriter, request *http.Reque
this.logger.Info("请求访问来了:%s %s", request.RequestURI, subPath) this.logger.Info("请求访问来了:%s %s", request.RequestURI, subPath)
method := request.Method method := request.Method
if method == "PROPFIND1" { if method == "PROPFIND" {
this.davService.HandlePropfind(writer, request, subPath) this.davService.HandlePropfind(writer, request, subPath)

View File

@ -1,33 +1,3 @@
package rest package rest
import (
"encoding/xml"
)
/**
*
* WebDav协议文档
* https://tools.ietf.org/html/rfc4918
* http://www.webdav.org/specs/rfc4918.html
*
*/
const (
//有多少层展示多少层
INFINITE_DEPTH = -1
)
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_propfind
//PROPFIND方法请求时POST BODY入参
type Propfind struct {
XMLName xml.Name `xml:"D:propfind"`
XmlNS string `xml:"xmlns:D,attr"`
Allprop *struct{} `xml:"D:allprop"`
Propname *struct{} `xml:"D:propname"`
Prop PropfindProps `xml:"D:prop"`
Include PropfindProps `xml:"D:include"`
}
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_prop (for propfind)
type PropfindProps []xml.Name

View File

@ -1,17 +1,17 @@
package rest package rest
import ( import (
"encoding/xml"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"net/url"
"tank/rest/dav"
) )
/** /**
* *
* WebDav协议文档 * WebDav协议文档
* https://tools.ietf.org/html/rfc4918 * https://tools.ietf.org/html/rfc4918
* * 主要参考 golang.org/x/net/webdav
*/ */
//@Service //@Service
type DavService struct { type DavService struct {
@ -30,22 +30,24 @@ func (this *DavService) Init() {
} }
} }
//从request中读取深度 func (this *DavService) makePropstatResponse(href string, pstats []dav.Propstat) *dav.Response {
func (this *DavService) readDepth(request *http.Request) int { resp := dav.Response{
Href: []string{(&url.URL{Path: href}).EscapedPath()},
depth := INFINITE_DEPTH Propstat: make([]dav.SubPropstat, 0, len(pstats)),
if hdr := request.Header.Get("Depth"); hdr != "" {
if hdr == "0" {
depth = 0
} else if hdr == "1" {
depth = 1
} else if hdr == "infinity" {
depth = INFINITE_DEPTH
} else {
panic("Depth格式错误")
}
} }
return depth for _, p := range pstats {
var xmlErr *dav.XmlError
if p.XMLError != "" {
xmlErr = &dav.XmlError{InnerXML: []byte(p.XMLError)}
}
resp.Propstat = append(resp.Propstat, dav.SubPropstat{
Status: fmt.Sprintf("HTTP/1.1 %d %s", p.Status, dav.StatusText(p.Status)),
Prop: p.Props,
ResponseDescription: p.ResponseDescription,
Error: xmlErr,
})
}
return &resp
} }
//处理 方法 //处理 方法
@ -54,28 +56,25 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http
//获取请求者 //获取请求者
user := this.checkUser(writer, request) user := this.checkUser(writer, request)
//读取希望访问的深度。
depth := this.readDepth(request)
//找寻请求的目录 //找寻请求的目录
matter := this.matterDao.checkByUserUuidAndPath(user.Uuid, subPath) matter := this.matterDao.checkByUserUuidAndPath(user.Uuid, subPath)
//TODO: 读取请求参数。按照用户的参数请求返回内容。 //读取请求参数。按照用户的参数请求返回内容。
propfind := &Propfind{} propfind, _, err := dav.ReadPropfind(request.Body)
body, err := ioutil.ReadAll(request.Body)
this.PanicError(err) this.PanicError(err)
//从xml中解析内容到struct //准备一个输出结果的Writer
err = xml.Unmarshal(body, &propfind) multiStatusWriter := dav.MultiStatusWriter{Writer: writer}
var propstats []dav.Propstat
propstats = append(propstats, dav.Propstat{
ResponseDescription: "有点问题",
})
response := this.makePropstatResponse("/eyeblue/ready/go", propstats)
err = multiStatusWriter.Write(response)
this.PanicError(err) this.PanicError(err)
//从struct还原到xml fmt.Printf("%v %v \n", matter.Name, propfind.Prop)
output, err := xml.MarshalIndent(propfind, " ", " ")
this.PanicError(err)
fmt.Println(string(output))
fmt.Printf("%v %v \n", depth, matter.Name)
} }