Skip to content

Commit

Permalink
Refine some capital letters. Finish the Lock method.
Browse files Browse the repository at this point in the history
  • Loading branch information
zicla committed May 5, 2020
1 parent a314d4d commit ed0aa01
Show file tree
Hide file tree
Showing 10 changed files with 374 additions and 260 deletions.
99 changes: 97 additions & 2 deletions code/rest/dav_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"path"
"regexp"
"strings"
"time"
)

/**
Expand All @@ -28,6 +29,7 @@ type DavService struct {
BaseBean
matterDao *MatterDao
matterService *MatterService
lockSystem webdav.LockSystem
}

func (this *DavService) Init() {
Expand All @@ -43,6 +45,8 @@ func (this *DavService) Init() {
this.matterService = b
}

// init the webdav lock system.
this.lockSystem = webdav.NewMemLS()
}

//get the depth in header. Not support infinity yet.
Expand Down Expand Up @@ -536,9 +540,100 @@ func (this *DavService) HandleCopy(writer http.ResponseWriter, request *http.Req
}

//lock.
func (this *DavService) HandleLock(writer http.ResponseWriter, request *http.Request, user *User, subPath string) {
func (this *DavService) HandleLock(w http.ResponseWriter, r *http.Request, user *User, subPath string) {

xLimits := r.Header.Get("X-Litmus")
if xLimits == "locks: 6 (lock_excl)" {
fmt.Println("stop here!")
}

duration, err := webdav.ParseTimeout(r.Header.Get("Timeout"))
if err != nil {
panic(result.BadRequest(err.Error()))
}
li, status, err := webdav.ReadLockInfo(r.Body)
if err != nil {
panic(result.BadRequest(fmt.Sprintf("error:%s, status=%d", err.Error(), status)))
}

token, ld, now, created := "", webdav.LockDetails{}, time.Now(), false
if li == (webdav.LockInfo{}) {
// An empty LockInfo means to refresh the lock.
ih, ok := webdav.ParseIfHeader(r.Header.Get("If"))
if !ok {
panic(result.BadRequest(webdav.ErrInvalidIfHeader.Error()))
}
if len(ih.Lists) == 1 && len(ih.Lists[0].Conditions) == 1 {
token = ih.Lists[0].Conditions[0].Token
}
if token == "" {
panic(result.BadRequest(webdav.ErrInvalidLockToken.Error()))
}
ld, err = this.lockSystem.Refresh(now, token, duration)
if err != nil {
if err == webdav.ErrNoSuchLock {
panic(result.StatusCodeWebResult(http.StatusPreconditionFailed, err.Error()))
}
panic(result.StatusCodeWebResult(http.StatusInternalServerError, err.Error()))
}

} else {
// Section 9.10.3 says that "If no Depth header is submitted on a LOCK request,
// then the request MUST act as if a "Depth:infinity" had been submitted."
depth := webdav.InfiniteDepth
if hdr := r.Header.Get("Depth"); hdr != "" {
depth = webdav.ParseDepth(hdr)
if depth != 0 && depth != webdav.InfiniteDepth {
// Section 9.10.3 says that "Values other than 0 or infinity must not be
// used with the Depth header on a LOCK method".
panic(result.StatusCodeWebResult(http.StatusBadRequest, webdav.ErrInvalidDepth.Error()))
}
}

ld = webdav.LockDetails{
Root: subPath,
Duration: duration,
OwnerXML: li.Owner.InnerXML,
ZeroDepth: depth == 0,
}
token, err = this.lockSystem.Create(now, ld)
if err != nil {
if err == webdav.ErrLocked {
panic(result.StatusCodeWebResult(http.StatusLocked, err.Error()))
}
panic(result.StatusCodeWebResult(http.StatusInternalServerError, err.Error()))
}
defer func() {
//when error occur, rollback.
//this.lockSystem.Unlock(now, token)
}()

// Create the resource if it didn't previously exist.
// ctx := r.Context()
//if _, err := this.FileSystem.Stat(ctx, subPath); err != nil {
// f, err := h.FileSystem.OpenFile(ctx, reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
// if err != nil {
// // TODO: detect missing intermediate dirs and return http.StatusConflict?
// return http.StatusInternalServerError, err
// }
// f.Close()
// created = true
//}

// http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token says that the
// Lock-Token value is a Coded-URL. We add angle brackets.
w.Header().Set("Lock-Token", "<"+token+">")
}

w.Header().Set("Content-Type", "application/xml; charset=utf-8")
if created {
// This is "w.WriteHeader(http.StatusCreated)" and not "return
// http.StatusCreated, nil" because we write our own (XML) response to w
// and Handler.ServeHTTP would otherwise write "Created".
w.WriteHeader(http.StatusCreated)
}
_, _ = webdav.WriteLockInfo(w, token, ld)

panic(result.BadRequest("not support LOCK yet."))
}

//unlock
Expand Down
21 changes: 20 additions & 1 deletion code/tool/result/web_result.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"github.com/eyebluecn/tank/code/tool/i18n"
"net/http"
"strconv"
)

type WebResult struct {
Expand Down Expand Up @@ -73,7 +74,13 @@ func FetchHttpStatus(code string) int {
} else if code == SERVER.Code {
return SERVER.HttpStatus
} else {
return UNKNOWN.HttpStatus
//if this is an int. regard it as statusCode
statusCode, err := strconv.Atoi(code)
if err != nil {
return UNKNOWN.HttpStatus
} else {
return statusCode
}
}
}

Expand Down Expand Up @@ -104,6 +111,18 @@ func CustomWebResult(codeWrapper *CodeWrapper, description string) *WebResult {
return wr
}

//use standard http status code.
func StatusCodeWebResult(statusCode int, description string) *WebResult {
if description == "" {
description = http.StatusText(statusCode)
}
wr := &WebResult{
Code: fmt.Sprintf("%d", statusCode),
Msg: description,
}
return wr
}

func BadRequestI18n(request *http.Request, item *i18n.Item, v ...interface{}) *WebResult {
return CustomWebResult(BAD_REQUEST, fmt.Sprintf(item.Message(request), v...))
}
Expand Down
6 changes: 3 additions & 3 deletions code/tool/webdav/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,10 +370,10 @@ func (fs *memFS) Rename(ctx context.Context, oldName, newName string) error {
if oNode.children != nil {
if nNode, ok := nDir.children[nFrag]; ok {
if nNode.children == nil {
return errNotADirectory
return ErrNotADirectory
}
if len(nNode.children) != 0 {
return errDirectoryNotEmpty
return ErrDirectoryNotEmpty
}
}
}
Expand Down Expand Up @@ -653,7 +653,7 @@ func copyProps(dst, src File) error {
// See section 9.8.5 for when various HTTP status codes apply.
func copyFiles(ctx context.Context, fs FileSystem, src, dst string, overwrite bool, depth int, recursion int) (status int, err error) {
if recursion == 1000 {
return http.StatusInternalServerError, errRecursionTooDeep
return http.StatusInternalServerError, ErrRecursionTooDeep
}
recursion++

Expand Down
96 changes: 48 additions & 48 deletions code/tool/webdav/if.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,107 +11,107 @@ import (
"strings"
)

// ifHeader is a disjunction (OR) of ifLists.
type ifHeader struct {
lists []ifList
// IfHeader is a disjunction (OR) of ifLists.
type IfHeader struct {
Lists []IfList
}

// ifList is a conjunction (AND) of Conditions, and an optional resource tag.
type ifList struct {
resourceTag string
conditions []Condition
// IfList is a conjunction (AND) of Conditions, and an optional resource tag.
type IfList struct {
ResourceTag string
Conditions []Condition
}

// parseIfHeader parses the "If: foo bar" HTTP header. The httpHeader string
// ParseIfHeader parses the "If: foo bar" HTTP header. The httpHeader string
// should omit the "If:" prefix and have any "\r\n"s collapsed to a " ", as is
// returned by req.Header.Get("If") for a http.Request req.
func parseIfHeader(httpHeader string) (h ifHeader, ok bool) {
func ParseIfHeader(httpHeader string) (h IfHeader, ok bool) {
s := strings.TrimSpace(httpHeader)
switch tokenType, _, _ := lex(s); tokenType {
case '(':
return parseNoTagLists(s)
case angleTokenType:
return parseTaggedLists(s)
return ParseNoTagLists(s)
case AngleTokenType:
return ParseTaggedLists(s)
default:
return ifHeader{}, false
return IfHeader{}, false
}
}

func parseNoTagLists(s string) (h ifHeader, ok bool) {
func ParseNoTagLists(s string) (h IfHeader, ok bool) {
for {
l, remaining, ok := parseList(s)
l, remaining, ok := ParseList(s)
if !ok {
return ifHeader{}, false
return IfHeader{}, false
}
h.lists = append(h.lists, l)
h.Lists = append(h.Lists, l)
if remaining == "" {
return h, true
}
s = remaining
}
}

func parseTaggedLists(s string) (h ifHeader, ok bool) {
func ParseTaggedLists(s string) (h IfHeader, ok bool) {
resourceTag, n := "", 0
for first := true; ; first = false {
tokenType, tokenStr, remaining := lex(s)
switch tokenType {
case angleTokenType:
case AngleTokenType:
if !first && n == 0 {
return ifHeader{}, false
return IfHeader{}, false
}
resourceTag, n = tokenStr, 0
s = remaining
case '(':
n++
l, remaining, ok := parseList(s)
l, remaining, ok := ParseList(s)
if !ok {
return ifHeader{}, false
return IfHeader{}, false
}
l.resourceTag = resourceTag
h.lists = append(h.lists, l)
l.ResourceTag = resourceTag
h.Lists = append(h.Lists, l)
if remaining == "" {
return h, true
}
s = remaining
default:
return ifHeader{}, false
return IfHeader{}, false
}
}
}

func parseList(s string) (l ifList, remaining string, ok bool) {
func ParseList(s string) (l IfList, remaining string, ok bool) {
tokenType, _, s := lex(s)
if tokenType != '(' {
return ifList{}, "", false
return IfList{}, "", false
}
for {
tokenType, _, remaining = lex(s)
if tokenType == ')' {
if len(l.conditions) == 0 {
return ifList{}, "", false
if len(l.Conditions) == 0 {
return IfList{}, "", false
}
return l, remaining, true
}
c, remaining, ok := parseCondition(s)
c, remaining, ok := ParseCondition(s)
if !ok {
return ifList{}, "", false
return IfList{}, "", false
}
l.conditions = append(l.conditions, c)
l.Conditions = append(l.Conditions, c)
s = remaining
}
}

func parseCondition(s string) (c Condition, remaining string, ok bool) {
func ParseCondition(s string) (c Condition, remaining string, ok bool) {
tokenType, tokenStr, s := lex(s)
if tokenType == notTokenType {
if tokenType == NotTokenType {
c.Not = true
tokenType, tokenStr, s = lex(s)
}
switch tokenType {
case strTokenType, angleTokenType:
case StrTokenType, AngleTokenType:
c.Token = tokenStr
case squareTokenType:
case SquareTokenType:
c.ETag = tokenStr
default:
return Condition{}, "", false
Expand All @@ -122,12 +122,12 @@ func parseCondition(s string) (c Condition, remaining string, ok bool) {
// Single-rune tokens like '(' or ')' have a token type equal to their rune.
// All other tokens have a negative token type.
const (
errTokenType = rune(-1)
eofTokenType = rune(-2)
strTokenType = rune(-3)
notTokenType = rune(-4)
angleTokenType = rune(-5)
squareTokenType = rune(-6)
ErrTokenType = rune(-1)
EofTokenType = rune(-2)
StrTokenType = rune(-3)
NotTokenType = rune(-4)
AngleTokenType = rune(-5)
SquareTokenType = rune(-6)
)

func lex(s string) (tokenType rune, tokenStr string, remaining string) {
Expand All @@ -138,7 +138,7 @@ func lex(s string) (tokenType rune, tokenStr string, remaining string) {
s = s[1:]
}
if len(s) == 0 {
return eofTokenType, "", ""
return EofTokenType, "", ""
}
i := 0
loop:
Expand All @@ -152,22 +152,22 @@ loop:
if i != 0 {
tokenStr, remaining = s[:i], s[i:]
if tokenStr == "Not" {
return notTokenType, "", remaining
return NotTokenType, "", remaining
}
return strTokenType, tokenStr, remaining
return StrTokenType, tokenStr, remaining
}

j := 0
switch s[0] {
case '<':
j, tokenType = strings.IndexByte(s, '>'), angleTokenType
j, tokenType = strings.IndexByte(s, '>'), AngleTokenType
case '[':
j, tokenType = strings.IndexByte(s, ']'), squareTokenType
j, tokenType = strings.IndexByte(s, ']'), SquareTokenType
default:
return rune(s[0]), "", s[1:]
}
if j < 0 {
return errTokenType, "", ""
return ErrTokenType, "", ""
}
return tokenType, s[1:j], s[j+1:]
}
Loading

0 comments on commit ed0aa01

Please sign in to comment.