Commit 0a501af1 authored by Geoff Simmons's avatar Geoff Simmons

Split the function maps used by the VCL templates.

parent 6121294a
......@@ -28,7 +28,11 @@
package vcl
import "text/template"
import (
"fmt"
"strings"
"text/template"
)
const aclTmplSrc = `
import std;
......@@ -70,5 +74,54 @@ sub vcl_recv {
const aclTmplName = "acl"
var aclTmpl = template.Must(template.New(aclTmplName).Funcs(fMap).
const (
xffFirst = `regsub(req.http.X-Forwarded-For,"^([^,\s]+).*","\1")`
xff2ndLast = `regsub(req.http.X-Forwarded-For,"^.*?([[:xdigit:]:.]+)\s*,[^,]*$","\1")`
)
func hasXFF(acls []ACL) bool {
for _, acl := range acls {
if strings.HasPrefix(acl.Comparand, "xff-") {
return true
}
}
return false
}
func aclCmp(comparand string) string {
if strings.HasPrefix(comparand, "xff-") ||
strings.HasPrefix(comparand, "req.http.") {
if comparand == "xff-first" {
comparand = xffFirst
} else if comparand == "xff-2ndlast" {
comparand = xff2ndLast
}
return fmt.Sprintf(`std.ip(%s, "0.0.0.0")`, comparand)
}
return comparand
}
func aclMask(bits uint8) string {
if bits > 128 {
return ""
}
return fmt.Sprintf("/%d", bits)
}
var aclFuncs = template.FuncMap{
"aclMask": func(bits uint8) string { return aclMask(bits) },
"hasXFF": func(acls []ACL) bool { return hasXFF(acls) },
"aclName": func(name string) string {
return mangle(name + "_acl")
},
"cmpRelation": func(cmp CompareType, negate bool) string {
return cmpRelation(cmp, negate)
},
"aclCmp": func(comparand string) string {
return aclCmp(comparand)
},
}
var aclTmpl = template.Must(template.New(aclTmplName).Funcs(aclFuncs).
Parse(aclTmplSrc))
......@@ -80,5 +80,14 @@ sub vcl_synth {
const authTmplName = "auth"
var authTmpl = template.Must(template.New(authTmplName).Funcs(fMap).
var authFuncs = template.FuncMap{
"credsMatcher": func(realm string) string {
return mangle(realm + "_auth")
},
"cmpRelation": func(cmp CompareType, negate bool) string {
return cmpRelation(cmp, negate)
},
}
var authTmpl = template.Must(template.New(authTmplName).Funcs(authFuncs).
Parse(authTmplSrc))
......@@ -28,7 +28,10 @@
package vcl
import "text/template"
import (
"fmt"
"text/template"
)
const reqDispTmplSrc = `
import re2;
......@@ -82,5 +85,47 @@ sub vcl_recv {
const reqDispTmplName = "request-disposition"
var reqDispTmpl = template.Must(template.New(reqDispTmplName).Funcs(fMap).
Parse(reqDispTmplSrc))
func reqNeedsMatcher(cond Condition) bool {
switch cond.Compare {
case Match, Prefix:
return true
case Exists, Greater, GreaterEqual, Less, LessEqual:
return false
}
if cond.Count != nil || len(cond.Values) == 1 {
return false
}
return true
}
func reqFlags(cond Condition) string {
return matcherFlags(cond.Compare != Match, cond.MatchFlags)
}
func reqValue(cond Condition) string {
if cond.Count != nil {
return fmt.Sprintf("%d", *cond.Count)
}
return `"` + cond.Values[0] + `"`
}
var reqDispFuncs = template.FuncMap{
"exists": func(cmp CompareType) bool { return cmp == Exists },
"match": func(cmp CompareType) string { return match(cmp) },
"needsCompile": func(cmp CompareType) bool { return cmp == Match },
"value": func(cond Condition) string { return reqValue(cond) },
"vmod": func(cmp CompareType) string { return vmod(cmp) },
"reqFlags": func(cond Condition) string { return reqFlags(cond) },
"cmpRelation": func(cmp CompareType, negate bool) string {
return cmpRelation(cmp, negate)
},
"reqNeedsMatcher": func(cond Condition) bool {
return reqNeedsMatcher(cond)
},
"reqObj": func(didx, cidx int) string {
return fmt.Sprintf("vk8s_reqdisp_%d_%d", didx, cidx)
},
}
var reqDispTmpl = template.Must(template.New(reqDispTmplName).
Funcs(reqDispFuncs).Parse(reqDispTmplSrc))
......@@ -28,7 +28,11 @@
package vcl
import "text/template"
import (
"fmt"
"strings"
"text/template"
)
const rewriteTmplSrc = `
import re2;
......@@ -88,5 +92,186 @@ sub vcl_{{rewrSub $r}} {
const rewriteTmplName = "rewrite"
var rewriteTmpl = template.Must(template.New(rewriteTmplName).Funcs(fMap).
Parse(rewriteTmplSrc))
func needsMatcher(rewr Rewrite) bool {
switch rewr.Method {
case Append, Prepend, Delete, Replace:
if len(rewr.Rules) == 0 ||
(len(rewr.Rules) == 1 && rewr.Rules[0].Value == "") {
return false
}
return true
default:
return true
}
}
func needsSave(rewr Rewrite) bool {
if rewr.Compare != Match {
return false
}
switch rewr.Method {
case Sub, Suball, RewriteMethod:
return true
default:
return false
}
}
func rewrName(i int) string {
return fmt.Sprintf("vk8s_rewrite_%d", i)
}
func rewrFlags(rewr Rewrite) string {
return matcherFlags(rewr.Compare != Match, rewr.MatchFlags)
}
func rewrSub(rewr Rewrite) string {
if rewr.VCLSub == Unspecified {
if strings.HasPrefix(rewr.Target, "resp") ||
strings.HasPrefix(rewr.Target, "resp") {
rewr.VCLSub = Deliver
} else if strings.HasPrefix(rewr.Target, "beresp") ||
strings.HasPrefix(rewr.Target, "beresp") {
rewr.VCLSub = BackendResponse
} else if strings.HasPrefix(rewr.Target, "req") {
rewr.VCLSub = Recv
} else {
rewr.VCLSub = BackendFetch
}
}
switch rewr.VCLSub {
case Recv:
return "recv"
case Pipe:
return "pipe"
case Pass:
return "pass"
case Hash:
return "hash"
case Purge:
return "purge"
case Miss:
return "miss"
case Hit:
return "hit"
case Deliver:
return "deliver"
case Synth:
return "synth"
case BackendFetch:
return "backend_fetch"
case BackendResponse:
return "backend_response"
case BackendError:
return "backend_error"
default:
return "__UNKNOWN_VCL_SUB__"
}
}
func rewrSelect(rewr Rewrite) string {
if rewr.Select == Unique {
return ""
}
return "select=" + rewr.Select.String()
}
func rewrOperand1(rewr Rewrite) string {
if len(rewr.Rules) == 0 {
return rewr.Target
}
return rewr.Source
}
func rewrOperand2(rewr Rewrite, i int) string {
if len(rewr.Rules) == 1 && rewr.Rules[0].Value == "" {
return `"` + rewr.Rules[0].Rewrite + `"`
}
if len(rewr.Rules) > 0 && rewr.Rules[0].Value != "" {
return rewrName(i) + ".string(" + rewrSelect(rewr) + ")"
}
return rewr.Source
}
func rewrOp(rewr Rewrite) string {
switch rewr.Method {
case Sub:
return "sub"
case Suball:
if rewr.Compare == Match {
return "suball"
}
return "sub"
case RewriteMethod:
return "extract"
default:
return "__INVALID_REWRITE_OPERAION__"
}
}
var rewriteFuncs = template.FuncMap{
"match": func(cmp CompareType) string { return match(cmp) },
"needsMatcher": func(rewr Rewrite) bool { return needsMatcher(rewr) },
"needsCompile": func(cmp CompareType) bool { return cmp == Match },
"needsSave": func(rewr Rewrite) bool { return needsSave(rewr) },
"rewrFlags": func(rewr Rewrite) string { return rewrFlags(rewr) },
"rewrSub": func(rewr Rewrite) string { return rewrSub(rewr) },
"rewrOp": func(rewr Rewrite) string { return rewrOp(rewr) },
"rewrSelect": func(rewr Rewrite) string { return rewrSelect(rewr) },
"rewrName": func(i int) string { return rewrName(i) },
"vmod": func(cmp CompareType) string { return vmod(cmp) },
"needsAll": func(rewr Rewrite) bool {
return rewr.Compare != Match && rewr.Method == Suball
},
"needsNeverCapture": func(rewr Rewrite) bool {
return rewr.Compare == Match && rewr.MatchFlags.NeverCapture
},
"needsRegex": func(rewr Rewrite) bool {
return rewr.Compare != Match &&
(rewr.Method == Sub || rewr.Method == Suball)
},
"needsUniqueCheck": func(rewr Rewrite) bool {
if rewr.Compare == Equal || rewr.Select != Unique {
return false
}
switch rewr.Method {
case Delete:
return false
case Sub, Suball, RewriteMethod:
return true
default:
return len(rewr.Rules) > 0 && rewr.Rules[0].Value != ""
}
},
"needsSelectEnum": func(rewr Rewrite) bool {
return rewr.Select != Unique
},
"rewrMethodAppend": func(rewr Rewrite) bool {
return rewr.Method == Append
},
"rewrMethodPrepend": func(rewr Rewrite) bool {
return rewr.Method == Prepend
},
"rewrMethodDelete": func(rewr Rewrite) bool {
return rewr.Method == Delete
},
"rewrMethodReplace": func(rewr Rewrite) bool {
return rewr.Method == Replace
},
"rewrOperand1": func(rewr Rewrite) string {
return rewrOperand1(rewr)
},
"rewrOperand2": func(rewr Rewrite, i int) string {
return rewrOperand2(rewr, i)
},
"saveRegex": func(rewr Rewrite, rule RewriteRule) string {
regex := `^\Q` + rule.Value + `\E`
if rewr.Compare == Prefix {
return regex
}
return regex + "$"
},
}
var rewriteTmpl = template.Must(template.New(rewriteTmplName).
Funcs(rewriteFuncs).Parse(rewriteTmplSrc))
......@@ -35,130 +35,8 @@ import (
"math/big"
"regexp"
"strings"
"text/template"
)
var fMap = template.FuncMap{
"plusOne": func(i int) int { return i + 1 },
"vclMangle": func(s string) string { return mangle(s) },
"aclMask": func(bits uint8) string { return aclMask(bits) },
"hasXFF": func(acls []ACL) bool { return hasXFF(acls) },
"dirType": func(svc Service) string { return dirType(svc) },
"rewrName": func(i int) string { return rewrName(i) },
"needsMatcher": func(rewr Rewrite) bool { return needsMatcher(rewr) },
"rewrFlags": func(rewr Rewrite) string { return rewrFlags(rewr) },
"needsSave": func(rewr Rewrite) bool { return needsSave(rewr) },
"rewrSub": func(rewr Rewrite) string { return rewrSub(rewr) },
"rewrOp": func(rewr Rewrite) string { return rewrOp(rewr) },
"rewrSelect": func(rewr Rewrite) string { return rewrSelect(rewr) },
"value": func(cond Condition) string { return reqValue(cond) },
"reqFlags": func(cond Condition) string { return reqFlags(cond) },
"needsCompile": func(cmp CompareType) bool { return cmp == Match },
"exists": func(cmp CompareType) bool { return cmp == Exists },
"match": func(cmp CompareType) string { return match(cmp) },
"vmod": func(cmp CompareType) string { return vmod(cmp) },
"aclCmp": func(comparand string) string {
return aclCmp(comparand)
},
"cmpRelation": func(cmp CompareType, negate bool) string {
return cmpRelation(cmp, negate)
},
"backendName": func(svc Service, addr string) string {
return backendName(svc, addr)
},
"dirName": func(svc Service) string {
return directorName(svc)
},
"resolverName": func(svc Service) string {
return resolverName(svc)
},
"urlMatcher": func(rule Rule) string {
return urlMatcher(rule)
},
"aclName": func(name string) string {
return mangle(name + "_acl")
},
"probeName": func(name string) string {
return mangle(name + "_probe")
},
"credsMatcher": func(realm string) string {
return mangle(realm + "_auth")
},
"rewrMethodAppend": func(rewr Rewrite) bool {
return rewr.Method == Append
},
"rewrMethodPrepend": func(rewr Rewrite) bool {
return rewr.Method == Prepend
},
"rewrMethodDelete": func(rewr Rewrite) bool {
return rewr.Method == Delete
},
"rewrMethodReplace": func(rewr Rewrite) bool {
return rewr.Method == Replace
},
"needsRegex": func(rewr Rewrite) bool {
return rewr.Compare != Match &&
(rewr.Method == Sub || rewr.Method == Suball)
},
"saveRegex": func(rewr Rewrite, rule RewriteRule) string {
regex := `^\Q` + rule.Value + `\E`
if rewr.Compare == Prefix {
return regex
}
return regex + "$"
},
"needsAll": func(rewr Rewrite) bool {
return rewr.Compare != Match && rewr.Method == Suball
},
"needsNeverCapture": func(rewr Rewrite) bool {
return rewr.Compare == Match && rewr.MatchFlags.NeverCapture
},
"rewrOperand1": func(rewr Rewrite) string {
return rewrOperand1(rewr)
},
"rewrOperand2": func(rewr Rewrite, i int) string {
return rewrOperand2(rewr, i)
},
"needsUniqueCheck": func(rewr Rewrite) bool {
if rewr.Compare == Equal || rewr.Select != Unique {
return false
}
switch rewr.Method {
case Delete:
return false
case Sub, Suball, RewriteMethod:
return true
default:
return len(rewr.Rules) > 0 && rewr.Rules[0].Value != ""
}
},
"needsSelectEnum": func(rewr Rewrite) bool {
return rewr.Select != Unique
},
"reqObj": func(didx, cidx int) string {
return fmt.Sprintf("vk8s_reqdisp_%d_%d", didx, cidx)
},
"reqNeedsMatcher": func(cond Condition) bool {
return reqNeedsMatcher(cond)
},
}
// maxSymLen is a workaround for Varnish issue #2880
// https://github.com/varnishcache/varnish-cache/issues/2880
// Will be unnecssary as of the March 2019 release
const maxSymLen = 46
var vclIllegal = regexp.MustCompile("[^[:word:]-]+")
func replIllegal(ill []byte) []byte {
repl := []byte("_")
for _, b := range ill {
repl = append(repl, []byte(fmt.Sprintf("%02x", b))...)
}
repl = append(repl, []byte("_")...)
return repl
}
// GetSrc returns the VCL generated to implement a Spec.
func (spec Spec) GetSrc() (string, error) {
var buf bytes.Buffer
......@@ -196,6 +74,25 @@ func (spec Spec) GetSrc() (string, error) {
return buf.String(), nil
}
// The following functions are re-used in the function maps of more
// than one template.
// maxSymLen is a workaround for Varnish issue #2880
// https://github.com/varnishcache/varnish-cache/issues/2880
// Will be unnecssary as of the March 2019 release
const maxSymLen = 46
var vclIllegal = regexp.MustCompile("[^[:word:]-]+")
func replIllegal(ill []byte) []byte {
repl := []byte("_")
for _, b := range ill {
repl = append(repl, []byte(fmt.Sprintf("%02x", b))...)
}
repl = append(repl, []byte("_")...)
return repl
}
func bound(s string, l int) string {
if len(s) <= l {
return s
......@@ -219,57 +116,6 @@ func mangle(s string) string {
return bound(string(mangled), maxSymLen)
}
func backendName(svc Service, addr string) string {
return mangle(svc.Name + "_" + strings.Replace(addr, ".", "_", -1))
}
func directorName(svc Service) string {
return mangle(svc.Name + "_director")
}
func resolverName(svc Service) string {
return mangle(svc.Name + "_resolver")
}
func urlMatcher(rule Rule) string {
return mangle(strings.Replace(rule.Host, ".", "_", -1) + "_url")
}
func aclMask(bits uint8) string {
if bits > 128 {
return ""
}
return fmt.Sprintf("/%d", bits)
}
const (
xffFirst = `regsub(req.http.X-Forwarded-For,"^([^,\s]+).*","\1")`
xff2ndLast = `regsub(req.http.X-Forwarded-For,"^.*?([[:xdigit:]:.]+)\s*,[^,]*$","\1")`
)
func aclCmp(comparand string) string {
if strings.HasPrefix(comparand, "xff-") ||
strings.HasPrefix(comparand, "req.http.") {
if comparand == "xff-first" {
comparand = xffFirst
} else if comparand == "xff-2ndlast" {
comparand = xff2ndLast
}
return fmt.Sprintf(`std.ip(%s, "0.0.0.0")`, comparand)
}
return comparand
}
func hasXFF(acls []ACL) bool {
for _, acl := range acls {
if strings.HasPrefix(acl.Comparand, "xff-") {
return true
}
}
return false
}
func cmpRelation(cmp CompareType, negate bool) string {
switch cmp {
case Equal:
......@@ -295,43 +141,6 @@ func cmpRelation(cmp CompareType, negate bool) string {
}
}
func dirType(svc Service) string {
if svc.Director == nil {
return RoundRobin.String()
}
return svc.Director.Type.String()
}
func needsMatcher(rewr Rewrite) bool {
switch rewr.Method {
case Append, Prepend, Delete, Replace:
if len(rewr.Rules) == 0 ||
(len(rewr.Rules) == 1 && rewr.Rules[0].Value == "") {
return false
}
return true
default:
return true
}
}
func reqNeedsMatcher(cond Condition) bool {
switch cond.Compare {
case Match, Prefix:
return true
case Exists, Greater, GreaterEqual, Less, LessEqual:
return false
}
if cond.Count != nil || len(cond.Values) == 1 {
return false
}
return true
}
func rewrName(i int) string {
return fmt.Sprintf("vk8s_rewrite_%d", i)
}
func vmod(cmp CompareType) string {
switch cmp {
case Equal, Prefix:
......@@ -388,94 +197,6 @@ func matcherFlags(isSelector bool, flagSpec MatchFlagsType) string {
return strings.Join(flags, ",")
}
func rewrFlags(rewr Rewrite) string {
return matcherFlags(rewr.Compare != Match, rewr.MatchFlags)
}
func reqFlags(cond Condition) string {
return matcherFlags(cond.Compare != Match, cond.MatchFlags)
}
func needsSave(rewr Rewrite) bool {
if rewr.Compare != Match {
return false
}
switch rewr.Method {
case Sub, Suball, RewriteMethod:
return true
default:
return false
}
}
func rewrSub(rewr Rewrite) string {
if rewr.VCLSub == Unspecified {
if strings.HasPrefix(rewr.Target, "resp") ||
strings.HasPrefix(rewr.Target, "resp") {
rewr.VCLSub = Deliver
} else if strings.HasPrefix(rewr.Target, "beresp") ||
strings.HasPrefix(rewr.Target, "beresp") {
rewr.VCLSub = BackendResponse
} else if strings.HasPrefix(rewr.Target, "req") {
rewr.VCLSub = Recv
} else {
rewr.VCLSub = BackendFetch
}
}
switch rewr.VCLSub {
case Recv:
return "recv"
case Pipe:
return "pipe"
case Pass:
return "pass"
case Hash:
return "hash"
case Purge:
return "purge"
case Miss:
return "miss"
case Hit:
return "hit"
case Deliver:
return "deliver"
case Synth:
return "synth"
case BackendFetch:
return "backend_fetch"
case BackendResponse:
return "backend_response"
case BackendError:
return "backend_error"
default:
return "__UNKNOWN_VCL_SUB__"
}
}
func rewrSelect(rewr Rewrite) string {
if rewr.Select == Unique {
return ""
}
return "select=" + rewr.Select.String()
}
func rewrOperand1(rewr Rewrite) string {
if len(rewr.Rules) == 0 {
return rewr.Target
}
return rewr.Source
}
func rewrOperand2(rewr Rewrite, i int) string {
if len(rewr.Rules) == 1 && rewr.Rules[0].Value == "" {
return `"` + rewr.Rules[0].Rewrite + `"`
}
if len(rewr.Rules) > 0 && rewr.Rules[0].Value != "" {
return rewrName(i) + ".string(" + rewrSelect(rewr) + ")"
}
return rewr.Source
}
func match(cmp CompareType) string {
switch cmp {
case Match, Equal:
......@@ -486,26 +207,3 @@ func match(cmp CompareType) string {
return "__INVALID_MATCH_OPERATION__"
}
}
func rewrOp(rewr Rewrite) string {
switch rewr.Method {
case Sub:
return "sub"
case Suball:
if rewr.Compare == Match {
return "suball"
}
return "sub"
case RewriteMethod:
return "extract"
default:
return "__INVALID_REWRITE_OPERAION__"
}
}
func reqValue(cond Condition) string {
if cond.Count != nil {
return fmt.Sprintf("%d", *cond.Count)
}
return `"` + cond.Values[0] + `"`
}
......@@ -28,7 +28,10 @@
package vcl
import "text/template"
import (
"strings"
"text/template"
)
const ingTmplSrc = `vcl 4.1;
......@@ -263,5 +266,40 @@ sub vcl_hit {
const ingTmplName = "vcl"
func dirType(svc Service) string {
if svc.Director == nil {
return RoundRobin.String()
}
return svc.Director.Type.String()
}
func backendName(svc Service, addr string) string {
return mangle(svc.Name + "_" + strings.Replace(addr, ".", "_", -1))
}
func urlMatcher(rule Rule) string {
return mangle(strings.Replace(rule.Host, ".", "_", -1) + "_url")
}
var vclFuncs = template.FuncMap{
"plusOne": func(i int) int { return i + 1 },
"dirType": func(svc Service) string { return dirType(svc) },
"probeName": func(name string) string {
return mangle(name + "_probe")
},
"backendName": func(svc Service, addr string) string {
return backendName(svc, addr)
},
"dirName": func(svc Service) string {
return mangle(svc.Name + "_director")
},
"resolverName": func(svc Service) string {
return mangle(svc.Name + "_resolver")
},
"urlMatcher": func(rule Rule) string {
return urlMatcher(rule)
},
}
var ingressTmpl = template.Must(template.New(ingTmplName).
Funcs(fMap).Parse(ingTmplSrc))
Funcs(vclFuncs).Parse(ingTmplSrc))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment