diff --git a/rest/dav/webdav.go b/rest/dav/webdav.go index 28793d4..a8ceedd 100644 --- a/rest/dav/webdav.go +++ b/rest/dav/webdav.go @@ -394,14 +394,14 @@ func (this *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStat if err != nil { return http.StatusBadRequest, err } - li, status, err := readLockInfo(r.Body) + li, status, err := ReadLockInfo(r.Body) if err != nil { return status, err } ctx := r.Context() token, ld, now, created := "", LockDetails{}, time.Now(), false - if li == (lockInfo{}) { + if li == (LockInfo{}) { // An empty lockInfo means to refresh the lock. ih, ok := parseIfHeader(r.Header.Get("If")) if !ok { @@ -479,7 +479,7 @@ func (this *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStat // and Handler.ServeHTTP would otherwise write "Created". w.WriteHeader(http.StatusCreated) } - writeLockInfo(w, token, ld) + WriteLockInfo(w, token, ld) return 0, nil } @@ -527,12 +527,12 @@ func (this *Handler) handlePropfind(writer http.ResponseWriter, request *http.Re } } //读取出request希望获取的文件属性。 - pf, status, err := readPropfind(request.Body) + pf, status, err := ReadPropfind(request.Body) if err != nil { return status, err } - multiStatusWriter := multistatusWriter{w: writer} + multiStatusWriter := MultiStatusWriter{Writer: writer} walkFn := func(reqPath string, info os.FileInfo, err error) error { if err != nil { @@ -566,7 +566,7 @@ func (this *Handler) handlePropfind(writer http.ResponseWriter, request *http.Re } propstatResponse := makePropstatResponse(href, propstats) - return multiStatusWriter.write(propstatResponse) + return multiStatusWriter.Write(propstatResponse) } 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 } - patches, status, err := readProppatch(r.Body) + patches, status, err := ReadProppatch(r.Body) if err != nil { return status, err } @@ -607,8 +607,8 @@ func (this *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (st if err != nil { return http.StatusInternalServerError, err } - mw := multistatusWriter{w: w} - writeErr := mw.write(makePropstatResponse(r.URL.Path, pstats)) + mw := MultiStatusWriter{Writer: w} + writeErr := mw.Write(makePropstatResponse(r.URL.Path, pstats)) closeErr := mw.close() if writeErr != nil { return http.StatusInternalServerError, writeErr @@ -619,17 +619,17 @@ func (this *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (st return 0, nil } -func makePropstatResponse(href string, pstats []Propstat) *response { - resp := response{ +func makePropstatResponse(href string, pstats []Propstat) *Response { + resp := Response{ Href: []string{(&url.URL{Path: href}).EscapedPath()}, - Propstat: make([]propstat, 0, len(pstats)), + Propstat: make([]SubPropstat, 0, len(pstats)), } for _, p := range pstats { - var xmlErr *xmlError + var xmlErr *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)), Prop: p.Props, ResponseDescription: p.ResponseDescription, diff --git a/rest/dav/xml.go b/rest/dav/xml.go index 6eea9ae..fa1adf0 100644 --- a/rest/dav/xml.go +++ b/rest/dav/xml.go @@ -36,53 +36,53 @@ import ( ) // http://www.webdav.org/specs/rfc4918.html#ELEMENT_lockinfo -type lockInfo struct { +type LockInfo struct { XMLName ixml.Name `xml:"lockinfo"` Exclusive *struct{} `xml:"lockscope>exclusive"` Shared *struct{} `xml:"lockscope>shared"` Write *struct{} `xml:"locktype>write"` - Owner owner `xml:"owner"` + Owner Owner `xml:"owner"` } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_owner -type owner struct { +type Owner struct { InnerXML string `xml:",innerxml"` } -func readLockInfo(r io.Reader) (li lockInfo, status int, err error) { - c := &countingReader{r: r} +func ReadLockInfo(r io.Reader) (li LockInfo, status int, err error) { + c := &CountingReader{r: r} if err = ixml.NewDecoder(c).Decode(&li); err != nil { if err == io.EOF { if c.n == 0 { // An empty body means to refresh the lock. // http://www.webdav.org/specs/rfc4918.html#refreshing-locks - return lockInfo{}, 0, nil + return LockInfo{}, 0, nil } err = errInvalidLockInfo } - return lockInfo{}, http.StatusBadRequest, err + return LockInfo{}, http.StatusBadRequest, err } // We only support exclusive (non-shared) write locks. In practice, these are // the only types of locks that seem to matter. if li.Exclusive == nil || li.Shared != nil || li.Write == nil { - return lockInfo{}, http.StatusNotImplemented, errUnsupportedLockInfo + return LockInfo{}, http.StatusNotImplemented, errUnsupportedLockInfo } return li, 0, nil } //这是一个带字节计数器的Reader,可以知道总共读取了多少个字节。 -type countingReader struct { +type CountingReader struct { n int 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) c.n += n 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" if ld.ZeroDepth { 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) -type propfindProps []xml.Name +type PropfindProps []xml.Name // UnmarshalXML appends the property names enclosed within start to pn. // // It returns an error if start does not contain any properties or if // 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 { t, err := next(d) 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 -type propfind struct { +type Propfind struct { XMLName ixml.Name `xml:"DAV: propfind"` Allprop *struct{} `xml:"DAV: allprop"` Propname *struct{} `xml:"DAV: propname"` - Prop propfindProps `xml:"DAV: prop"` - Include propfindProps `xml:"DAV: include"` + Prop PropfindProps `xml:"DAV: prop"` + Include PropfindProps `xml:"DAV: include"` } //从request中读出需要的属性。比如:getcontentlength 大小 creationdate 创建时间 -func readPropfind(r io.Reader) (pf propfind, status int, err error) { - c := countingReader{r: r} +func ReadPropfind(r io.Reader) (pf Propfind, status int, err error) { + c := CountingReader{r: r} if err = ixml.NewDecoder(&c).Decode(&pf); err != nil { if err == io.EOF { if c.n == 0 { // An empty body means to propfind allprop. // 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 } - return propfind{}, http.StatusBadRequest, err + return Propfind{}, http.StatusBadRequest, err } 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) { - return propfind{}, http.StatusBadRequest, errInvalidPropfind + return Propfind{}, http.StatusBadRequest, errInvalidPropfind } 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 { - return propfind{}, http.StatusBadRequest, errInvalidPropfind + return Propfind{}, http.StatusBadRequest, errInvalidPropfind } 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 // instead of an xml.Name. -type ixmlProperty struct { +type IxmlProperty struct { XMLName ixml.Name Lang string `xml:"xml:lang,attr,omitempty"` InnerXML []byte `xml:",innerxml"` } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_error -// See multistatusWriter for the "D:" namespace prefix. -type xmlError struct { +// See MultiStatusWriter for the "D:" namespace prefix. +type XmlError struct { XMLName ixml.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 { +// See MultiStatusWriter for the "D:" namespace prefix. +type SubPropstat struct { Prop []Property `xml:"D:prop>_ignored_"` Status string `xml:"D:status"` - Error *xmlError `xml:"D:error"` + Error *XmlError `xml:"D:error"` ResponseDescription string `xml:"D:responsedescription,omitempty"` } // ixmlPropstat is the same as the propstat type except it holds an ixml.Name // instead of an xml.Name. -type ixmlPropstat struct { - Prop []ixmlProperty `xml:"D:prop>_ignored_"` +type IxmlPropstat struct { + Prop []IxmlProperty `xml:"D:prop>_ignored_"` Status string `xml:"D:status"` - Error *xmlError `xml:"D:error"` + 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 *ixml.Encoder, start ixml.StartElement) error { +// before encoding. See MultiStatusWriter. +func (ps SubPropstat) MarshalXML(e *ixml.Encoder, start ixml.StartElement) error { // Convert from a propstat to an ixmlPropstat. - ixmlPs := ixmlPropstat{ - Prop: make([]ixmlProperty, len(ps.Prop)), + ixmlPs := IxmlPropstat{ + Prop: make([]IxmlProperty, len(ps.Prop)), Status: ps.Status, Error: ps.Error, ResponseDescription: ps.ResponseDescription, } for k, prop := range ps.Prop { - ixmlPs.Prop[k] = ixmlProperty{ + ixmlPs.Prop[k] = IxmlProperty{ XMLName: ixml.Name(prop.XMLName), Lang: prop.Lang, 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. - type newpropstat ixmlPropstat + type newpropstat IxmlPropstat return e.EncodeElement(newpropstat(ixmlPs), start) } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_response -// See multistatusWriter for the "D:" namespace prefix. -type response struct { - XMLName ixml.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"` +// See MultiStatusWriter for the "D:" namespace prefix. +type Response struct { + XMLName ixml.Name `xml:"D:response"` + Href []string `xml:"D:href"` + Propstat []SubPropstat `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 @@ -308,15 +308,15 @@ type response struct { // 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 { +type MultiStatusWriter struct { // ResponseDescription contains the optional responsedescription // of the multistatus XML element. Only the latest content before // close will be emitted. Empty response descriptions are not // written. - responseDescription string + ResponseDescription string - w http.ResponseWriter - enc *ixml.Encoder + Writer http.ResponseWriter + Encoder *ixml.Encoder } // 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 // of r with a multistatus tag. Callers must call close after the last response // has been written. -func (this *multistatusWriter) write(r *response) error { +func (this *MultiStatusWriter) Write(r *Response) error { switch len(r.Href) { case 0: return errInvalidResponse @@ -344,24 +344,24 @@ func (this *multistatusWriter) write(r *response) error { if err != nil { return err } - return this.enc.Encode(r) + return this.Encoder.Encode(r) } // writeHeader writes a XML multistatus start element on w's underlying // http.ResponseWriter and returns the result of the write operation. // After the first write attempt, writeHeader becomes a no-op. -func (this *multistatusWriter) writeHeader() error { - if this.enc != nil { +func (this *MultiStatusWriter) writeHeader() error { + if this.Encoder != nil { return nil } - this.w.Header().Add("Content-Type", "text/xml; charset=utf-8") - this.w.WriteHeader(StatusMulti) - _, err := fmt.Fprintf(this.w, ``) + this.Writer.Header().Add("Content-Type", "text/xml; charset=utf-8") + this.Writer.WriteHeader(StatusMulti) + _, err := fmt.Fprintf(this.Writer, ``) if err != nil { return err } - this.enc = ixml.NewEncoder(this.w) - return this.enc.EncodeToken(ixml.StartElement{ + this.Encoder = ixml.NewEncoder(this.Writer) + return this.Encoder.EncodeToken(ixml.StartElement{ Name: ixml.Name{ Space: "DAV:", Local: "multistatus", @@ -375,18 +375,18 @@ func (this *multistatusWriter) writeHeader() error { // Close completes the marshalling of the multistatus response. It returns // 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. -func (this *multistatusWriter) close() error { - if this.enc == nil { +func (this *MultiStatusWriter) close() error { + if this.Encoder == nil { return nil } var end []ixml.Token - if this.responseDescription != "" { + if this.ResponseDescription != "" { name := ixml.Name{Space: "DAV:", Local: "responsedescription"} end = append(end, ixml.StartElement{Name: name}, - ixml.CharData(this.responseDescription), + ixml.CharData(this.ResponseDescription), ixml.EndElement{Name: name}, ) } @@ -394,12 +394,12 @@ func (this *multistatusWriter) close() error { Name: ixml.Name{Space: "DAV:", Local: "multistatus"}, }) for _, t := range end { - err := this.enc.EncodeToken(t) + err := this.Encoder.EncodeToken(t) if err != nil { return err } } - return this.enc.Flush() + return this.Encoder.Flush() } 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 } -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. // To make sure that the unmarshalled value contains all required // 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) -type proppatchProps []Property +type ProppatchProps []Property // UnmarshalXML appends the property names and values enclosed within start // to ps. @@ -453,7 +453,7 @@ type proppatchProps []Property // // UnmarshalXML returns an error if start does not contain any properties or if // 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, "") for { 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), Lang: xmlLang(t.(ixml.StartElement), lang), } - err = d.DecodeElement(((*xmlValue)(&p.InnerXML)), &elem) + err = d.DecodeElement(((*XmlValue)(&p.InnerXML)), &elem) if err != nil { 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_remove -type setRemove struct { +type SetRemove struct { XMLName ixml.Name 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 -type propertyupdate struct { +type PropertyUpdate struct { XMLName ixml.Name `xml:"DAV: propertyupdate"` 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) { - var pu propertyupdate +func ReadProppatch(r io.Reader) (patches []Proppatch, status int, err error) { + var pu PropertyUpdate if err = ixml.NewDecoder(r).Decode(&pu); err != nil { return nil, http.StatusBadRequest, err } diff --git a/rest/dav/xml_test.go b/rest/dav/xml_test.go index 57f0189..1fe6328 100644 --- a/rest/dav/xml_test.go +++ b/rest/dav/xml_test.go @@ -25,12 +25,12 @@ func TestReadLockInfo(t *testing.T) { testCases := []struct { desc string input string - wantLI lockInfo + wantLI LockInfo wantStatus int }{{ "bad: junk", "xxx", - lockInfo{}, + LockInfo{}, http.StatusBadRequest, }, { "bad: invalid owner XML", @@ -42,7 +42,7 @@ func TestReadLockInfo(t *testing.T) { " no end tag \n" + " \n" + "", - lockInfo{}, + LockInfo{}, http.StatusBadRequest, }, { "bad: invalid UTF-8", @@ -54,7 +54,7 @@ func TestReadLockInfo(t *testing.T) { " \xff \n" + " \n" + "", - lockInfo{}, + LockInfo{}, http.StatusBadRequest, }, { "bad: unfinished XML #1", @@ -62,7 +62,7 @@ func TestReadLockInfo(t *testing.T) { "\n" + " \n" + " \n", - lockInfo{}, + LockInfo{}, http.StatusBadRequest, }, { "bad: unfinished XML #2", @@ -71,12 +71,12 @@ func TestReadLockInfo(t *testing.T) { " \n" + " \n" + " \n", - lockInfo{}, + LockInfo{}, http.StatusBadRequest, }, { "good: empty", "", - lockInfo{}, + LockInfo{}, 0, }, { "good: plain-text owner", @@ -86,11 +86,11 @@ func TestReadLockInfo(t *testing.T) { " \n" + " gopher\n" + "", - lockInfo{ + LockInfo{ XMLName: ixml.Name{Space: "DAV:", Local: "lockinfo"}, Exclusive: new(struct{}), Write: new(struct{}), - Owner: owner{ + Owner: Owner{ InnerXML: "gopher", }, }, @@ -105,11 +105,11 @@ func TestReadLockInfo(t *testing.T) { " http://example.org/~ejw/contact.html\n" + " \n" + "", - lockInfo{ + LockInfo{ XMLName: ixml.Name{Space: "DAV:", Local: "lockinfo"}, Exclusive: new(struct{}), Write: new(struct{}), - Owner: owner{ + Owner: Owner{ InnerXML: "\n http://example.org/~ejw/contact.html\n ", }, }, @@ -117,7 +117,7 @@ func TestReadLockInfo(t *testing.T) { }} 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 err == nil { t.Errorf("%s: got nil error, want non-nil", tc.desc) @@ -139,7 +139,7 @@ func TestReadPropfind(t *testing.T) { testCases := []struct { desc string input string - wantPF propfind + wantPF Propfind wantStatus int }{{ desc: "propfind: propname", @@ -147,14 +147,14 @@ func TestReadPropfind(t *testing.T) { "\n" + " \n" + "", - wantPF: propfind{ + wantPF: Propfind{ XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, Propname: new(struct{}), }, }, { desc: "propfind: empty body means allprop", input: "", - wantPF: propfind{ + wantPF: Propfind{ Allprop: new(struct{}), }, }, { @@ -163,7 +163,7 @@ func TestReadPropfind(t *testing.T) { "\n" + " \n" + "", - wantPF: propfind{ + wantPF: Propfind{ XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, Allprop: new(struct{}), }, @@ -174,10 +174,10 @@ func TestReadPropfind(t *testing.T) { " \n" + " \n" + "", - wantPF: propfind{ + wantPF: Propfind{ XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, 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", @@ -186,10 +186,10 @@ func TestReadPropfind(t *testing.T) { " \n" + " \n" + "", - wantPF: propfind{ + wantPF: Propfind{ XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, Allprop: new(struct{}), - Include: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, + Include: PropfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, }, }, { desc: "propfind: propfind", @@ -197,9 +197,9 @@ func TestReadPropfind(t *testing.T) { "\n" + " \n" + "", - wantPF: propfind{ + wantPF: 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", @@ -210,9 +210,9 @@ func TestReadPropfind(t *testing.T) { " \n" + " \n" + "", - wantPF: propfind{ + wantPF: 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", @@ -220,9 +220,9 @@ func TestReadPropfind(t *testing.T) { "\n" + " \n" + "", - wantPF: propfind{ + wantPF: 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", @@ -230,9 +230,9 @@ func TestReadPropfind(t *testing.T) { "\n" + " foobar\n" + "", - wantPF: propfind{ + wantPF: 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)", @@ -241,7 +241,7 @@ func TestReadPropfind(t *testing.T) { " \n" + " *boss*\n" + "", - wantPF: propfind{ + wantPF: Propfind{ XMLName: ixml.Name{Space: "DAV:", Local: "propfind"}, Propname: new(struct{}), }, @@ -330,7 +330,7 @@ func TestReadPropfind(t *testing.T) { }} 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 err == nil { 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 testCases := []struct { desc string - responses []response + responses []Response respdesc string writeHeader bool wantXML string @@ -361,9 +361,9 @@ func TestMultistatusWriter(t *testing.T) { wantErr error }{{ desc: "section 9.2.2 (failed dependency)", - responses: []response{{ + responses: []Response{{ Href: []string{"http://example.com/foo"}, - Propstat: []propstat{{ + Propstat: []SubPropstat{{ Prop: []Property{{ XMLName: xml.Name{ Space: "http://ns.example.com/", @@ -405,10 +405,10 @@ func TestMultistatusWriter(t *testing.T) { wantCode: StatusMulti, }, { desc: "section 9.6.2 (lock-token-submitted)", - responses: []response{{ + responses: []Response{{ Href: []string{"http://example.com/foo"}, Status: "HTTP/1.1 423 Locked", - Error: &xmlError{ + Error: &XmlError{ InnerXML: []byte(``), }, }}, @@ -424,9 +424,9 @@ func TestMultistatusWriter(t *testing.T) { wantCode: StatusMulti, }, { desc: "section 9.1.3", - responses: []response{{ + responses: []Response{{ Href: []string{"http://example.com/foo"}, - Propstat: []propstat{{ + Propstat: []SubPropstat{{ Prop: []Property{{ XMLName: xml.Name{Space: "http://ns.example.com/boxschema/", Local: "bigbox"}, InnerXML: []byte(`` + @@ -492,8 +492,8 @@ func TestMultistatusWriter(t *testing.T) { wantCode: StatusMulti, }, { desc: "bad: no href", - responses: []response{{ - Propstat: []propstat{{ + responses: []Response{{ + Propstat: []SubPropstat{{ Prop: []Property{{ XMLName: xml.Name{ Space: "http://example.com/", @@ -508,7 +508,7 @@ func TestMultistatusWriter(t *testing.T) { wantCode: http.StatusOK, }, { desc: "bad: multiple hrefs and no status", - responses: []response{{ + responses: []Response{{ Href: []string{"http://example.com/foo", "http://example.com/bar"}, }}, wantErr: errInvalidResponse, @@ -516,7 +516,7 @@ func TestMultistatusWriter(t *testing.T) { wantCode: http.StatusOK, }, { desc: "bad: one href and no propstat", - responses: []response{{ + responses: []Response{{ Href: []string{"http://example.com/foo"}, }}, wantErr: errInvalidResponse, @@ -524,9 +524,9 @@ func TestMultistatusWriter(t *testing.T) { wantCode: http.StatusOK, }, { desc: "bad: status with one href and propstat", - responses: []response{{ + responses: []Response{{ Href: []string{"http://example.com/foo"}, - Propstat: []propstat{{ + Propstat: []SubPropstat{{ Prop: []Property{{ XMLName: xml.Name{ Space: "http://example.com/", @@ -542,12 +542,12 @@ func TestMultistatusWriter(t *testing.T) { wantCode: http.StatusOK, }, { desc: "bad: multiple hrefs and propstat", - responses: []response{{ + responses: []Response{{ Href: []string{ "http://example.com/foo", "http://example.com/bar", }, - Propstat: []propstat{{ + Propstat: []SubPropstat{{ Prop: []Property{{ XMLName: xml.Name{ Space: "http://example.com/", @@ -566,7 +566,7 @@ func TestMultistatusWriter(t *testing.T) { loop: for _, tc := range testCases { rec := httptest.NewRecorder() - w := multistatusWriter{w: rec, responseDescription: tc.respdesc} + w := MultiStatusWriter{Writer: rec, ResponseDescription: tc.respdesc} if tc.writeHeader { if err := w.writeHeader(); err != nil { t.Errorf("%s: got writeHeader error %v, want nil", tc.desc, err) @@ -574,7 +574,7 @@ loop: } } for _, r := range tc.responses { - if err := w.write(&r); err != nil { + if err := w.Write(&r); err != nil { if err != tc.wantErr { t.Errorf("%s: got write error %v, want %v", tc.desc, err, tc.wantErr) @@ -705,7 +705,7 @@ func TestReadProppatch(t *testing.T) { }} 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 err == nil { t.Errorf("%s: got nil error, want non-nil", tc.desc) @@ -800,7 +800,7 @@ func TestUnmarshalXMLValue(t *testing.T) { var n xmlNormalizer for _, tc := range testCases { d := ixml.NewDecoder(strings.NewReader(tc.input)) - var v xmlValue + var v XmlValue if err := d.Decode(&v); err != nil { t.Errorf("%s: got error %v, want nil", tc.desc, err) continue diff --git a/rest/dav_controller.go b/rest/dav_controller.go index 04186a4..b9d5167 100644 --- a/rest/dav_controller.go +++ b/rest/dav_controller.go @@ -98,7 +98,7 @@ func (this *DavController) Index(writer http.ResponseWriter, request *http.Reque this.logger.Info("请求访问来了:%s %s", request.RequestURI, subPath) method := request.Method - if method == "PROPFIND1" { + if method == "PROPFIND" { this.davService.HandlePropfind(writer, request, subPath) diff --git a/rest/dav_model.go b/rest/dav_model.go index f118216..c9f4f37 100644 --- a/rest/dav_model.go +++ b/rest/dav_model.go @@ -1,33 +1,3 @@ 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 diff --git a/rest/dav_service.go b/rest/dav_service.go index 8d2e54c..66c729d 100644 --- a/rest/dav_service.go +++ b/rest/dav_service.go @@ -1,17 +1,17 @@ package rest import ( - "encoding/xml" "fmt" - "io/ioutil" "net/http" + "net/url" + "tank/rest/dav" ) /** * * WebDav协议文档 * https://tools.ietf.org/html/rfc4918 - * + * 主要参考 golang.org/x/net/webdav */ //@Service type DavService struct { @@ -30,22 +30,24 @@ func (this *DavService) Init() { } } -//从request中读取深度 -func (this *DavService) readDepth(request *http.Request) int { - - depth := INFINITE_DEPTH - 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格式错误!") - } +func (this *DavService) makePropstatResponse(href string, pstats []dav.Propstat) *dav.Response { + resp := dav.Response{ + Href: []string{(&url.URL{Path: href}).EscapedPath()}, + Propstat: make([]dav.SubPropstat, 0, len(pstats)), } - 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) - //读取希望访问的深度。 - depth := this.readDepth(request) - //找寻请求的目录 matter := this.matterDao.checkByUserUuidAndPath(user.Uuid, subPath) - //TODO: 读取请求参数。按照用户的参数请求返回内容。 - propfind := &Propfind{} - body, err := ioutil.ReadAll(request.Body) + //读取请求参数。按照用户的参数请求返回内容。 + propfind, _, err := dav.ReadPropfind(request.Body) this.PanicError(err) - //从xml中解析内容到struct - err = xml.Unmarshal(body, &propfind) + //准备一个输出结果的Writer + 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) - //从struct还原到xml - output, err := xml.MarshalIndent(propfind, " ", " ") - this.PanicError(err) - fmt.Println(string(output)) - - - - fmt.Printf("%v %v \n", depth, matter.Name) + fmt.Printf("%v %v \n", matter.Name, propfind.Prop) }