mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-26 13:43:47 +03:00
httpcaddyfile: Make global options pluggable (#3265)
* httpcaddyfile: Make global options pluggable * httpcaddyfile: Add a global options adapt test * httpcaddyfile: Wrap err Co-Authored-By: Dave Henderson <dhenderson@gmail.com> * httpcaddyfile: Revert wrap err Co-authored-by: Dave Henderson <dhenderson@gmail.com>
This commit is contained in:
parent
4c55d26f11
commit
dc9f4f13fc
4 changed files with 130 additions and 41 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
email test@example.com
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue