mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-10-31 10:37:24 -04: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
					
				| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user