@marcel91200 / caddy Mirror · read-only / commits / fe516575
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

core: Add ReplaceFunc method to Replacer to allow dynamic replacements

Matthew Holt committed Dec 17, 2019 at 16:29 UTC fe516575db3da5c0b9eba74b07066ecc22d90ba4
2 files changed +38 -13
replacer.go
+35 -10
@@ -27,10 +27,11 @@ import (
27 type Replacer interface {
28 Set(variable, value string)
29 Delete(variable string)
30 - Map(ReplacementFunc)
30 + Map(ReplacerFunc)
31 ReplaceAll(input, empty string) string
32 ReplaceKnown(input, empty string) string
33 ReplaceOrErr(input string, errOnEmpty, errOnUnknown bool) (string, error)
34 + ReplaceFunc(input string, f ReplacementFunc) (string, error)
35 }
36
37 // NewReplacer returns a new Replacer.
@@ -38,7 +39,7 @@ func NewReplacer() Replacer {
39 rep := &replacer{
40 static: make(map[string]string),
41 }
41 - rep.providers = []ReplacementFunc{
42 + rep.providers = []ReplacerFunc{
43 globalDefaultReplacements,
44 rep.fromStatic,
45 }
@@ -46,13 +47,13 @@ func NewReplacer() Replacer {
47 }
48
49 type replacer struct {
49 - providers []ReplacementFunc
50 + providers []ReplacerFunc
51 static map[string]string
52 }
53
54 // Map adds mapFunc to the list of value providers.
55 // mapFunc will be executed only at replace-time.
55 -func (r *replacer) Map(mapFunc ReplacementFunc) {
56 +func (r *replacer) Map(mapFunc ReplacerFunc) {
57 r.providers = append(r.providers, mapFunc)
58 }
59
@@ -77,14 +78,14 @@ func (r *replacer) fromStatic(key string) (val string, ok bool) {
78 // that are empty or not recognized will cause an error to
79 // be returned.
80 func (r *replacer) ReplaceOrErr(input string, errOnEmpty, errOnUnknown bool) (string, error) {
80 - return r.replace(input, "", false, errOnEmpty, errOnUnknown)
81 + return r.replace(input, "", false, errOnEmpty, errOnUnknown, nil)
82 }
83
84 // ReplaceKnown is like ReplaceAll but only replaces
85 // placeholders that are known (recognized). Unrecognized
86 // placeholders will remain in the output.
87 func (r *replacer) ReplaceKnown(input, empty string) string {
87 - out, _ := r.replace(input, empty, false, false, false)
88 + out, _ := r.replace(input, empty, false, false, false, nil)
89 return out
90 }
91
@@ -93,12 +94,21 @@ func (r *replacer) ReplaceKnown(input, empty string) string {
94 // whether they are recognized or not. Values that are empty
95 // string will be substituted with empty.
96 func (r *replacer) ReplaceAll(input, empty string) string {
96 - out, _ := r.replace(input, empty, true, false, false)
97 + out, _ := r.replace(input, empty, true, false, false, nil)
98 return out
99 }
100
101 +// ReplaceFunc calls ReplaceAll efficiently replaces placeholders in input with
102 +// their values. All placeholders are replaced in the output
103 +// whether they are recognized or not. Values that are empty
104 +// string will be substituted with empty.
105 +func (r *replacer) ReplaceFunc(input string, f ReplacementFunc) (string, error) {
106 + return r.replace(input, "", true, false, false, f)
107 +}
108 +
109 func (r *replacer) replace(input, empty string,
101 - treatUnknownAsEmpty, errOnEmpty, errOnUnknown bool) (string, error) {
110 + treatUnknownAsEmpty, errOnEmpty, errOnUnknown bool,
111 + f ReplacementFunc) (string, error) {
112 if !strings.Contains(input, string(phOpen)) {
113 return input, nil
114 }
@@ -134,6 +144,13 @@ func (r *replacer) replace(input, empty string,
144 for _, mapFunc := range r.providers {
145 if val, ok := mapFunc(key); ok {
146 found = true
147 + if f != nil {
148 + var err error
149 + val, err = f(key, val)
150 + if err != nil {
151 + return "", err
152 + }
153 + }
154 if val == "" {
155 if errOnEmpty {
156 return "", fmt.Errorf("evaluated placeholder %s%s%s is empty",
@@ -174,12 +191,12 @@ func (r *replacer) replace(input, empty string,
191 return sb.String(), nil
192 }
193
177 -// ReplacementFunc is a function that returns a replacement
194 +// ReplacerFunc is a function that returns a replacement
195 // for the given key along with true if the function is able
196 // to service that key (even if the value is blank). If the
197 // function does not recognize the key, false should be
198 // returned.
182 -type ReplacementFunc func(key string) (val string, ok bool)
199 +type ReplacerFunc func(key string) (val string, ok bool)
200
201 func globalDefaultReplacements(key string) (string, bool) {
202 // check environment variable
@@ -206,6 +223,14 @@ func globalDefaultReplacements(key string) (string, bool) {
223 return "", false
224 }
225
226 +// ReplacementFunc is a function that is called when a
227 +// replacement is being performed. It receives the
228 +// variable (i.e. placeholder name) and the value that
229 +// will be the replacement, and returns the value that
230 +// will actually be the replacement, or an error. Note
231 +// that errors are sometimes ignored by replacers.
232 +type ReplacementFunc func(variable, val string) (string, error)
233 +
234 // nowFunc is a variable so tests can change it
235 // in order to obtain a deterministic time.
236 var nowFunc = time.Now
replacer_test.go
+3 -3
@@ -133,7 +133,7 @@ func TestReplacerSet(t *testing.T) {
133
134 func TestReplacerReplaceKnown(t *testing.T) {
135 rep := replacer{
136 - providers: []ReplacementFunc{
136 + providers: []ReplacerFunc{
137 // split our possible vars to two functions (to test if both functions are called)
138 func(key string) (val string, ok bool) {
139 switch key {
@@ -239,7 +239,7 @@ func TestReplacerDelete(t *testing.T) {
239 func TestReplacerMap(t *testing.T) {
240 rep := testReplacer()
241
242 - for i, tc := range []ReplacementFunc{
242 + for i, tc := range []ReplacerFunc{
243 func(key string) (val string, ok bool) {
244 return "", false
245 },
@@ -317,7 +317,7 @@ func TestReplacerNew(t *testing.T) {
317
318 func testReplacer() replacer {
319 return replacer{
320 - providers: make([]ReplacementFunc, 0),
320 + providers: make([]ReplacerFunc, 0),
321 static: make(map[string]string),
322 }
323 }