@marcel91200 / caddy Mirror · read-only / commits / dc9f4f13
Fork 0

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: 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>

Francis Lavoie committed May 11, 2020 at 17:00 UTC dc9f4f13fc1cc102c713c69ded295b3fcf685e96
4 files changed +130 -41
caddyconfig/httpcaddyfile/directives.go
+18
@@ -120,6 +120,17 @@ func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) {
120 })
121 }
122
123 +// RegisterGlobalOption registers a unique global option opt with
124 +// an associated unmarshaling (setup) function. When the global
125 +// option opt is encountered in a Caddyfile, setupFunc will be
126 +// called to unmarshal its tokens.
127 +func RegisterGlobalOption(opt string, setupFunc UnmarshalGlobalFunc) {
128 + if _, ok := registeredGlobalOptions[opt]; ok {
129 + panic("global option " + opt + " already registered")
130 + }
131 + registeredGlobalOptions[opt] = setupFunc
132 +}
133 +
134 // Helper is a type which helps setup a value from
135 // Caddyfile tokens.
136 type Helper struct {
@@ -454,6 +465,13 @@ type (
465 // for you. These are passed to a call to
466 // RegisterHandlerDirective.
467 UnmarshalHandlerFunc func(h Helper) (caddyhttp.MiddlewareHandler, error)
468 +
469 + // UnmarshalGlobalFunc is a function which can unmarshal Caddyfile
470 + // tokens into a global option config value using a Helper type.
471 + // These are passed in a call to RegisterGlobalOption.
472 + UnmarshalGlobalFunc func(d *caddyfile.Dispenser) (interface{}, error)
473 )
474
475 var registeredDirectives = make(map[string]UnmarshalFunc)
476 +
477 +var registeredGlobalOptions = make(map[string]UnmarshalGlobalFunc)
caddyconfig/httpcaddyfile/httptype.go
+9 -30
@@ -284,39 +284,18 @@ func (ServerType) evaluateGlobalOptionsBlock(serverBlocks []serverBlock, options
284 var val interface{}
285 var err error
286 disp := caddyfile.NewDispenser(segment)
287 - switch dir {
288 - case "debug":
289 - val = true
290 - case "http_port":
291 - val, err = parseOptHTTPPort(disp)
292 - case "https_port":
293 - val, err = parseOptHTTPSPort(disp)
294 - case "default_sni":
295 - val, err = parseOptSingleString(disp)
296 - case "order":
297 - val, err = parseOptOrder(disp)
298 - case "experimental_http3":
299 - val, err = parseOptExperimentalHTTP3(disp)
300 - case "storage":
301 - val, err = parseOptStorage(disp)
302 - case "acme_ca", "acme_dns", "acme_ca_root":
303 - val, err = parseOptSingleString(disp)
304 - case "email":
305 - val, err = parseOptSingleString(disp)
306 - case "admin":
307 - val, err = parseOptAdmin(disp)
308 - case "on_demand_tls":
309 - val, err = parseOptOnDemand(disp)
310 - case "local_certs":
311 - val = true
312 - case "key_type":
313 - val, err = parseOptSingleString(disp)
314 - default:
315 - return nil, fmt.Errorf("unrecognized parameter name: %s", dir)
287 +
288 + dirFunc, ok := registeredGlobalOptions[dir]
289 + if !ok {
290 + tkn := segment[0]
291 + return nil, fmt.Errorf("%s:%d: unrecognized global option: %s", tkn.File, tkn.Line, dir)
292 }
293 +
294 + val, err = dirFunc(disp)
295 if err != nil {
318 - return nil, fmt.Errorf("%s: %v", dir, err)
296 + return nil, fmt.Errorf("parsing caddyfile tokens for '%s': %v", dir, err)
297 }
298 +
299 options[dir] = val
300 }
301
caddyconfig/httpcaddyfile/options.go
+29 -11
@@ -23,7 +23,29 @@ import (
23 "github.com/caddyserver/caddy/v2/modules/caddytls"
24 )
25
26 -func parseOptHTTPPort(d *caddyfile.Dispenser) (int, error) {
26 +func init() {
27 + RegisterGlobalOption("debug", parseOptTrue)
28 + RegisterGlobalOption("http_port", parseOptHTTPPort)
29 + RegisterGlobalOption("https_port", parseOptHTTPSPort)
30 + RegisterGlobalOption("default_sni", parseOptSingleString)
31 + RegisterGlobalOption("order", parseOptOrder)
32 + RegisterGlobalOption("experimental_http3", parseOptTrue)
33 + RegisterGlobalOption("storage", parseOptStorage)
34 + RegisterGlobalOption("acme_ca", parseOptSingleString)
35 + RegisterGlobalOption("acme_dns", parseOptSingleString)
36 + RegisterGlobalOption("acme_ca_root", parseOptSingleString)
37 + RegisterGlobalOption("email", parseOptSingleString)
38 + RegisterGlobalOption("admin", parseOptAdmin)
39 + RegisterGlobalOption("on_demand_tls", parseOptOnDemand)
40 + RegisterGlobalOption("local_certs", parseOptTrue)
41 + RegisterGlobalOption("key_type", parseOptSingleString)
42 +}
43 +
44 +func parseOptTrue(d *caddyfile.Dispenser) (interface{}, error) {
45 + return true, nil
46 +}
47 +
48 +func parseOptHTTPPort(d *caddyfile.Dispenser) (interface{}, error) {
49 var httpPort int
50 for d.Next() {
51 var httpPortStr string
@@ -39,7 +61,7 @@ func parseOptHTTPPort(d *caddyfile.Dispenser) (int, error) {
61 return httpPort, nil
62 }
63
42 -func parseOptHTTPSPort(d *caddyfile.Dispenser) (int, error) {
64 +func parseOptHTTPSPort(d *caddyfile.Dispenser) (interface{}, error) {
65 var httpsPort int
66 for d.Next() {
67 var httpsPortStr string
@@ -55,11 +77,7 @@ func parseOptHTTPSPort(d *caddyfile.Dispenser) (int, error) {
77 return httpsPort, nil
78 }
79
58 -func parseOptExperimentalHTTP3(d *caddyfile.Dispenser) (bool, error) {
59 - return true, nil
60 -}
61 -
62 -func parseOptOrder(d *caddyfile.Dispenser) ([]string, error) {
80 +func parseOptOrder(d *caddyfile.Dispenser) (interface{}, error) {
81 newOrder := directiveOrder
82
83 for d.Next() {
@@ -135,7 +153,7 @@ func parseOptOrder(d *caddyfile.Dispenser) ([]string, error) {
153 return newOrder, nil
154 }
155
138 -func parseOptStorage(d *caddyfile.Dispenser) (caddy.StorageConverter, error) {
156 +func parseOptStorage(d *caddyfile.Dispenser) (interface{}, error) {
157 if !d.Next() { // consume option name
158 return nil, d.ArgErr()
159 }
@@ -162,7 +180,7 @@ func parseOptStorage(d *caddyfile.Dispenser) (caddy.StorageConverter, error) {
180 return storage, nil
181 }
182
165 -func parseOptSingleString(d *caddyfile.Dispenser) (string, error) {
183 +func parseOptSingleString(d *caddyfile.Dispenser) (interface{}, error) {
184 d.Next() // consume parameter name
185 if !d.Next() {
186 return "", d.ArgErr()
@@ -174,7 +192,7 @@ func parseOptSingleString(d *caddyfile.Dispenser) (string, error) {
192 return val, nil
193 }
194
177 -func parseOptAdmin(d *caddyfile.Dispenser) (string, error) {
195 +func parseOptAdmin(d *caddyfile.Dispenser) (interface{}, error) {
196 if d.Next() {
197 var listenAddress string
198 if !d.AllArgs(&listenAddress) {
@@ -188,7 +206,7 @@ func parseOptAdmin(d *caddyfile.Dispenser) (string, error) {
206 return "", nil
207 }
208
191 -func parseOptOnDemand(d *caddyfile.Dispenser) (*caddytls.OnDemandConfig, error) {
209 +func parseOptOnDemand(d *caddyfile.Dispenser) (interface{}, error) {
210 var ond *caddytls.OnDemandConfig
211 for d.Next() {
212 if d.NextArg() {
caddytest/integration/caddyfile_adapt_test.go
+74
@@ -415,3 +415,77 @@ func TestNotBlockMerging(t *testing.T) {
415 }
416 }`)
417 }
418 +
419 +func TestGlobalOptions(t *testing.T) {
420 + caddytest.AssertAdapt(t, `
421 + {
422 + debug
423 + http_port 8080
424 + https_port 8443
425 + default_sni localhost
426 + order root first
427 + storage file_system {
428 + root /data
429 + }
430 + acme_ca https://example.com
431 + acme_ca_root /path/to/ca.crt
432 + email test@example.com
433 + admin off
434 + on_demand_tls {
435 + ask https://example.com
436 + interval 30s
437 + burst 20
438 + }
439 + local_certs
440 + key_type ed25519
441 + }
442 +
443 + :80
444 + `, "caddyfile", `{
445 + "admin": {
446 + "disabled": true
447 + },
448 + "logging": {
449 + "logs": {
450 + "default": {
451 + "level": "DEBUG"
452 + }
453 + }
454 + },
455 + "storage": {
456 + "module": "file_system",
457 + "root": "/data"
458 + },
459 + "apps": {
460 + "http": {
461 + "http_port": 8080,
462 + "https_port": 8443,
463 + "servers": {
464 + "srv0": {
465 + "listen": [
466 + ":80"
467 + ]
468 + }
469 + }
470 + },
471 + "tls": {
472 + "automation": {
473 + "policies": [
474 + {
475 + "issuer": {
476 + "module": "internal"
477 + }
478 + }
479 + ],
480 + "on_demand": {
481 + "rate_limit": {
482 + "interval": 30000000000,
483 + "burst": 20
484 + },
485 + "ask": "https://example.com"
486 + }
487 + }
488 + }
489 + }
490 +}`)
491 +}