Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 14, 05:15 UTC
httpcaddyfile: Refactor global options parsing; prevent duplicate keys
Matthew Holt committed
Feb 16, 2020 at 15:28 UTC
bc2e406572e9af290469b2d4d58974ac99c0b492
1 file changed
+63
-36
caddyconfig/httpcaddyfile/httptype.go
+63
-36
@@ -43,49 +43,31 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
43
var warnings []caddyconfig.Warning
44
gc := counter{new(int)}
45
46
+ // load all the server blocks and associate them with a "pile"
47
+ // of config values; also prohibit duplicate keys because they
48
+ // can make a config confusing if more than one server block is
49
+ // chosen to handle a request - we actually will make each
50
+ // server block's route terminal so that only one will run
51
+ sbKeys := make(map[string]struct{})
52
var serverBlocks []serverBlock
47
- for _, sblock := range originalServerBlocks {
53
+ for i, sblock := range originalServerBlocks {
54
+ for j, k := range sblock.Keys {
55
+ if _, ok := sbKeys[k]; ok {
56
+ return nil, warnings, fmt.Errorf("duplicate site address not allowed: '%s' in %v (site block %d, key %d)", k, sblock.Keys, i, j)
57
+ }
58
+ sbKeys[k] = struct{}{}
59
+ }
60
serverBlocks = append(serverBlocks, serverBlock{
61
block: sblock,
62
pile: make(map[string][]ConfigValue),
63
})
64
}
65
54
- // global configuration
55
- if len(serverBlocks) > 0 && len(serverBlocks[0].block.Keys) == 0 {
56
- sb := serverBlocks[0]
57
- for _, segment := range sb.block.Segments {
58
- dir := segment.Directive()
59
- var val interface{}
60
- var err error
61
- disp := caddyfile.NewDispenser(segment)
62
- // TODO: make this switch into a map
63
- switch dir {
64
- case "http_port":
65
- val, err = parseOptHTTPPort(disp)
66
- case "https_port":
67
- val, err = parseOptHTTPSPort(disp)
68
- case "order":
69
- val, err = parseOptOrder(disp)
70
- case "experimental_http3":
71
- val, err = parseOptExperimentalHTTP3(disp)
72
- case "storage":
73
- val, err = parseOptStorage(disp)
74
- case "acme_ca", "acme_dns", "acme_ca_root":
75
- val, err = parseOptACME(disp)
76
- case "email":
77
- val, err = parseOptEmail(disp)
78
- case "admin":
79
- val, err = parseOptAdmin(disp)
80
- default:
81
- return nil, warnings, fmt.Errorf("unrecognized parameter name: %s", dir)
82
- }
83
- if err != nil {
84
- return nil, warnings, fmt.Errorf("%s: %v", dir, err)
85
- }
86
- options[dir] = val
87
- }
88
- serverBlocks = serverBlocks[1:]
66
+ // apply any global options
67
+ var err error
68
+ serverBlocks, err = st.evaluateGlobalOptionsBlock(serverBlocks, options)
69
+ if err != nil {
70
+ return nil, warnings, err
71
}
72
73
for _, sb := range serverBlocks {
@@ -129,6 +111,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
111
}
112
}
113
114
+ // evaluate each directive ("segment") in this block
115
for _, segment := range sb.block.Segments {
116
dir := segment.Directive()
117
@@ -288,6 +271,50 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
271
return cfg, warnings, nil
272
}
273
274
+// evaluateGlobalOptionsBlock evaluates the global options block,
275
+// which is expected to be the first server block if it has zero
276
+// keys. It returns the updated list of server blocks with the
277
+// global options block removed, and updates options accordingly.
278
+func (ServerType) evaluateGlobalOptionsBlock(serverBlocks []serverBlock, options map[string]interface{}) ([]serverBlock, error) {
279
+ if len(serverBlocks) == 0 || len(serverBlocks[0].block.Keys) > 0 {
280
+ return serverBlocks, nil
281
+ }
282
+
283
+ for _, segment := range serverBlocks[0].block.Segments {
284
+ dir := segment.Directive()
285
+ var val interface{}
286
+ var err error
287
+ disp := caddyfile.NewDispenser(segment)
288
+ // TODO: make this switch into a map
289
+ switch dir {
290
+ case "http_port":
291
+ val, err = parseOptHTTPPort(disp)
292
+ case "https_port":
293
+ val, err = parseOptHTTPSPort(disp)
294
+ case "order":
295
+ val, err = parseOptOrder(disp)
296
+ case "experimental_http3":
297
+ val, err = parseOptExperimentalHTTP3(disp)
298
+ case "storage":
299
+ val, err = parseOptStorage(disp)
300
+ case "acme_ca", "acme_dns", "acme_ca_root":
301
+ val, err = parseOptACME(disp)
302
+ case "email":
303
+ val, err = parseOptEmail(disp)
304
+ case "admin":
305
+ val, err = parseOptAdmin(disp)
306
+ default:
307
+ return nil, fmt.Errorf("unrecognized parameter name: %s", dir)
308
+ }
309
+ if err != nil {
310
+ return nil, fmt.Errorf("%s: %v", dir, err)
311
+ }
312
+ options[dir] = val
313
+ }
314
+
315
+ return serverBlocks[1:], nil
316
+}
317
+
318
// hostsFromServerBlockKeys returns a list of all the
319
// hostnames found in the keys of the server block sb.
320
// The list may not be in a consistent order.