123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- package httpbinding
- import (
- "bytes"
- "fmt"
- )
- const (
- uriTokenStart = '{'
- uriTokenStop = '}'
- uriTokenSkip = '+'
- )
- func bufCap(b []byte, n int) []byte {
- if cap(b) < n {
- return make([]byte, 0, n)
- }
- return b[0:0]
- }
- // replacePathElement replaces a single element in the path []byte.
- // Escape is used to control whether the value will be escaped using Amazon path escape style.
- func replacePathElement(path, fieldBuf []byte, key, val string, escape bool) ([]byte, []byte, error) {
- fieldBuf = bufCap(fieldBuf, len(key)+3) // { <key> [+] }
- fieldBuf = append(fieldBuf, uriTokenStart)
- fieldBuf = append(fieldBuf, key...)
- start := bytes.Index(path, fieldBuf)
- end := start + len(fieldBuf)
- if start < 0 || len(path[end:]) == 0 {
- // TODO what to do about error?
- return path, fieldBuf, fmt.Errorf("invalid path index, start=%d,end=%d. %s", start, end, path)
- }
- encodeSep := true
- if path[end] == uriTokenSkip {
- // '+' token means do not escape slashes
- encodeSep = false
- end++
- }
- if escape {
- val = EscapePath(val, encodeSep)
- }
- if path[end] != uriTokenStop {
- return path, fieldBuf, fmt.Errorf("invalid path element, does not contain token stop, %s", path)
- }
- end++
- fieldBuf = bufCap(fieldBuf, len(val))
- fieldBuf = append(fieldBuf, val...)
- keyLen := end - start
- valLen := len(fieldBuf)
- if keyLen == valLen {
- copy(path[start:], fieldBuf)
- return path, fieldBuf, nil
- }
- newLen := len(path) + (valLen - keyLen)
- if len(path) < newLen {
- path = path[:cap(path)]
- }
- if cap(path) < newLen {
- newURI := make([]byte, newLen)
- copy(newURI, path)
- path = newURI
- }
- // shift
- copy(path[start+valLen:], path[end:])
- path = path[:newLen]
- copy(path[start:], fieldBuf)
- return path, fieldBuf, nil
- }
- // EscapePath escapes part of a URL path in Amazon style.
- func EscapePath(path string, encodeSep bool) string {
- var buf bytes.Buffer
- for i := 0; i < len(path); i++ {
- c := path[i]
- if noEscape[c] || (c == '/' && !encodeSep) {
- buf.WriteByte(c)
- } else {
- fmt.Fprintf(&buf, "%%%02X", c)
- }
- }
- return buf.String()
- }
- var noEscape [256]bool
- func init() {
- for i := 0; i < len(noEscape); i++ {
- // AWS expects every character except these to be escaped
- noEscape[i] = (i >= 'A' && i <= 'Z') ||
- (i >= 'a' && i <= 'z') ||
- (i >= '0' && i <= '9') ||
- i == '-' ||
- i == '.' ||
- i == '_' ||
- i == '~'
- }
- }
|