summaryrefslogtreecommitdiff
path: root/caddyconfig/httpcaddyfile/builtins.go
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-08-21 10:46:35 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2019-08-21 10:46:35 -0600
commitc9980fd3671d873a7197a5ac4d6ac9d6b046abb6 (patch)
tree75c301ab10590fb5f7d5b869a3424b8d46176bbf /caddyconfig/httpcaddyfile/builtins.go
parentc4159ef76d279d6a84257b24dbe97430af32eb1e (diff)
Refactor Caddyfile adapter and module registration
Use piles from which to draw config values. Module values can return their name, so now we can do two-way mapping from value to name and name to value; whereas before we could only map name to value. This was problematic with the Caddyfile adapter since it receives values and needs to know the name to put in the config.
Diffstat (limited to 'caddyconfig/httpcaddyfile/builtins.go')
-rw-r--r--caddyconfig/httpcaddyfile/builtins.go356
1 files changed, 177 insertions, 179 deletions
diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go
index 7e51e46..0fdfcd5 100644
--- a/caddyconfig/httpcaddyfile/builtins.go
+++ b/caddyconfig/httpcaddyfile/builtins.go
@@ -19,239 +19,237 @@ import (
"fmt"
"html"
"net/http"
+ "reflect"
- "github.com/caddyserver/caddy/v2/caddyconfig"
- "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
- "github.com/caddyserver/caddy/v2/modules/caddyhttp"
+ "github.com/caddyserver/caddy/caddyconfig"
+ "github.com/caddyserver/caddy/modules/caddyhttp"
"github.com/caddyserver/caddy/v2/modules/caddytls"
)
-func (st *ServerType) parseRoot(
- tkns []caddyfile.Token,
- matcherDefs map[string]map[string]json.RawMessage,
- warnings *[]caddyconfig.Warning,
-) ([]caddyhttp.Route, error) {
- var routes []caddyhttp.Route
-
- matchersAndTokens, err := st.tokensToMatcherSets(tkns, matcherDefs, warnings)
- if err != nil {
- return nil, err
- }
-
- for _, mst := range matchersAndTokens {
- d := caddyfile.NewDispenser("Caddyfile", mst.tokens)
-
- var root string
- for d.Next() {
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- root = d.Val()
- if d.NextArg() {
- return nil, d.ArgErr()
- }
- }
-
- varsHandler := caddyhttp.VarsMiddleware{"root": root}
- route := caddyhttp.Route{
- Handle: []json.RawMessage{
- caddyconfig.JSONModuleObject(varsHandler, "handler", "vars", warnings),
- },
- }
- if mst.matcherSet != nil {
- route.MatcherSets = []map[string]json.RawMessage{mst.matcherSet}
- }
+func init() {
+ RegisterDirective("bind", parseBind)
+ RegisterDirective("root", parseRoot)
+ RegisterDirective("tls", parseTLS)
+ RegisterHandlerDirective("redir", parseRedir)
+}
- routes = append(routes, route)
+func parseBind(h Helper) ([]ConfigValue, error) {
+ var lnHosts []string
+ for h.Next() {
+ lnHosts = append(lnHosts, h.RemainingArgs()...)
}
-
- return routes, nil
+ return h.NewBindAddresses(lnHosts), nil
}
-func (st *ServerType) parseRedir(
- tkns []caddyfile.Token,
- matcherDefs map[string]map[string]json.RawMessage,
- warnings *[]caddyconfig.Warning,
-) ([]caddyhttp.Route, error) {
- var routes []caddyhttp.Route
+func parseRoot(h Helper) ([]ConfigValue, error) {
+ if !h.Next() {
+ return nil, h.ArgErr()
+ }
- matchersAndTokens, err := st.tokensToMatcherSets(tkns, matcherDefs, warnings)
+ matcherSet, ok, err := h.MatcherToken()
if err != nil {
return nil, err
}
-
- for _, mst := range matchersAndTokens {
- var route caddyhttp.Route
-
- d := caddyfile.NewDispenser("Caddyfile", mst.tokens)
-
- for d.Next() {
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- to := d.Val()
-
- var code string
- if d.NextArg() {
- code = d.Val()
- }
- if code == "permanent" {
- code = "301"
- }
- if code == "temporary" || code == "" {
- code = "307"
- }
- var body string
- if code == "meta" {
- // Script tag comes first since that will better imitate a redirect in the browser's
- // history, but the meta tag is a fallback for most non-JS clients.
- const metaRedir = `<!DOCTYPE html>
-<html>
- <head>
- <title>Redirecting...</title>
- <script>window.location.replace("%s");</script>
- <meta http-equiv="refresh" content="0; URL='%s'">
- </head>
- <body>Redirecting to <a href="%s">%s</a>...</body>
-</html>
-`
- safeTo := html.EscapeString(to)
- body = fmt.Sprintf(metaRedir, safeTo, safeTo, safeTo, safeTo)
- }
-
- handler := caddyhttp.StaticResponse{
- StatusCode: caddyhttp.WeakString(code),
- Headers: http.Header{"Location": []string{to}},
- Body: body,
- }
-
- route.Handle = append(route.Handle,
- caddyconfig.JSONModuleObject(handler, "handler", "static_response", warnings))
- }
-
- if mst.matcherSet != nil {
- route.MatcherSets = []map[string]json.RawMessage{mst.matcherSet}
- }
-
- routes = append(routes, route)
+ if !ok {
+ // no matcher token; oops
+ h.Dispenser.Prev()
}
- return routes, nil
-}
-
-func (st *ServerType) parseTLSAutomationManager(d *caddyfile.Dispenser) (caddytls.ACMEManagerMaker, error) {
- var m caddytls.ACMEManagerMaker
-
- for d.Next() {
- firstLine := d.RemainingArgs()
- if len(firstLine) == 1 && firstLine[0] != "off" {
- m.Email = firstLine[0]
- }
-
- var hasBlock bool
- for d.NextBlock() {
- hasBlock = true
- switch d.Val() {
- case "ca":
- arg := d.RemainingArgs()
- if len(arg) != 1 {
- return m, d.ArgErr()
- }
- m.CA = arg[0]
- // TODO: other properties
- }
- }
+ if !h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ root := h.Val()
+ if h.NextArg() {
+ return nil, h.ArgErr()
+ }
- // a naked tls directive is not allowed
- if len(firstLine) == 0 && !hasBlock {
- return m, d.ArgErr()
- }
+ varsHandler := caddyhttp.VarsMiddleware{"root": root}
+ route := caddyhttp.Route{
+ HandlersRaw: []json.RawMessage{
+ caddyconfig.JSONModuleObject(varsHandler, "handler", "vars", nil),
+ },
+ }
+ if matcherSet != nil {
+ route.MatcherSetsRaw = []map[string]json.RawMessage{matcherSet}
}
- return m, nil
+ return h.NewVarsRoute(route), nil
}
-func (st *ServerType) parseTLSCerts(d *caddyfile.Dispenser) (map[string]caddytls.CertificateLoader, error) {
+func parseTLS(h Helper) ([]ConfigValue, error) {
+ var configVals []ConfigValue
+
+ cp := new(caddytls.ConnectionPolicy)
var fileLoader caddytls.FileLoader
var folderLoader caddytls.FolderLoader
-
- for d.Next() {
- // file loader
- firstLine := d.RemainingArgs()
- if len(firstLine) == 2 {
+ var mgr caddytls.ACMEManagerMaker
+ var off bool
+
+ for h.Next() {
+ // file certificate loader
+ firstLine := h.RemainingArgs()
+ switch len(firstLine) {
+ case 0:
+ case 1:
+ if firstLine[0] == "off" {
+ off = true
+ } else {
+ mgr.Email = firstLine[0]
+ }
+ case 2:
fileLoader = append(fileLoader, caddytls.CertKeyFilePair{
Certificate: firstLine[0],
Key: firstLine[1],
- // TODO: tags, for enterprise module's certificate selection
+ // TODO: add tags, for enterprise module's certificate selection
})
+ default:
+ return nil, h.ArgErr()
}
- // folder loader
- for d.NextBlock() {
- if d.Val() == "load" {
- folderLoader = append(folderLoader, d.RemainingArgs()...)
- }
- }
- }
-
- // put configured loaders into the map
- loaders := make(map[string]caddytls.CertificateLoader)
- if len(fileLoader) > 0 {
- loaders["load_files"] = fileLoader
- }
- if len(folderLoader) > 0 {
- loaders["load_folders"] = folderLoader
- }
-
- return loaders, nil
-}
+ var hasBlock bool
+ for h.NextBlock() {
+ hasBlock = true
-func (st *ServerType) parseTLSConnPolicy(d *caddyfile.Dispenser) (*caddytls.ConnectionPolicy, error) {
- cp := new(caddytls.ConnectionPolicy)
+ switch h.Val() {
- for d.Next() {
- for d.NextBlock() {
- switch d.Val() {
+ // connection policy
case "protocols":
- args := d.RemainingArgs()
+ args := h.RemainingArgs()
if len(args) == 0 {
- return nil, d.SyntaxErr("one or two protocols")
+ return nil, h.SyntaxErr("one or two protocols")
}
if len(args) > 0 {
if _, ok := caddytls.SupportedProtocols[args[0]]; !ok {
- return nil, d.Errf("Wrong protocol name or protocol not supported: '%s'", args[0])
+ return nil, h.Errf("Wrong protocol name or protocol not supported: '%s'", args[0])
}
cp.ProtocolMin = args[0]
}
if len(args) > 1 {
if _, ok := caddytls.SupportedProtocols[args[1]]; !ok {
- return nil, d.Errf("Wrong protocol name or protocol not supported: '%s'", args[1])
+ return nil, h.Errf("Wrong protocol name or protocol not supported: '%s'", args[1])
}
cp.ProtocolMax = args[1]
}
case "ciphers":
- for d.NextArg() {
- if _, ok := caddytls.SupportedCipherSuites[d.Val()]; !ok {
- return nil, d.Errf("Wrong cipher suite name or cipher suite not supported: '%s'", d.Val())
+ for h.NextArg() {
+ if _, ok := caddytls.SupportedCipherSuites[h.Val()]; !ok {
+ return nil, h.Errf("Wrong cipher suite name or cipher suite not supported: '%s'", h.Val())
}
- cp.CipherSuites = append(cp.CipherSuites, d.Val())
+ cp.CipherSuites = append(cp.CipherSuites, h.Val())
}
case "curves":
- for d.NextArg() {
- if _, ok := caddytls.SupportedCurves[d.Val()]; !ok {
- return nil, d.Errf("Wrong curve name or curve not supported: '%s'", d.Val())
+ for h.NextArg() {
+ if _, ok := caddytls.SupportedCurves[h.Val()]; !ok {
+ return nil, h.Errf("Wrong curve name or curve not supported: '%s'", h.Val())
}
- cp.Curves = append(cp.Curves, d.Val())
+ cp.Curves = append(cp.Curves, h.Val())
}
case "alpn":
- args := d.RemainingArgs()
+ args := h.RemainingArgs()
if len(args) == 0 {
- return nil, d.ArgErr()
+ return nil, h.ArgErr()
}
cp.ALPN = args
+
+ // certificate folder loader
+ case "load":
+ folderLoader = append(folderLoader, h.RemainingArgs()...)
+
+ // automation policy
+ case "ca":
+ arg := h.RemainingArgs()
+ if len(arg) != 1 {
+ return nil, h.ArgErr()
+ }
+ mgr.CA = arg[0]
+
+ // TODO: other properties for automation manager
}
}
+
+ // a naked tls directive is not allowed
+ if len(firstLine) == 0 && !hasBlock {
+ return nil, h.ArgErr()
+ }
+ }
+
+ // connection policy
+ configVals = append(configVals, ConfigValue{
+ Class: "tls.connection_policy",
+ Value: cp,
+ })
+
+ // certificate loaders
+ if len(fileLoader) > 0 {
+ configVals = append(configVals, ConfigValue{
+ Class: "tls.certificate_loader",
+ Value: fileLoader,
+ })
+ }
+ if len(folderLoader) > 0 {
+ configVals = append(configVals, ConfigValue{
+ Class: "tls.certificate_loader",
+ Value: folderLoader,
+ })
+ }
+
+ // automation policy
+ if off {
+ configVals = append(configVals, ConfigValue{
+ Class: "tls.off",
+ Value: true,
+ })
+ } else if !reflect.DeepEqual(mgr, caddytls.ACMEManagerMaker{}) {
+ configVals = append(configVals, ConfigValue{
+ Class: "tls.automation_manager",
+ Value: mgr,
+ })
+ }
+
+ return configVals, nil
+}
+
+func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
+ if !h.Next() {
+ return nil, h.ArgErr()
+ }
+
+ if !h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ to := h.Val()
+
+ var code string
+ if h.NextArg() {
+ code = h.Val()
+ }
+ if code == "permanent" {
+ code = "301"
+ }
+ if code == "temporary" || code == "" {
+ code = "307"
+ }
+ var body string
+ if code == "meta" {
+ // Script tag comes first since that will better imitate a redirect in the browser's
+ // history, but the meta tag is a fallback for most non-JS clients.
+ const metaRedir = `<!DOCTYPE html>
+<html>
+ <head>
+ <title>Redirecting...</title>
+ <script>window.location.replace("%s");</script>
+ <meta http-equiv="refresh" content="0; URL='%s'">
+ </head>
+ <body>Redirecting to <a href="%s">%s</a>...</body>
+</html>
+`
+ safeTo := html.EscapeString(to)
+ body = fmt.Sprintf(metaRedir, safeTo, safeTo, safeTo, safeTo)
}
- return cp, nil
+ return caddyhttp.StaticResponse{
+ StatusCode: caddyhttp.WeakString(code),
+ Headers: http.Header{"Location": []string{to}},
+ Body: body,
+ }, nil
}