aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--caddyconfig/httpcaddyfile/directives.go18
-rw-r--r--caddyconfig/httpcaddyfile/httptype.go39
-rw-r--r--caddyconfig/httpcaddyfile/options.go40
-rw-r--r--caddytest/integration/caddyfile_adapt_test.go74
4 files changed, 130 insertions, 41 deletions
diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go
index ac401e1fb..157877245 100644
--- a/caddyconfig/httpcaddyfile/directives.go
+++ b/caddyconfig/httpcaddyfile/directives.go
@@ -120,6 +120,17 @@ func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) {
})
}
+// RegisterGlobalOption registers a unique global option opt with
+// an associated unmarshaling (setup) function. When the global
+// option opt is encountered in a Caddyfile, setupFunc will be
+// called to unmarshal its tokens.
+func RegisterGlobalOption(opt string, setupFunc UnmarshalGlobalFunc) {
+ if _, ok := registeredGlobalOptions[opt]; ok {
+ panic("global option " + opt + " already registered")
+ }
+ registeredGlobalOptions[opt] = setupFunc
+}
+
// Helper is a type which helps setup a value from
// Caddyfile tokens.
type Helper struct {
@@ -454,6 +465,13 @@ type (
// for you. These are passed to a call to
// RegisterHandlerDirective.
UnmarshalHandlerFunc func(h Helper) (caddyhttp.MiddlewareHandler, error)
+
+ // UnmarshalGlobalFunc is a function which can unmarshal Caddyfile
+ // tokens into a global option config value using a Helper type.
+ // These are passed in a call to RegisterGlobalOption.
+ UnmarshalGlobalFunc func(d *caddyfile.Dispenser) (interface{}, error)
)
var registeredDirectives = make(map[string]UnmarshalFunc)
+
+var registeredGlobalOptions = make(map[string]UnmarshalGlobalFunc)
diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go
index aacaf9130..378289c39 100644
--- a/caddyconfig/httpcaddyfile/httptype.go
+++ b/caddyconfig/httpcaddyfile/httptype.go
@@ -284,39 +284,18 @@ func (ServerType) evaluateGlobalOptionsBlock(serverBlocks []serverBlock, options
var val interface{}
var err error
disp := caddyfile.NewDispenser(segment)
- switch dir {
- case "debug":
- val = true
- case "http_port":
- val, err = parseOptHTTPPort(disp)
- case "https_port":
- val, err = parseOptHTTPSPort(disp)
- case "default_sni":
- val, err = parseOptSingleString(disp)
- case "order":
- val, err = parseOptOrder(disp)
- case "experimental_http3":
- val, err = parseOptExperimentalHTTP3(disp)
- case "storage":
- val, err = parseOptStorage(disp)
- case "acme_ca", "acme_dns", "acme_ca_root":
- val, err = parseOptSingleString(disp)
- case "email":
- val, err = parseOptSingleString(disp)
- case "admin":
- val, err = parseOptAdmin(disp)
- case "on_demand_tls":
- val, err = parseOptOnDemand(disp)
- case "local_certs":
- val = true
- case "key_type":
- val, err = parseOptSingleString(disp)
- default:
- return nil, fmt.Errorf("unrecognized parameter name: %s", dir)
+
+ dirFunc, ok := registeredGlobalOptions[dir]
+ if !ok {
+ tkn := segment[0]
+ return nil, fmt.Errorf("%s:%d: unrecognized global option: %s", tkn.File, tkn.Line, dir)
}
+
+ val, err = dirFunc(disp)
if err != nil {
- return nil, fmt.Errorf("%s: %v", dir, err)
+ return nil, fmt.Errorf("parsing caddyfile tokens for '%s': %v", dir, err)
}
+
options[dir] = val
}
diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go
index 2ab73b24c..de288db91 100644
--- a/caddyconfig/httpcaddyfile/options.go
+++ b/caddyconfig/httpcaddyfile/options.go
@@ -23,7 +23,29 @@ import (
"github.com/caddyserver/caddy/v2/modules/caddytls"
)
-func parseOptHTTPPort(d *caddyfile.Dispenser) (int, error) {
+func init() {
+ RegisterGlobalOption("debug", parseOptTrue)
+ RegisterGlobalOption("http_port", parseOptHTTPPort)
+ RegisterGlobalOption("https_port", parseOptHTTPSPort)
+ RegisterGlobalOption("default_sni", parseOptSingleString)
+ RegisterGlobalOption("order", parseOptOrder)
+ RegisterGlobalOption("experimental_http3", parseOptTrue)
+ RegisterGlobalOption("storage", parseOptStorage)
+ RegisterGlobalOption("acme_ca", parseOptSingleString)
+ RegisterGlobalOption("acme_dns", parseOptSingleString)
+ RegisterGlobalOption("acme_ca_root", parseOptSingleString)
+ RegisterGlobalOption("email", parseOptSingleString)
+ RegisterGlobalOption("admin", parseOptAdmin)
+ RegisterGlobalOption("on_demand_tls", parseOptOnDemand)
+ RegisterGlobalOption("local_certs", parseOptTrue)
+ RegisterGlobalOption("key_type", parseOptSingleString)
+}
+
+func parseOptTrue(d *caddyfile.Dispenser) (interface{}, error) {
+ return true, nil
+}
+
+func parseOptHTTPPort(d *caddyfile.Dispenser) (interface{}, error) {
var httpPort int
for d.Next() {
var httpPortStr string
@@ -39,7 +61,7 @@ func parseOptHTTPPort(d *caddyfile.Dispenser) (int, error) {
return httpPort, nil
}
-func parseOptHTTPSPort(d *caddyfile.Dispenser) (int, error) {
+func parseOptHTTPSPort(d *caddyfile.Dispenser) (interface{}, error) {
var httpsPort int
for d.Next() {
var httpsPortStr string
@@ -55,11 +77,7 @@ func parseOptHTTPSPort(d *caddyfile.Dispenser) (int, error) {
return httpsPort, nil
}
-func parseOptExperimentalHTTP3(d *caddyfile.Dispenser) (bool, error) {
- return true, nil
-}
-
-func parseOptOrder(d *caddyfile.Dispenser) ([]string, error) {
+func parseOptOrder(d *caddyfile.Dispenser) (interface{}, error) {
newOrder := directiveOrder
for d.Next() {
@@ -135,7 +153,7 @@ func parseOptOrder(d *caddyfile.Dispenser) ([]string, error) {
return newOrder, nil
}
-func parseOptStorage(d *caddyfile.Dispenser) (caddy.StorageConverter, error) {
+func parseOptStorage(d *caddyfile.Dispenser) (interface{}, error) {
if !d.Next() { // consume option name
return nil, d.ArgErr()
}
@@ -162,7 +180,7 @@ func parseOptStorage(d *caddyfile.Dispenser) (caddy.StorageConverter, error) {
return storage, nil
}
-func parseOptSingleString(d *caddyfile.Dispenser) (string, error) {
+func parseOptSingleString(d *caddyfile.Dispenser) (interface{}, error) {
d.Next() // consume parameter name
if !d.Next() {
return "", d.ArgErr()
@@ -174,7 +192,7 @@ func parseOptSingleString(d *caddyfile.Dispenser) (string, error) {
return val, nil
}
-func parseOptAdmin(d *caddyfile.Dispenser) (string, error) {
+func parseOptAdmin(d *caddyfile.Dispenser) (interface{}, error) {
if d.Next() {
var listenAddress string
if !d.AllArgs(&listenAddress) {
@@ -188,7 +206,7 @@ func parseOptAdmin(d *caddyfile.Dispenser) (string, error) {
return "", nil
}
-func parseOptOnDemand(d *caddyfile.Dispenser) (*caddytls.OnDemandConfig, error) {
+func parseOptOnDemand(d *caddyfile.Dispenser) (interface{}, error) {
var ond *caddytls.OnDemandConfig
for d.Next() {
if d.NextArg() {
diff --git a/caddytest/integration/caddyfile_adapt_test.go b/caddytest/integration/caddyfile_adapt_test.go
index 514a5064c..c2ad892d1 100644
--- a/caddytest/integration/caddyfile_adapt_test.go
+++ b/caddytest/integration/caddyfile_adapt_test.go
@@ -415,3 +415,77 @@ func TestNotBlockMerging(t *testing.T) {
}
}`)
}
+
+func TestGlobalOptions(t *testing.T) {
+ caddytest.AssertAdapt(t, `
+ {
+ debug
+ http_port 8080
+ https_port 8443
+ default_sni localhost
+ order root first
+ storage file_system {
+ root /data
+ }
+ acme_ca https://example.com
+ acme_ca_root /path/to/ca.crt
+ admin off
+ on_demand_tls {
+ ask https://example.com
+ interval 30s
+ burst 20
+ }
+ local_certs
+ key_type ed25519
+ }
+
+ :80
+ `, "caddyfile", `{
+ "admin": {
+ "disabled": true
+ },
+ "logging": {
+ "logs": {
+ "default": {
+ "level": "DEBUG"
+ }
+ }
+ },
+ "storage": {
+ "module": "file_system",
+ "root": "/data"
+ },
+ "apps": {
+ "http": {
+ "http_port": 8080,
+ "https_port": 8443,
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":80"
+ ]
+ }
+ }
+ },
+ "tls": {
+ "automation": {
+ "policies": [
+ {
+ "issuer": {
+ "module": "internal"
+ }
+ }
+ ],
+ "on_demand": {
+ "rate_limit": {
+ "interval": 30000000000,
+ "burst": 20
+ },
+ "ask": "https://example.com"
+ }
+ }
+ }
+ }
+}`)
+}