github.com/avenga/couper@v1.12.2/eval/lib/url.go (about) 1 package lib 2 3 import ( 4 "fmt" 5 "net/url" 6 "regexp" 7 "strings" 8 9 "github.com/zclconf/go-cty/cty" 10 "github.com/zclconf/go-cty/cty/function" 11 ) 12 13 var ( 14 // https://datatracker.ietf.org/doc/html/rfc3986#page-50 15 regexParseURL = regexp.MustCompile(`^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?`) 16 URLEncodeFunc = newURLEncodeFunction() 17 RelativeURLFunc = newRelativeURLFunction() 18 ) 19 20 func newURLEncodeFunction() function.Function { 21 return function.New(&function.Spec{ 22 Params: []function.Parameter{{ 23 Name: "s", 24 Type: cty.String, 25 }}, 26 Type: function.StaticReturnType(cty.String), 27 Impl: func(args []cty.Value, _ cty.Type) (ret cty.Value, err error) { 28 first := args[0] 29 result := strings.Replace(url.QueryEscape(first.AsString()), "+", "%20", -1) 30 return cty.StringVal(string(result)), nil 31 }, 32 }) 33 } 34 35 func AbsoluteURL(urlRef string, origin *url.URL) (string, error) { 36 u, err := url.Parse(urlRef) 37 if err != nil { 38 return "", err 39 } 40 41 if !u.IsAbs() { 42 return origin.ResolveReference(u).String(), nil 43 } 44 return urlRef, nil 45 } 46 47 func newRelativeURLFunction() function.Function { 48 return function.New(&function.Spec{ 49 Params: []function.Parameter{{ 50 Name: "s", 51 Type: cty.String, 52 }}, 53 Type: function.StaticReturnType(cty.String), 54 Impl: func(args []cty.Value, _ cty.Type) (ret cty.Value, err error) { 55 absURL := strings.TrimSpace(args[0].AsString()) 56 57 if !strings.HasPrefix(absURL, "/") && !strings.HasPrefix(absURL, "http://") && !strings.HasPrefix(absURL, "https://") { 58 return cty.StringVal(""), fmt.Errorf("invalid url given: %q", absURL) 59 } 60 61 // Do not use the result of url.Parse() to preserve the # character in an empty fragment. 62 if _, err := url.Parse(absURL); err != nil { 63 return cty.StringVal(""), err 64 } 65 66 // The regexParseURL garanties the len of 10 in the result. 67 urlParts := regexParseURL.FindStringSubmatch(absURL) 68 69 // The path must begin w/ a slash. 70 if !strings.HasPrefix(urlParts[5], "/") { 71 urlParts[5] = "/" + urlParts[5] 72 } 73 74 return cty.StringVal(urlParts[5] + urlParts[6] + urlParts[8]), nil 75 }, 76 }) 77 }