mirror of
https://github.com/caddyserver/caddy.git
synced 2025-03-10 15:48:58 +01:00
httpcaddyfile: Refactor global options parsing; prevent duplicate keys
This commit is contained in:
parent
bf776e7de7
commit
bc2e406572
1 changed files with 63 additions and 36 deletions
|
@ -43,49 +43,31 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
||||||
var warnings []caddyconfig.Warning
|
var warnings []caddyconfig.Warning
|
||||||
gc := counter{new(int)}
|
gc := counter{new(int)}
|
||||||
|
|
||||||
|
// load all the server blocks and associate them with a "pile"
|
||||||
|
// of config values; also prohibit duplicate keys because they
|
||||||
|
// can make a config confusing if more than one server block is
|
||||||
|
// chosen to handle a request - we actually will make each
|
||||||
|
// server block's route terminal so that only one will run
|
||||||
|
sbKeys := make(map[string]struct{})
|
||||||
var serverBlocks []serverBlock
|
var serverBlocks []serverBlock
|
||||||
for _, sblock := range originalServerBlocks {
|
for i, sblock := range originalServerBlocks {
|
||||||
|
for j, k := range sblock.Keys {
|
||||||
|
if _, ok := sbKeys[k]; ok {
|
||||||
|
return nil, warnings, fmt.Errorf("duplicate site address not allowed: '%s' in %v (site block %d, key %d)", k, sblock.Keys, i, j)
|
||||||
|
}
|
||||||
|
sbKeys[k] = struct{}{}
|
||||||
|
}
|
||||||
serverBlocks = append(serverBlocks, serverBlock{
|
serverBlocks = append(serverBlocks, serverBlock{
|
||||||
block: sblock,
|
block: sblock,
|
||||||
pile: make(map[string][]ConfigValue),
|
pile: make(map[string][]ConfigValue),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// global configuration
|
// apply any global options
|
||||||
if len(serverBlocks) > 0 && len(serverBlocks[0].block.Keys) == 0 {
|
|
||||||
sb := serverBlocks[0]
|
|
||||||
for _, segment := range sb.block.Segments {
|
|
||||||
dir := segment.Directive()
|
|
||||||
var val interface{}
|
|
||||||
var err error
|
var err error
|
||||||
disp := caddyfile.NewDispenser(segment)
|
serverBlocks, err = st.evaluateGlobalOptionsBlock(serverBlocks, options)
|
||||||
// TODO: make this switch into a map
|
|
||||||
switch dir {
|
|
||||||
case "http_port":
|
|
||||||
val, err = parseOptHTTPPort(disp)
|
|
||||||
case "https_port":
|
|
||||||
val, err = parseOptHTTPSPort(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 = parseOptACME(disp)
|
|
||||||
case "email":
|
|
||||||
val, err = parseOptEmail(disp)
|
|
||||||
case "admin":
|
|
||||||
val, err = parseOptAdmin(disp)
|
|
||||||
default:
|
|
||||||
return nil, warnings, fmt.Errorf("unrecognized parameter name: %s", dir)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, warnings, fmt.Errorf("%s: %v", dir, err)
|
return nil, warnings, err
|
||||||
}
|
|
||||||
options[dir] = val
|
|
||||||
}
|
|
||||||
serverBlocks = serverBlocks[1:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, sb := range serverBlocks {
|
for _, sb := range serverBlocks {
|
||||||
|
@ -129,6 +111,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// evaluate each directive ("segment") in this block
|
||||||
for _, segment := range sb.block.Segments {
|
for _, segment := range sb.block.Segments {
|
||||||
dir := segment.Directive()
|
dir := segment.Directive()
|
||||||
|
|
||||||
|
@ -288,6 +271,50 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
||||||
return cfg, warnings, nil
|
return cfg, warnings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// evaluateGlobalOptionsBlock evaluates the global options block,
|
||||||
|
// which is expected to be the first server block if it has zero
|
||||||
|
// keys. It returns the updated list of server blocks with the
|
||||||
|
// global options block removed, and updates options accordingly.
|
||||||
|
func (ServerType) evaluateGlobalOptionsBlock(serverBlocks []serverBlock, options map[string]interface{}) ([]serverBlock, error) {
|
||||||
|
if len(serverBlocks) == 0 || len(serverBlocks[0].block.Keys) > 0 {
|
||||||
|
return serverBlocks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, segment := range serverBlocks[0].block.Segments {
|
||||||
|
dir := segment.Directive()
|
||||||
|
var val interface{}
|
||||||
|
var err error
|
||||||
|
disp := caddyfile.NewDispenser(segment)
|
||||||
|
// TODO: make this switch into a map
|
||||||
|
switch dir {
|
||||||
|
case "http_port":
|
||||||
|
val, err = parseOptHTTPPort(disp)
|
||||||
|
case "https_port":
|
||||||
|
val, err = parseOptHTTPSPort(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 = parseOptACME(disp)
|
||||||
|
case "email":
|
||||||
|
val, err = parseOptEmail(disp)
|
||||||
|
case "admin":
|
||||||
|
val, err = parseOptAdmin(disp)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unrecognized parameter name: %s", dir)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s: %v", dir, err)
|
||||||
|
}
|
||||||
|
options[dir] = val
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverBlocks[1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
// hostsFromServerBlockKeys returns a list of all the
|
// hostsFromServerBlockKeys returns a list of all the
|
||||||
// hostnames found in the keys of the server block sb.
|
// hostnames found in the keys of the server block sb.
|
||||||
// The list may not be in a consistent order.
|
// The list may not be in a consistent order.
|
||||||
|
|
Loading…
Reference in a new issue