Add the dav_test.
This commit is contained in:
parent
dc3e570067
commit
955e7a01db
@ -6,12 +6,12 @@ package dav
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"tank/rest/dav/xml"
|
"tank/rest/dav/xml"
|
||||||
|
"tank/rest/result"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Proppatch describes a property update instruction as defined in RFC 4918.
|
// Proppatch describes a property update instruction as defined in RFC 4918.
|
||||||
@ -100,26 +100,6 @@ func EscapeXML(s string) string {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ContentTyper is an optional interface for the os.FileInfo
|
|
||||||
// objects returned by the FileSystem.
|
|
||||||
//
|
|
||||||
// If this interface is defined then it will be used to read the
|
|
||||||
// content type from the object.
|
|
||||||
//
|
|
||||||
// If this interface is not defined the file will be opened and the
|
|
||||||
// content type will be guessed from the initial contents of the file.
|
|
||||||
type ContentTyper interface {
|
|
||||||
// ContentType returns the content type for the file.
|
|
||||||
//
|
|
||||||
// If this returns error ErrNotImplemented then the error will
|
|
||||||
// be ignored and the base implementation will be used
|
|
||||||
// instead.
|
|
||||||
ContentType(ctx context.Context) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// http://www.webdav.org/specs/rfc4918.html#status.code.extensions.to.http11
|
// http://www.webdav.org/specs/rfc4918.html#status.code.extensions.to.http11
|
||||||
const (
|
const (
|
||||||
StatusMulti = 207
|
StatusMulti = 207
|
||||||
@ -245,33 +225,37 @@ type Propfind struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//从request中读出需要的属性。比如:getcontentlength 大小 creationdate 创建时间
|
//从request中读出需要的属性。比如:getcontentlength 大小 creationdate 创建时间
|
||||||
func ReadPropfind(reader io.Reader) (propfind Propfind, status int, err error) {
|
func ReadPropfind(reader io.Reader) (propfind *Propfind) {
|
||||||
|
propfind = &Propfind{}
|
||||||
|
|
||||||
c := CountingReader{reader: reader}
|
c := CountingReader{reader: reader}
|
||||||
if err = xml.NewDecoder(&c).Decode(&propfind); err != nil {
|
if err := xml.NewDecoder(&c).Decode(&propfind); 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{})}
|
||||||
}
|
}
|
||||||
err = errInvalidPropfind
|
err = errInvalidPropfind
|
||||||
}
|
}
|
||||||
return Propfind{}, http.StatusBadRequest, err
|
|
||||||
|
panic(result.BadRequest(err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if propfind.Allprop == nil && propfind.Include != nil {
|
if propfind.Allprop == nil && propfind.Include != nil {
|
||||||
return Propfind{}, http.StatusBadRequest, errInvalidPropfind
|
panic(result.BadRequest(errInvalidPropfind.Error()))
|
||||||
}
|
}
|
||||||
if propfind.Allprop != nil && (propfind.Prop != nil || propfind.Propname != nil) {
|
if propfind.Allprop != nil && (propfind.Prop != nil || propfind.Propname != nil) {
|
||||||
return Propfind{}, http.StatusBadRequest, errInvalidPropfind
|
panic(result.BadRequest(errInvalidPropfind.Error()))
|
||||||
}
|
}
|
||||||
if propfind.Prop != nil && propfind.Propname != nil {
|
if propfind.Prop != nil && propfind.Propname != nil {
|
||||||
return Propfind{}, http.StatusBadRequest, errInvalidPropfind
|
panic(result.BadRequest(errInvalidPropfind.Error()))
|
||||||
}
|
}
|
||||||
if propfind.Propname == nil && propfind.Allprop == nil && propfind.Prop == nil {
|
if propfind.Propname == nil && propfind.Allprop == nil && propfind.Prop == nil {
|
||||||
return Propfind{}, http.StatusBadRequest, errInvalidPropfind
|
panic(result.BadRequest(errInvalidPropfind.Error()))
|
||||||
}
|
}
|
||||||
return propfind, 0, nil
|
|
||||||
|
return propfind
|
||||||
}
|
}
|
||||||
|
|
||||||
// Property represents a single DAV resource property as defined in RFC 4918.
|
// Property represents a single DAV resource property as defined in RFC 4918.
|
||||||
@ -395,16 +379,16 @@ 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(response *Response) error {
|
||||||
switch len(r.Href) {
|
switch len(response.Href) {
|
||||||
case 0:
|
case 0:
|
||||||
return errInvalidResponse
|
return errInvalidResponse
|
||||||
case 1:
|
case 1:
|
||||||
if len(r.Propstat) > 0 != (r.Status == "") {
|
if len(response.Propstat) > 0 != (response.Status == "") {
|
||||||
return errInvalidResponse
|
return errInvalidResponse
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if len(r.Propstat) > 0 || r.Status == "" {
|
if len(response.Propstat) > 0 || response.Status == "" {
|
||||||
return errInvalidResponse
|
return errInvalidResponse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -412,7 +396,7 @@ func (this *MultiStatusWriter) Write(r *Response) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return this.Encoder.Encode(r)
|
return this.Encoder.Encode(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeHeader writes a XML multistatus start element on w's underlying
|
// writeHeader writes a XML multistatus start element on w's underlying
|
||||||
|
@ -11,11 +11,13 @@ import (
|
|||||||
"tank/rest/dav/xml"
|
"tank/rest/dav/xml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* WebDav协议文档
|
* WebDav协议文档
|
||||||
* https://tools.ietf.org/html/rfc4918
|
* https://tools.ietf.org/html/rfc4918
|
||||||
* 主要参考 golang.org/x/net/webdav
|
* 主要参考 golang.org/x/net/webdav
|
||||||
|
* 测试机:http://www.webdav.org/neon/litmus/
|
||||||
*/
|
*/
|
||||||
//@Service
|
//@Service
|
||||||
type DavService struct {
|
type DavService struct {
|
||||||
@ -129,7 +131,7 @@ func (this *DavService) AllPropXmlNames(matter *Matter) []xml.Name {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//从一个matter中获取其 []dav.Propstat
|
//从一个matter中获取其 []dav.Propstat
|
||||||
func (this *DavService) Propstats(user *User, matter *Matter, propfind dav.Propfind) []dav.Propstat {
|
func (this *DavService) Propstats(user *User, matter *Matter, propfind *dav.Propfind) []dav.Propstat {
|
||||||
|
|
||||||
propstats := make([]dav.Propstat, 0)
|
propstats := make([]dav.Propstat, 0)
|
||||||
if propfind.Propname != nil {
|
if propfind.Propname != nil {
|
||||||
@ -158,8 +160,7 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http
|
|||||||
depth := this.ParseDepth(request)
|
depth := this.ParseDepth(request)
|
||||||
|
|
||||||
//读取请求参数。按照用户的参数请求返回内容。
|
//读取请求参数。按照用户的参数请求返回内容。
|
||||||
propfind, _, err := dav.ReadPropfind(request.Body)
|
propfind := dav.ReadPropfind(request.Body)
|
||||||
this.PanicError(err)
|
|
||||||
|
|
||||||
//寻找符合条件的matter.
|
//寻找符合条件的matter.
|
||||||
//如果是空或者/就是请求根目录
|
//如果是空或者/就是请求根目录
|
||||||
@ -177,7 +178,7 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http
|
|||||||
}
|
}
|
||||||
|
|
||||||
//准备一个输出结果的Writer
|
//准备一个输出结果的Writer
|
||||||
multiStatusWriter := dav.MultiStatusWriter{Writer: writer}
|
multiStatusWriter := &dav.MultiStatusWriter{Writer: writer}
|
||||||
|
|
||||||
for _, matter := range matters {
|
for _, matter := range matters {
|
||||||
|
|
||||||
@ -187,12 +188,12 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http
|
|||||||
path := fmt.Sprintf("%s%s", WEBDAV_PREFFIX, matter.Path)
|
path := fmt.Sprintf("%s%s", WEBDAV_PREFFIX, matter.Path)
|
||||||
response := this.makePropstatResponse(path, propstats)
|
response := this.makePropstatResponse(path, propstats)
|
||||||
|
|
||||||
err = multiStatusWriter.Write(response)
|
err := multiStatusWriter.Write(response)
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//闭合
|
//闭合
|
||||||
err = multiStatusWriter.Close()
|
err := multiStatusWriter.Close()
|
||||||
this.PanicError(err)
|
this.PanicError(err)
|
||||||
|
|
||||||
fmt.Printf("%v %v \n", subPath, propfind.Prop)
|
fmt.Printf("%v %v \n", subPath, propfind.Prop)
|
||||||
|
@ -122,7 +122,8 @@ func (this *Logger) openFile() {
|
|||||||
panic("日志文件无法正常打开: " + err.Error())
|
panic("日志文件无法正常打开: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
this.goLogger = log.New(f, "", log.Ltime)
|
this.goLogger = log.New(f, "", log.LstdFlags|log.Lshortfile)
|
||||||
|
|
||||||
this.file = f
|
this.file = f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReadPropfind(t *testing.T) {
|
func TestXmlDecoder(t *testing.T) {
|
||||||
|
|
||||||
propfind := &dav.Propfind{}
|
propfind := &dav.Propfind{}
|
||||||
|
|
||||||
@ -46,7 +46,55 @@ func TestReadPropfind(t *testing.T) {
|
|||||||
|
|
||||||
for k, v := range resultMap {
|
for k, v := range resultMap {
|
||||||
if !v {
|
if !v {
|
||||||
t.Errorf("index = %s error", k)
|
t.Errorf(" %s error", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("[%v] pass!", time.Now())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXmlEncoder(t *testing.T) {
|
||||||
|
|
||||||
|
writer := &bytes.Buffer{}
|
||||||
|
|
||||||
|
response := &dav.Response{
|
||||||
|
XMLName: xml.Name{Space: "DAV:", Local: "response"},
|
||||||
|
Href: []string{"/api/dav"},
|
||||||
|
Propstat: []dav.SubPropstat{
|
||||||
|
{
|
||||||
|
Prop: []dav.Property{
|
||||||
|
{
|
||||||
|
XMLName: xml.Name{Space: "DAV:", Local: "resourcetype"},
|
||||||
|
InnerXML: []byte(`<D:collection xmlns:D="DAV:"/>`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
XMLName: xml.Name{Space: "DAV:", Local: "getlastmodified"},
|
||||||
|
InnerXML: []byte(`Mon, 22 Apr 2019 06:38:36 GMT`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Status: "HTTP/1.1 200 OK",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := xml.NewEncoder(writer).Encode(response)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
bs := writer.Bytes()
|
||||||
|
|
||||||
|
str := string(bs)
|
||||||
|
|
||||||
|
resultMap := make(map[string]bool)
|
||||||
|
|
||||||
|
resultMap["equal"] = str == `<D:response><D:href>/api/dav</D:href><D:propstat><D:prop><D:resourcetype><D:collection xmlns:D="DAV:"/></D:resourcetype><D:getlastmodified>Mon, 22 Apr 2019 06:38:36 GMT</D:getlastmodified></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>`
|
||||||
|
|
||||||
|
for k, v := range resultMap {
|
||||||
|
if !v {
|
||||||
|
t.Errorf("%s error", k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user