@marcel91200 / caddy Mirror · read-only / commits / af25f025
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

caddyfile: Support global config block; allow non-empty blocks w/ 0 keys

Matthew Holt committed Aug 22, 2019 at 13:38 UTC af25f0254e94eb2e2898ba495bfc3de209a49e79
8 files changed +118 -28
caddyconfig/caddyfile/adapter.go
+4 -4
@@ -29,15 +29,15 @@ type Adapter struct {
29 }
30
31 // Adapt converts the Caddyfile config in body to Caddy JSON.
32 -func (a Adapter) Adapt(body []byte, options map[string]string) ([]byte, []caddyconfig.Warning, error) {
32 +func (a Adapter) Adapt(body []byte, options map[string]interface{}) ([]byte, []caddyconfig.Warning, error) {
33 if a.ServerType == nil {
34 return nil, nil, fmt.Errorf("no server type")
35 }
36 if options == nil {
37 - options = make(map[string]string)
37 + options = make(map[string]interface{})
38 }
39
40 - filename := options["filename"]
40 + filename, _ := options["filename"].(string)
41 if filename == "" {
42 filename = "Caddyfile"
43 }
@@ -80,7 +80,7 @@ type ServerType interface {
80 // (e.g. CLI flags) and creates a Caddy
81 // config, along with any warnings or
82 // an error.
83 - Setup([]ServerBlock, map[string]string) (*caddy.Config, []caddyconfig.Warning, error)
83 + Setup([]ServerBlock, map[string]interface{}) (*caddy.Config, []caddyconfig.Warning, error)
84 }
85
86 // Interface guard
caddyconfig/caddyfile/dispenser.go
+19 -4
@@ -186,10 +186,10 @@ func (d *Dispenser) File() string {
186
187 // Args is a convenience function that loads the next arguments
188 // (tokens on the same line) into an arbitrary number of strings
189 -// pointed to in targets. If there are fewer tokens available
190 -// than string pointers, the remaining strings will not be changed
191 -// and false will be returned. If there were enough tokens available
192 -// to fill the arguments, then true will be returned.
189 +// pointed to in targets. If there are not enough argument tokens
190 +// available to fill targets, false is returned and the remaining
191 +// targets are left unchanged. If all the targets are filled,
192 +// then true is returned.
193 func (d *Dispenser) Args(targets ...*string) bool {
194 for i := 0; i < len(targets); i++ {
195 if !d.NextArg() {
@@ -200,6 +200,21 @@ func (d *Dispenser) Args(targets ...*string) bool {
200 return true
201 }
202
203 +// AllArgs is like Args, but if there are more argument tokens
204 +// available than there are targets, false is returned. The
205 +// number of available argument tokens must match the number of
206 +// targets exactly to return true.
207 +func (d *Dispenser) AllArgs(targets ...*string) bool {
208 + if !d.Args(targets...) {
209 + return false
210 + }
211 + if d.NextArg() {
212 + d.Prev()
213 + return false
214 + }
215 + return true
216 +}
217 +
218 // RemainingArgs loads any more arguments (tokens on the same line)
219 // into a slice and returns them. Open curly brace tokens also indicate
220 // the end of arguments, and the curly brace is not included in
caddyconfig/caddyfile/parse.go
+1 -1
@@ -70,7 +70,7 @@ func (p *parser) parseAll() ([]ServerBlock, error) {
70 if err != nil {
71 return blocks, err
72 }
73 - if len(p.block.Keys) > 0 {
73 + if len(p.block.Keys) > 0 || len(p.block.Segments) > 0 {
74 blocks = append(blocks, p.block)
75 }
76 if p.nesting > 0 {
caddyconfig/configadapters.go
+1 -1
@@ -22,7 +22,7 @@ import (
22 // Adapter is a type which can adapt a configuration to Caddy JSON.
23 // It returns the results and any warnings, or an error.
24 type Adapter interface {
25 - Adapt(body []byte, options map[string]string) ([]byte, []Warning, error)
25 + Adapt(body []byte, options map[string]interface{}) ([]byte, []Warning, error)
26 }
27
28 // Warning represents a warning or notice related to conversion.
caddyconfig/httpcaddyfile/global.go new
+53
@@ -0,0 +1,53 @@
1 +// Copyright 2015 Matthew Holt and The Caddy Authors
2 +//
3 +// Licensed under the Apache License, Version 2.0 (the "License");
4 +// you may not use this file except in compliance with the License.
5 +// You may obtain a copy of the License at
6 +//
7 +// http://www.apache.org/licenses/LICENSE-2.0
8 +//
9 +// Unless required by applicable law or agreed to in writing, software
10 +// distributed under the License is distributed on an "AS IS" BASIS,
11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 +// See the License for the specific language governing permissions and
13 +// limitations under the License.
14 +
15 +package httpcaddyfile
16 +
17 +import (
18 + "strconv"
19 +
20 + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
21 +)
22 +
23 +func parseHTTPPort(d *caddyfile.Dispenser) (int, error) {
24 + var httpPort int
25 + for d.Next() {
26 + var httpPortStr string
27 + if !d.AllArgs(&httpPortStr) {
28 + return 0, d.ArgErr()
29 + }
30 + var err error
31 + httpPort, err = strconv.Atoi(httpPortStr)
32 + if err != nil {
33 + return 0, d.Errf("converting port '%s' to integer value: %v", httpPortStr, err)
34 + }
35 + }
36 + return httpPort, nil
37 +}
38 +
39 +func parseHTTPSPort(d *caddyfile.Dispenser) (int, error) {
40 + var httpsPort int
41 + for d.Next() {
42 + var httpsPortStr string
43 + if !d.AllArgs(&httpsPortStr) {
44 + return 0, d.ArgErr()
45 + }
46 + var err error
47 + httpsPort, err = strconv.Atoi(httpsPortStr)
48 + if err != nil {
49 + return 0, d.Errf("converting port '%s' to integer value: %v", httpsPortStr, err)
50 + }
51 + }
52 + return httpsPort, nil
53 +}
caddyconfig/httpcaddyfile/httptype.go
+38 -15
@@ -19,7 +19,6 @@ import (
19 "fmt"
20 "reflect"
21 "sort"
22 - "strconv"
22 "strings"
23
24 "github.com/caddyserver/caddy/v2"
@@ -44,7 +43,7 @@ type ServerType struct {
43
44 // Setup makes a config from the tokens.
45 func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
47 - options map[string]string) (*caddy.Config, []caddyconfig.Warning, error) {
46 + options map[string]interface{}) (*caddy.Config, []caddyconfig.Warning, error) {
47 var warnings []caddyconfig.Warning
48
49 var serverBlocks []serverBlock
@@ -55,6 +54,29 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
54 })
55 }
56
57 + // global configuration
58 + if len(serverBlocks) > 0 && len(serverBlocks[0].block.Keys) == 0 {
59 + sb := serverBlocks[0]
60 + for _, segment := range sb.block.Segments {
61 + dir := segment.Directive()
62 + var val interface{}
63 + var err error
64 + switch dir {
65 + case "http_port":
66 + val, err = parseHTTPPort(caddyfile.NewDispenser(segment))
67 + case "https_port":
68 + val, err = parseHTTPSPort(caddyfile.NewDispenser(segment))
69 + default:
70 + return nil, warnings, fmt.Errorf("unrecognized parameter name: %s", dir)
71 + }
72 + if err != nil {
73 + return nil, warnings, fmt.Errorf("%s: %v", dir, err)
74 + }
75 + options[dir] = val
76 + }
77 + serverBlocks = serverBlocks[1:]
78 + }
79 +
80 for _, sb := range serverBlocks {
81 // replace shorthand placeholders (which are
82 // convenient when writing a Caddyfile) with
@@ -77,11 +99,15 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
99 }
100 }
101
102 + if len(sb.block.Keys) == 0 {
103 + return nil, warnings, fmt.Errorf("server block without any key is global configuration, and if used, it must be first")
104 + }
105 +
106 // extract matcher definitions
107 d := sb.block.DispenseDirective("matcher")
108 matcherDefs, err := st.parseMatcherDefinitions(d)
109 if err != nil {
84 - return nil, nil, err
110 + return nil, warnings, err
111 }
112
113 for _, segment := range sb.block.Segments {
@@ -129,8 +155,8 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
155
156 // now that each server is configured, make the HTTP app
157 httpApp := caddyhttp.App{
132 - HTTPPort: tryInt(options["http-port"], &warnings),
133 - HTTPSPort: tryInt(options["https-port"], &warnings),
158 + HTTPPort: tryInt(options["http_port"], &warnings),
159 + HTTPSPort: tryInt(options["https_port"], &warnings),
160 Servers: servers,
161 }
162
@@ -494,17 +520,14 @@ func encodeMatcherSet(matchers map[string]caddyhttp.RequestMatcher) (map[string]
520 return msEncoded, nil
521 }
522
497 -// tryInt tries to convert str to an integer. If it fails, it downgrades
498 -// the error to a warning and returns 0.
499 -func tryInt(str string, warnings *[]caddyconfig.Warning) int {
500 - if str == "" {
501 - return 0
502 - }
503 - val, err := strconv.Atoi(str)
504 - if err != nil && warnings != nil {
505 - *warnings = append(*warnings, caddyconfig.Warning{Message: err.Error()})
523 +// tryInt tries to convert val to an integer. If it fails,
524 +// it downgrades the error to a warning and returns 0.
525 +func tryInt(val interface{}, warnings *[]caddyconfig.Warning) int {
526 + intVal, ok := val.(int)
527 + if val != nil && !ok && warnings != nil {
528 + *warnings = append(*warnings, caddyconfig.Warning{Message: "not an integer type"})
529 }
507 - return val
530 + return intVal
531 }
532
533 type matcherSetAndTokens struct {
cmd/commands.go
+1 -1
@@ -331,7 +331,7 @@ func cmdAdaptConfig() (int, error) {
331 fmt.Errorf("reading input file: %v", err)
332 }
333
334 - opts := make(map[string]string)
334 + opts := make(map[string]interface{})
335 if *adaptCmdPrettyFlag {
336 opts["pretty"] = "true"
337 }
cmd/main.go
+1 -2
@@ -131,9 +131,8 @@ func loadConfig(configFile, adapterName string) ([]byte, error) {
131
132 // adapt config
133 if cfgAdapter != nil {
134 - adaptedConfig, warnings, err := cfgAdapter.Adapt(config, map[string]string{
134 + adaptedConfig, warnings, err := cfgAdapter.Adapt(config, map[string]interface{}{
135 "filename": configFile,
136 - // TODO: all other options... (http-port, etc...)
136 })
137 if err != nil {
138 return nil, fmt.Errorf("adapting config using %s: %v", adapterName, err)