...

Source file src/github.com/aws/smithy-go/encoding/httpbinding/path_replace.go

Documentation: github.com/aws/smithy-go/encoding/httpbinding

     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  // replacePathElement replaces a single element in the path []byte.
    23  // Escape is used to control whether the value will be escaped using Amazon path escape style.
    24  func replacePathElement(path, fieldBuf []byte, key, val string, escape bool) ([]byte, []byte, error) {
    25  	fieldBuf = bufCap(fieldBuf, len(key)+3) // { <key> [+] }
    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  		// TODO what to do about error?
    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  		// '+' token means do not escape slashes
    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  	// shift
    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  // EscapePath escapes part of a URL path in Amazon style.
    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  		// AWS expects every character except these to be escaped
   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