...
1 package httpbinding
2
3 import (
4 "bytes"
5 "fmt"
6 )
7
8 const (
9 uriTokenStart = '{'
10 uriTokenStop = '}'
11 uriTokenSkip = '+'
12 )
13
14 func bufCap(b []byte, n int) []byte {
15 if cap(b) < n {
16 return make([]byte, 0, n)
17 }
18
19 return b[0:0]
20 }
21
22
23
24 func replacePathElement(path, fieldBuf []byte, key, val string, escape bool) ([]byte, []byte, error) {
25 fieldBuf = bufCap(fieldBuf, len(key)+3)
26 fieldBuf = append(fieldBuf, uriTokenStart)
27 fieldBuf = append(fieldBuf, key...)
28
29 start := bytes.Index(path, fieldBuf)
30 end := start + len(fieldBuf)
31 if start < 0 || len(path[end:]) == 0 {
32
33 return path, fieldBuf, fmt.Errorf("invalid path index, start=%d,end=%d. %s", start, end, path)
34 }
35
36 encodeSep := true
37 if path[end] == uriTokenSkip {
38
39 encodeSep = false
40 end++
41 }
42
43 if escape {
44 val = EscapePath(val, encodeSep)
45 }
46
47 if path[end] != uriTokenStop {
48 return path, fieldBuf, fmt.Errorf("invalid path element, does not contain token stop, %s", path)
49 }
50 end++
51
52 fieldBuf = bufCap(fieldBuf, len(val))
53 fieldBuf = append(fieldBuf, val...)
54
55 keyLen := end - start
56 valLen := len(fieldBuf)
57
58 if keyLen == valLen {
59 copy(path[start:], fieldBuf)
60 return path, fieldBuf, nil
61 }
62
63 newLen := len(path) + (valLen - keyLen)
64 if len(path) < newLen {
65 path = path[:cap(path)]
66 }
67 if cap(path) < newLen {
68 newURI := make([]byte, newLen)
69 copy(newURI, path)
70 path = newURI
71 }
72
73
74 copy(path[start+valLen:], path[end:])
75 path = path[:newLen]
76 copy(path[start:], fieldBuf)
77
78 return path, fieldBuf, nil
79 }
80
81
82 func EscapePath(path string, encodeSep bool) string {
83 var buf bytes.Buffer
84 for i := 0; i < len(path); i++ {
85 c := path[i]
86 if noEscape[c] || (c == '/' && !encodeSep) {
87 buf.WriteByte(c)
88 } else {
89 fmt.Fprintf(&buf, "%%%02X", c)
90 }
91 }
92 return buf.String()
93 }
94
95 var noEscape [256]bool
96
97 func init() {
98 for i := 0; i < len(noEscape); i++ {
99
100 noEscape[i] = (i >= 'A' && i <= 'Z') ||
101 (i >= 'a' && i <= 'z') ||
102 (i >= '0' && i <= '9') ||
103 i == '-' ||
104 i == '.' ||
105 i == '_' ||
106 i == '~'
107 }
108 }
109
View as plain text