Vendor dependencies
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/aws/smithy-go"
|
||||
)
|
||||
|
||||
// Endpoint is the endpoint object returned by Endpoint resolution V2
|
||||
type Endpoint struct {
|
||||
// The complete URL minimally specifying the scheme and host.
|
||||
// May optionally specify the port and base path component.
|
||||
URI url.URL
|
||||
|
||||
// An optional set of headers to be sent using transport layer headers.
|
||||
Headers http.Header
|
||||
|
||||
// A grab-bag property map of endpoint attributes. The
|
||||
// values present here are subject to change, or being add/removed at any
|
||||
// time.
|
||||
Properties smithy.Properties
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package bdd
|
||||
|
||||
const resultOffset int32 = 100_000_000
|
||||
const intsPerNode = 3
|
||||
|
||||
// Evaluate traverses a compiled BDD node array and returns the result index.
|
||||
// nodes is a flat array of [condIdx, hi, lo] triples (1-indexed).
|
||||
// root is the root node reference. evalCond returns true/false for condition index.
|
||||
func Evaluate(nodes []int32, root int32, evalCond func(int) bool) int32 {
|
||||
ref := root
|
||||
for {
|
||||
if ref >= resultOffset {
|
||||
return ref - resultOffset
|
||||
}
|
||||
if ref == 1 || ref == -1 {
|
||||
return 0 // NoMatchRule
|
||||
}
|
||||
|
||||
complement := ref < 0
|
||||
nodeIdx := ref
|
||||
if complement {
|
||||
nodeIdx = -ref
|
||||
}
|
||||
base := (nodeIdx - 1) * intsPerNode
|
||||
condIdx := nodes[base]
|
||||
hi := nodes[base+1]
|
||||
lo := nodes[base+2]
|
||||
|
||||
if complement != evalCond(int(condIdx)) {
|
||||
ref = hi
|
||||
} else {
|
||||
ref = lo
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// Package rulesfn provides endpoint rule functions for evaluating endpoint
|
||||
// resolution rules.
|
||||
|
||||
package rulesfn
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package rulesfn
|
||||
|
||||
import "strings"
|
||||
|
||||
// Split splits the input string by the delimiter and returns the resulting
|
||||
// parts. If limit is > 0, at most limit substrings are returned.
|
||||
// Returns a slice with a single empty string if the input is empty.
|
||||
func Split(input, delimiter string, limit int) []string {
|
||||
if len(input) == 0 {
|
||||
return []string{""}
|
||||
}
|
||||
if limit > 0 {
|
||||
return strings.SplitN(input, delimiter, limit)
|
||||
}
|
||||
return strings.Split(input, delimiter)
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package rulesfn
|
||||
|
||||
// StringSlice is a string slice with a negative-index-aware Get method for use
|
||||
// in endpoint rule evaluation.
|
||||
type StringSlice []string
|
||||
|
||||
// Get returns a pointer to the string at index i, or nil if the index is out
|
||||
// of bounds. Negative indices count from the end of the slice.
|
||||
func (s StringSlice) Get(i int) *string {
|
||||
if i < 0 {
|
||||
i = len(s) + i
|
||||
}
|
||||
if i < 0 || i >= len(s) {
|
||||
return nil
|
||||
}
|
||||
v := s[i]
|
||||
return &v
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package rulesfn
|
||||
|
||||
// Substring returns the substring of the input provided. If the start or stop
|
||||
// indexes are not valid for the input nil will be returned. If errors occur
|
||||
// they will be added to the provided [ErrorCollector].
|
||||
func SubString(input string, start, stop int, reverse bool) *string {
|
||||
if start < 0 || stop < 1 || start >= stop || len(input) < stop {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, r := range input {
|
||||
if r > 127 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if !reverse {
|
||||
v := input[start:stop]
|
||||
return &v
|
||||
}
|
||||
|
||||
rStart := len(input) - stop
|
||||
rStop := len(input) - start
|
||||
return SubString(input, rStart, rStop, false)
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package rulesfn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
// IsValidHostLabel returns if the input is a single valid [RFC 1123] host
|
||||
// label. If allowSubDomains is true, will allow validation to include nested
|
||||
// host labels. Returns false if the input is not a valid host label. If errors
|
||||
// occur they will be added to the provided [ErrorCollector].
|
||||
//
|
||||
// [RFC 1123]: https://www.ietf.org/rfc/rfc1123.txt
|
||||
func IsValidHostLabel(input string, allowSubDomains bool) bool {
|
||||
var labels []string
|
||||
if allowSubDomains {
|
||||
labels = strings.Split(input, ".")
|
||||
} else {
|
||||
labels = []string{input}
|
||||
}
|
||||
|
||||
for _, label := range labels {
|
||||
if !smithyhttp.ValidHostLabel(label) {
|
||||
return false
|
||||
}
|
||||
if label[0] == '-' || label[len(label)-1] == '-' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ParseURL returns a [URL] if the provided string could be parsed. Returns nil
|
||||
// if the string could not be parsed. Any parsing error will be added to the
|
||||
// [ErrorCollector].
|
||||
//
|
||||
// If the input URL string contains an IP6 address with a zone index. The
|
||||
// returned [builtin.URL.Authority] value will contain the percent escaped (%)
|
||||
// zone index separator.
|
||||
func ParseURL(input string) *URL {
|
||||
u, err := url.Parse(input)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if u.RawQuery != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if u.Scheme != "http" && u.Scheme != "https" {
|
||||
return nil
|
||||
}
|
||||
|
||||
normalizedPath := u.Path
|
||||
if !strings.HasPrefix(normalizedPath, "/") {
|
||||
normalizedPath = "/" + normalizedPath
|
||||
}
|
||||
if !strings.HasSuffix(normalizedPath, "/") {
|
||||
normalizedPath = normalizedPath + "/"
|
||||
}
|
||||
|
||||
// IP6 hosts may have zone indexes that need to be escaped to be valid in a
|
||||
// URI. The Go URL parser will unescape the `%25` into `%`. This needs to
|
||||
// be reverted since the returned URL will be used in string builders.
|
||||
authority := strings.ReplaceAll(u.Host, "%", "%25")
|
||||
|
||||
return &URL{
|
||||
Scheme: u.Scheme,
|
||||
Authority: authority,
|
||||
Path: u.Path,
|
||||
NormalizedPath: normalizedPath,
|
||||
IsIp: net.ParseIP(hostnameWithoutZone(u)) != nil,
|
||||
}
|
||||
}
|
||||
|
||||
// URL provides the structure describing the parts of a parsed URL returned by
|
||||
// [ParseURL].
|
||||
type URL struct {
|
||||
Scheme string // https://www.rfc-editor.org/rfc/rfc3986#section-3.1
|
||||
Authority string // https://www.rfc-editor.org/rfc/rfc3986#section-3.2
|
||||
Path string // https://www.rfc-editor.org/rfc/rfc3986#section-3.3
|
||||
NormalizedPath string // https://www.rfc-editor.org/rfc/rfc3986#section-6.2.3
|
||||
IsIp bool
|
||||
}
|
||||
|
||||
// URIEncode returns an percent-encoded [RFC3986 section 2.1] version of the
|
||||
// input string.
|
||||
//
|
||||
// [RFC3986 section 2.1]: https://www.rfc-editor.org/rfc/rfc3986#section-2.1
|
||||
func URIEncode(input string) string {
|
||||
var output strings.Builder
|
||||
for _, c := range []byte(input) {
|
||||
if validPercentEncodedChar(c) {
|
||||
output.WriteByte(c)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(&output, "%%%X", c)
|
||||
}
|
||||
|
||||
return output.String()
|
||||
}
|
||||
|
||||
func validPercentEncodedChar(c byte) bool {
|
||||
return (c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
c == '-' || c == '_' || c == '.' || c == '~'
|
||||
}
|
||||
|
||||
// hostname implements u.Hostname() but strips the ipv6 zone ID (if present)
|
||||
// such that net.ParseIP can still recognize IPv6 addresses with zone IDs.
|
||||
//
|
||||
// FUTURE(10/2023): netip.ParseAddr handles this natively but we can't take
|
||||
// that package as a dependency yet due to our min go version (1.15, netip
|
||||
// starts in 1.18). When we align with go runtime deprecation policy in
|
||||
// 10/2023, we can remove this.
|
||||
func hostnameWithoutZone(u *url.URL) string {
|
||||
full := u.Hostname()
|
||||
|
||||
// this more or less mimics the internals of net/ (see unexported
|
||||
// splitHostZone in that source) but throws the zone away because we don't
|
||||
// need it
|
||||
if i := strings.LastIndex(full, "%"); i > -1 {
|
||||
return full[:i]
|
||||
}
|
||||
return full
|
||||
}
|
||||
Reference in New Issue
Block a user