xml.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package webdav
  5. // The XML encoding is covered by Section 14.
  6. // http://www.webdav.org/specs/rfc4918.html#xml.element.definitions
  7. import (
  8. "bytes"
  9. "encoding/xml"
  10. "fmt"
  11. "io"
  12. "net/http"
  13. "strconv"
  14. "time"
  15. )
  16. // http://www.webdav.org/specs/rfc4918.html#ELEMENT_lockinfo
  17. type lockInfo struct {
  18. XMLName xml.Name `xml:"lockinfo"`
  19. Exclusive *struct{} `xml:"lockscope>exclusive"`
  20. Shared *struct{} `xml:"lockscope>shared"`
  21. Write *struct{} `xml:"locktype>write"`
  22. Owner owner `xml:"owner"`
  23. }
  24. // http://www.webdav.org/specs/rfc4918.html#ELEMENT_owner
  25. type owner struct {
  26. InnerXML string `xml:",innerxml"`
  27. }
  28. func readLockInfo(r io.Reader) (li lockInfo, status int, err error) {
  29. c := &countingReader{r: r}
  30. if err = xml.NewDecoder(c).Decode(&li); err != nil {
  31. if err == io.EOF {
  32. if c.n == 0 {
  33. // An empty body means to refresh the lock.
  34. // http://www.webdav.org/specs/rfc4918.html#refreshing-locks
  35. return lockInfo{}, 0, nil
  36. }
  37. err = errInvalidLockInfo
  38. }
  39. return lockInfo{}, http.StatusBadRequest, err
  40. }
  41. // We only support exclusive (non-shared) write locks. In practice, these are
  42. // the only types of locks that seem to matter.
  43. if li.Exclusive == nil || li.Shared != nil || li.Write == nil {
  44. return lockInfo{}, http.StatusNotImplemented, errUnsupportedLockInfo
  45. }
  46. return li, 0, nil
  47. }
  48. type countingReader struct {
  49. n int
  50. r io.Reader
  51. }
  52. func (c *countingReader) Read(p []byte) (int, error) {
  53. n, err := c.r.Read(p)
  54. c.n += n
  55. return n, err
  56. }
  57. func writeLockInfo(w io.Writer, token string, ld LockDetails) (int, error) {
  58. depth := "infinity"
  59. if d := ld.Depth; d >= 0 {
  60. depth = strconv.Itoa(d)
  61. }
  62. timeout := ld.Duration / time.Second
  63. return fmt.Fprintf(w, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"+
  64. "<D:prop xmlns:D=\"DAV:\"><D:lockdiscovery><D:activelock>\n"+
  65. " <D:locktype><D:write/></D:locktype>\n"+
  66. " <D:lockscope><D:exclusive/></D:lockscope>\n"+
  67. " <D:depth>%s</D:depth>\n"+
  68. " <D:owner>%s</D:owner>\n"+
  69. " <D:timeout>Second-%d</D:timeout>\n"+
  70. " <D:locktoken><D:href>%s</D:href></D:locktoken>\n"+
  71. " <D:lockroot><D:href>%s</D:href></D:lockroot>\n"+
  72. "</D:activelock></D:lockdiscovery></D:prop>",
  73. depth, ld.OwnerXML, timeout, escape(token), escape(ld.Path),
  74. )
  75. }
  76. func escape(s string) string {
  77. for i := 0; i < len(s); i++ {
  78. switch s[i] {
  79. case '"', '&', '\'', '<', '>':
  80. b := bytes.NewBuffer(nil)
  81. xml.EscapeText(b, []byte(s))
  82. return b.String()
  83. }
  84. }
  85. return s
  86. }