-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
caddyfile.go
133 lines (118 loc) · 3.73 KB
/
caddyfile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright 2015 Matthew Holt and The Caddy Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package maphandler
import (
"strconv"
"strings"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
)
func init() {
httpcaddyfile.RegisterHandlerDirective("map", parseCaddyfile)
}
// parseCaddyfile sets up the map handler from Caddyfile tokens. Syntax:
//
// map [<matcher>] <source> <destinations...> {
// [~]<input> <outputs...>
// default <defaults...>
// }
//
// If the input value is prefixed with a tilde (~), then the input will be parsed as a
// regular expression.
//
// The Caddyfile adapter treats outputs that are a literal hyphen (-) as a null/nil
// value. This is useful if you want to fall back to default for that particular output.
//
// The number of outputs for each mapping must not be more than the number of destinations.
// However, for convenience, there may be fewer outputs than destinations and any missing
// outputs will be filled in implicitly.
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
var handler Handler
for h.Next() {
// source
if !h.NextArg() {
return nil, h.ArgErr()
}
handler.Source = h.Val()
// destinations
handler.Destinations = h.RemainingArgs()
if len(handler.Destinations) == 0 {
return nil, h.Err("missing destination argument(s)")
}
// mappings
for h.NextBlock(0) {
// defaults are a special case
if h.Val() == "default" {
if len(handler.Defaults) > 0 {
return nil, h.Err("defaults already defined")
}
handler.Defaults = h.RemainingArgs()
for len(handler.Defaults) < len(handler.Destinations) {
handler.Defaults = append(handler.Defaults, "")
}
continue
}
// every other line maps one input to one or more outputs
in := h.Val()
var outs []interface{}
for _, out := range h.RawRemainingArgs() {
if out == "-" {
outs = append(outs, nil)
} else {
outs = append(outs, specificType(out))
}
}
// cannot have more outputs than destinations
if len(outs) > len(handler.Destinations) {
return nil, h.Err("too many outputs")
}
// for convenience, can have fewer outputs than destinations, but the
// underlying handler won't accept that, so we fill in nil values
for len(outs) < len(handler.Destinations) {
outs = append(outs, nil)
}
// create the mapping
mapping := Mapping{Outputs: outs}
if strings.HasPrefix(in, "~") {
mapping.InputRegexp = in[1:]
} else {
mapping.Input = in
}
handler.Mappings = append(handler.Mappings, mapping)
}
}
return handler, nil
}
// specificType parses the token string and casts it to
// the appropriate scalar type. Supports " and ` quoted
// strings, integers, floats, bool (true/false), and
// anything else is returned as a string.
func specificType(v string) interface{} {
if strings.HasPrefix(v, "\"") {
return strings.Trim(v, "\"")
}
if strings.HasPrefix(v, "`") {
return strings.Trim(v, "`")
}
if num, err := strconv.Atoi(v); err == nil {
return num
}
if num, err := strconv.ParseFloat(v, 64); err == nil {
return num
}
if bool, err := strconv.ParseBool(v); err == nil {
return bool
}
return v
}