summaryrefslogtreecommitdiff
path: root/caddyconfig/httpcaddyfile
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2020-02-16 15:28:27 -0700
committerMatthew Holt <mholt@users.noreply.github.com>2020-02-16 15:28:27 -0700
commitbc2e406572e9af290469b2d4d58974ac99c0b492 (patch)
tree65b7d11389eb4dc2578c5c5a9d34ca814e18c270 /caddyconfig/httpcaddyfile
parentbf776e7de73205ff40caf7d95f05ddc4283116dd (diff)
httpcaddyfile: Refactor global options parsing; prevent duplicate keys
Diffstat (limited to 'caddyconfig/httpcaddyfile')
-rw-r--r--caddyconfig/httpcaddyfile/httptype.go99
1 files changed, 63 insertions, 36 deletions
diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go
index 4773ac8..f93b8c5 100644
--- a/caddyconfig/httpcaddyfile/httptype.go
+++ b/caddyconfig/httpcaddyfile/httptype.go
@@ -43,49 +43,31 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
var warnings []caddyconfig.Warning
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
- 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{
block: sblock,
pile: make(map[string][]ConfigValue),
})
}
- // global configuration
- 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
- 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, warnings, fmt.Errorf("unrecognized parameter name: %s", dir)
- }
- if err != nil {
- return nil, warnings, fmt.Errorf("%s: %v", dir, err)
- }
- options[dir] = val
- }
- serverBlocks = serverBlocks[1:]
+ // apply any global options
+ var err error
+ serverBlocks, err = st.evaluateGlobalOptionsBlock(serverBlocks, options)
+ if err != nil {
+ return nil, warnings, err
}
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 {
dir := segment.Directive()
@@ -288,6 +271,50 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
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
// hostnames found in the keys of the server block sb.
// The list may not be in a consistent order.