summaryrefslogtreecommitdiff
path: root/caddyconfig/httpcaddyfile/shorthands.go
blob: 102bc36d6276bf59955148464aa8b1d8f24ad56d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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)
			}
		}
	}
}