summaryrefslogtreecommitdiff
path: root/caddyconfig
diff options
context:
space:
mode:
authorĐỗ Trọng Hải <41283691+hainenber@users.noreply.github.com>2023-09-09 01:38:44 +0700
committerGitHub <noreply@github.com>2023-09-08 14:38:44 -0400
commit2cac3c5491e6428441ecf668cc4f5a86e67ed9b3 (patch)
tree6733b3808bbf088bfc8fa8d3b8e255ce0c4adb58 /caddyconfig
parentf2ab7099db6d8386299796e6eef8e30f65b21bcc (diff)
httpcaddyfile: fix placeholder shorthands in named routes (#5791)
Co-authored-by: Francis Lavoie <lavofr@gmail.com>
Diffstat (limited to 'caddyconfig')
-rw-r--r--caddyconfig/httpcaddyfile/httptype.go86
-rw-r--r--caddyconfig/httpcaddyfile/shorthands.go92
2 files changed, 107 insertions, 71 deletions
diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go
index 6fa5a9f..78fb7f0 100644
--- a/caddyconfig/httpcaddyfile/httptype.go
+++ b/caddyconfig/httpcaddyfile/httptype.go
@@ -18,7 +18,6 @@ import (
"encoding/json"
"fmt"
"reflect"
- "regexp"
"sort"
"strconv"
"strings"
@@ -82,46 +81,18 @@ func (st ServerType) Setup(
return nil, warnings, err
}
- originalServerBlocks, err = st.extractNamedRoutes(originalServerBlocks, options, &warnings)
+ // this will replace both static and user-defined placeholder shorthands
+ // with actual identifiers used by Caddy
+ replacer := NewShorthandReplacer()
+
+ originalServerBlocks, err = st.extractNamedRoutes(originalServerBlocks, options, &warnings, replacer)
if err != nil {
return nil, warnings, err
}
- // replace shorthand placeholders (which are convenient
- // when writing a Caddyfile) with their actual placeholder
- // identifiers or variable names
- replacer := strings.NewReplacer(placeholderShorthands()...)
-
- // these are placeholders that allow a user-defined final
- // parameters, but we still want to provide a shorthand
- // for those, so we use a regexp to replace
- regexpReplacements := []struct {
- search *regexp.Regexp
- replace string
- }{
- {regexp.MustCompile(`{header\.([\w-]*)}`), "{http.request.header.$1}"},
- {regexp.MustCompile(`{cookie\.([\w-]*)}`), "{http.request.cookie.$1}"},
- {regexp.MustCompile(`{labels\.([\w-]*)}`), "{http.request.host.labels.$1}"},
- {regexp.MustCompile(`{path\.([\w-]*)}`), "{http.request.uri.path.$1}"},
- {regexp.MustCompile(`{file\.([\w-]*)}`), "{http.request.uri.path.file.$1}"},
- {regexp.MustCompile(`{query\.([\w-]*)}`), "{http.request.uri.query.$1}"},
- {regexp.MustCompile(`{re\.([\w-]*)\.([\w-]*)}`), "{http.regexp.$1.$2}"},
- {regexp.MustCompile(`{vars\.([\w-]*)}`), "{http.vars.$1}"},
- {regexp.MustCompile(`{rp\.([\w-\.]*)}`), "{http.reverse_proxy.$1}"},
- {regexp.MustCompile(`{err\.([\w-\.]*)}`), "{http.error.$1}"},
- {regexp.MustCompile(`{file_match\.([\w-]*)}`), "{http.matchers.file.$1}"},
- }
-
for _, sb := range originalServerBlocks {
- for _, segment := range sb.block.Segments {
- for i := 0; i < len(segment); i++ {
- // simple string replacements
- segment[i].Text = replacer.Replace(segment[i].Text)
- // complex regexp replacements
- for _, r := range regexpReplacements {
- segment[i].Text = r.search.ReplaceAllString(segment[i].Text, r.replace)
- }
- }
+ for i := range sb.block.Segments {
+ replacer.ApplyToSegment(&sb.block.Segments[i])
}
if len(sb.block.Keys) == 0 {
@@ -452,6 +423,7 @@ func (ServerType) extractNamedRoutes(
serverBlocks []serverBlock,
options map[string]any,
warnings *[]caddyconfig.Warning,
+ replacer ShorthandReplacer,
) ([]serverBlock, error) {
namedRoutes := map[string]*caddyhttp.Route{}
@@ -477,11 +449,14 @@ func (ServerType) extractNamedRoutes(
continue
}
- // zip up all the segments since ParseSegmentAsSubroute
- // was designed to take a directive+
wholeSegment := caddyfile.Segment{}
- for _, segment := range sb.block.Segments {
- wholeSegment = append(wholeSegment, segment...)
+ for i := range sb.block.Segments {
+ // replace user-defined placeholder shorthands in extracted named routes
+ replacer.ApplyToSegment(&sb.block.Segments[i])
+
+ // zip up all the segments since ParseSegmentAsSubroute
+ // was designed to take a directive+
+ wholeSegment = append(wholeSegment, sb.block.Segments[i]...)
}
h := Helper{
@@ -1449,37 +1424,6 @@ func encodeMatcherSet(matchers map[string]caddyhttp.RequestMatcher) (caddy.Modul
return msEncoded, nil
}
-// placeholderShorthands returns a slice of old-new string pairs,
-// where the left of the pair is a placeholder shorthand that may
-// be used in the Caddyfile, and the right is the replacement.
-func placeholderShorthands() []string {
- return []string{
- "{dir}", "{http.request.uri.path.dir}",
- "{file}", "{http.request.uri.path.file}",
- "{host}", "{http.request.host}",
- "{hostport}", "{http.request.hostport}",
- "{port}", "{http.request.port}",
- "{method}", "{http.request.method}",
- "{path}", "{http.request.uri.path}",
- "{query}", "{http.request.uri.query}",
- "{remote}", "{http.request.remote}",
- "{remote_host}", "{http.request.remote.host}",
- "{remote_port}", "{http.request.remote.port}",
- "{scheme}", "{http.request.scheme}",
- "{uri}", "{http.request.uri}",
- "{tls_cipher}", "{http.request.tls.cipher_suite}",
- "{tls_version}", "{http.request.tls.version}",
- "{tls_client_fingerprint}", "{http.request.tls.client.fingerprint}",
- "{tls_client_issuer}", "{http.request.tls.client.issuer}",
- "{tls_client_serial}", "{http.request.tls.client.serial}",
- "{tls_client_subject}", "{http.request.tls.client.subject}",
- "{tls_client_certificate_pem}", "{http.request.tls.client.certificate_pem}",
- "{tls_client_certificate_der_base64}", "{http.request.tls.client.certificate_der_base64}",
- "{upstream_hostport}", "{http.reverse_proxy.upstream.hostport}",
- "{client_ip}", "{http.vars.client_ip}",
- }
-}
-
// WasReplacedPlaceholderShorthand checks if a token string was
// likely a replaced shorthand of the known Caddyfile placeholder
// replacement outputs. Useful to prevent some user-defined map
diff --git a/caddyconfig/httpcaddyfile/shorthands.go b/caddyconfig/httpcaddyfile/shorthands.go
new file mode 100644
index 0000000..102bc36
--- /dev/null
+++ b/caddyconfig/httpcaddyfile/shorthands.go
@@ -0,0 +1,92 @@
+package httpcaddyfile
+
+import (
+ "regexp"
+ "strings"
+
+ "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
+)
+
+type ComplexShorthandReplacer struct {
+ search *regexp.Regexp
+ replace string
+}
+
+type ShorthandReplacer struct {
+ complex []ComplexShorthandReplacer
+ simple *strings.Replacer
+}
+
+func NewShorthandReplacer() ShorthandReplacer {
+ // replace shorthand placeholders (which are convenient
+ // when writing a Caddyfile) with their actual placeholder
+ // identifiers or variable names
+ replacer := strings.NewReplacer(placeholderShorthands()...)
+
+ // these are placeholders that allow a user-defined final
+ // parameters, but we still want to provide a shorthand
+ // for those, so we use a regexp to replace
+ regexpReplacements := []ComplexShorthandReplacer{
+ {regexp.MustCompile(`{header\.([\w-]*)}`), "{http.request.header.$1}"},
+ {regexp.MustCompile(`{cookie\.([\w-]*)}`), "{http.request.cookie.$1}"},
+ {regexp.MustCompile(`{labels\.([\w-]*)}`), "{http.request.host.labels.$1}"},
+ {regexp.MustCompile(`{path\.([\w-]*)}`), "{http.request.uri.path.$1}"},
+ {regexp.MustCompile(`{file\.([\w-]*)}`), "{http.request.uri.path.file.$1}"},
+ {regexp.MustCompile(`{query\.([\w-]*)}`), "{http.request.uri.query.$1}"},
+ {regexp.MustCompile(`{re\.([\w-]*)\.([\w-]*)}`), "{http.regexp.$1.$2}"},
+ {regexp.MustCompile(`{vars\.([\w-]*)}`), "{http.vars.$1}"},
+ {regexp.MustCompile(`{rp\.([\w-\.]*)}`), "{http.reverse_proxy.$1}"},
+ {regexp.MustCompile(`{err\.([\w-\.]*)}`), "{http.error.$1}"},
+ {regexp.MustCompile(`{file_match\.([\w-]*)}`), "{http.matchers.file.$1}"},
+ }
+
+ return ShorthandReplacer{
+ complex: regexpReplacements,
+ simple: replacer,
+ }
+}
+
+// placeholderShorthands returns a slice of old-new string pairs,
+// where the left of the pair is a placeholder shorthand that may
+// be used in the Caddyfile, and the right is the replacement.
+func placeholderShorthands() []string {
+ return []string{
+ "{dir}", "{http.request.uri.path.dir}",
+ "{file}", "{http.request.uri.path.file}",
+ "{host}", "{http.request.host}",
+ "{hostport}", "{http.request.hostport}",
+ "{port}", "{http.request.port}",
+ "{method}", "{http.request.method}",
+ "{path}", "{http.request.uri.path}",
+ "{query}", "{http.request.uri.query}",
+ "{remote}", "{http.request.remote}",
+ "{remote_host}", "{http.request.remote.host}",
+ "{remote_port}", "{http.request.remote.port}",
+ "{scheme}", "{http.request.scheme}",
+ "{uri}", "{http.request.uri}",
+ "{tls_cipher}", "{http.request.tls.cipher_suite}",
+ "{tls_version}", "{http.request.tls.version}",
+ "{tls_client_fingerprint}", "{http.request.tls.client.fingerprint}",
+ "{tls_client_issuer}", "{http.request.tls.client.issuer}",
+ "{tls_client_serial}", "{http.request.tls.client.serial}",
+ "{tls_client_subject}", "{http.request.tls.client.subject}",
+ "{tls_client_certificate_pem}", "{http.request.tls.client.certificate_pem}",
+ "{tls_client_certificate_der_base64}", "{http.request.tls.client.certificate_der_base64}",
+ "{upstream_hostport}", "{http.reverse_proxy.upstream.hostport}",
+ "{client_ip}", "{http.vars.client_ip}",
+ }
+}
+
+// ApplyToSegment replaces shorthand placeholder to its full placeholder, understandable by Caddy.
+func (s ShorthandReplacer) ApplyToSegment(segment *caddyfile.Segment) {
+ if segment != nil {
+ for i := 0; i < len(*segment); i++ {
+ // simple string replacements
+ (*segment)[i].Text = s.simple.Replace((*segment)[i].Text)
+ // complex regexp replacements
+ for _, r := range s.complex {
+ (*segment)[i].Text = r.search.ReplaceAllString((*segment)[i].Text, r.replace)
+ }
+ }
+ }
+}