| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- // Copyright 2014 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package webdav
- // The XML encoding is covered by Section 14.
- // http://www.webdav.org/specs/rfc4918.html#xml.element.definitions
- import (
- "bytes"
- "encoding/xml"
- "fmt"
- "io"
- "net/http"
- "strconv"
- "time"
- )
- // http://www.webdav.org/specs/rfc4918.html#ELEMENT_lockinfo
- type lockInfo struct {
- XMLName xml.Name `xml:"lockinfo"`
- Exclusive *struct{} `xml:"lockscope>exclusive"`
- Shared *struct{} `xml:"lockscope>shared"`
- Write *struct{} `xml:"locktype>write"`
- Owner owner `xml:"owner"`
- }
- // http://www.webdav.org/specs/rfc4918.html#ELEMENT_owner
- type owner struct {
- InnerXML string `xml:",innerxml"`
- }
- func readLockInfo(r io.Reader) (li lockInfo, status int, err error) {
- c := &countingReader{r: r}
- if err = xml.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
- }
- err = errInvalidLockInfo
- }
- 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 li, 0, nil
- }
- type countingReader struct {
- n int
- r io.Reader
- }
- 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) {
- depth := "infinity"
- if d := ld.Depth; d >= 0 {
- depth = strconv.Itoa(d)
- }
- timeout := ld.Duration / time.Second
- return fmt.Fprintf(w, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"+
- "<D:prop xmlns:D=\"DAV:\"><D:lockdiscovery><D:activelock>\n"+
- " <D:locktype><D:write/></D:locktype>\n"+
- " <D:lockscope><D:exclusive/></D:lockscope>\n"+
- " <D:depth>%s</D:depth>\n"+
- " <D:owner>%s</D:owner>\n"+
- " <D:timeout>Second-%d</D:timeout>\n"+
- " <D:locktoken><D:href>%s</D:href></D:locktoken>\n"+
- " <D:lockroot><D:href>%s</D:href></D:lockroot>\n"+
- "</D:activelock></D:lockdiscovery></D:prop>",
- depth, ld.OwnerXML, timeout, escape(token), escape(ld.Path),
- )
- }
- func escape(s string) string {
- for i := 0; i < len(s); i++ {
- switch s[i] {
- case '"', '&', '\'', '<', '>':
- b := bytes.NewBuffer(nil)
- xml.EscapeText(b, []byte(s))
- return b.String()
- }
- }
- return s
- }
|