@marcel91200 / caddy Mirror · read-only
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 11, 01:00 UTC

master
go 160 lines 5.15 KB
Raw
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 caddyfile
16
17 import (
18 "regexp"
19 "strconv"
20 "strings"
21
22 "go.uber.org/zap"
23
24 "github.com/caddyserver/caddy/v2"
25 )
26
27 // parseVariadic determines if the token is a variadic placeholder,
28 // and if so, determines the index range (start/end) of args to use.
29 // Returns a boolean signaling whether a variadic placeholder was found,
30 // and the start and end indices.
31 func parseVariadic(token Token, argCount int) (bool, int, int) {
32 if !strings.HasPrefix(token.Text, "{args[") {
33 return false, 0, 0
34 }
35 if !strings.HasSuffix(token.Text, "]}") {
36 return false, 0, 0
37 }
38
39 argRange := strings.TrimSuffix(strings.TrimPrefix(token.Text, "{args["), "]}")
40 if argRange == "" {
41 caddy.Log().Named("caddyfile").Warn(
42 "Placeholder "+token.Text+" cannot have an empty index",
43 zap.String("file", token.File+":"+strconv.Itoa(token.Line)), zap.Strings("import_chain", token.imports))
44 return false, 0, 0
45 }
46
47 start, end, found := strings.Cut(argRange, ":")
48
49 // If no ":" delimiter is found, this is not a variadic.
50 // The replacer will pick this up.
51 if !found {
52 return false, 0, 0
53 }
54
55 // A valid token may contain several placeholders, and
56 // they may be separated by ":". It's not variadic.
57 // https://github.com/caddyserver/caddy/issues/5716
58 if strings.Contains(start, "}") || strings.Contains(end, "{") {
59 return false, 0, 0
60 }
61
62 var (
63 startIndex = 0
64 endIndex = argCount
65 err error
66 )
67 if start != "" {
68 startIndex, err = strconv.Atoi(start)
69 if err != nil {
70 caddy.Log().Named("caddyfile").Warn(
71 "Variadic placeholder "+token.Text+" has an invalid start index",
72 zap.String("file", token.File+":"+strconv.Itoa(token.Line)), zap.Strings("import_chain", token.imports))
73 return false, 0, 0
74 }
75 }
76 if end != "" {
77 endIndex, err = strconv.Atoi(end)
78 if err != nil {
79 caddy.Log().Named("caddyfile").Warn(
80 "Variadic placeholder "+token.Text+" has an invalid end index",
81 zap.String("file", token.File+":"+strconv.Itoa(token.Line)), zap.Strings("import_chain", token.imports))
82 return false, 0, 0
83 }
84 }
85
86 // bound check
87 if startIndex < 0 || startIndex > endIndex || endIndex > argCount {
88 caddy.Log().Named("caddyfile").Warn(
89 "Variadic placeholder "+token.Text+" indices are out of bounds, only "+strconv.Itoa(argCount)+" argument(s) exist",
90 zap.String("file", token.File+":"+strconv.Itoa(token.Line)), zap.Strings("import_chain", token.imports))
91 return false, 0, 0
92 }
93 return true, startIndex, endIndex
94 }
95
96 // makeArgsReplacer prepares a Replacer which can replace
97 // non-variadic args placeholders in imported tokens.
98 func makeArgsReplacer(args []string) *caddy.Replacer {
99 repl := caddy.NewEmptyReplacer()
100 repl.Map(func(key string) (any, bool) {
101 // TODO: Remove the deprecated {args.*} placeholder
102 // support at some point in the future
103 if matches := argsRegexpIndexDeprecated.FindStringSubmatch(key); len(matches) > 0 {
104 // What's matched may be a substring of the key
105 if matches[0] != key {
106 return nil, false
107 }
108
109 value, err := strconv.Atoi(matches[1])
110 if err != nil {
111 caddy.Log().Named("caddyfile").Warn(
112 "Placeholder {args." + matches[1] + "} has an invalid index")
113 return nil, false
114 }
115 if value < 0 || value >= len(args) {
116 caddy.Log().Named("caddyfile").Warn(
117 "Placeholder {args." + matches[1] + "} index is out of bounds, only " + strconv.Itoa(len(args)) + " argument(s) exist")
118 return nil, false
119 }
120 caddy.Log().Named("caddyfile").Warn(
121 "Placeholder {args." + matches[1] + "} deprecated, use {args[" + matches[1] + "]} instead")
122 return args[value], true
123 }
124
125 // Handle args[*] form
126 if matches := argsRegexpIndex.FindStringSubmatch(key); len(matches) > 0 {
127 // What's matched may be a substring of the key
128 if matches[0] != key {
129 return nil, false
130 }
131
132 if strings.Contains(matches[1], ":") {
133 caddy.Log().Named("caddyfile").Warn(
134 "Variadic placeholder {args[" + matches[1] + "]} must be a token on its own")
135 return nil, false
136 }
137 value, err := strconv.Atoi(matches[1])
138 if err != nil {
139 caddy.Log().Named("caddyfile").Warn(
140 "Placeholder {args[" + matches[1] + "]} has an invalid index")
141 return nil, false
142 }
143 if value < 0 || value >= len(args) {
144 caddy.Log().Named("caddyfile").Warn(
145 "Placeholder {args[" + matches[1] + "]} index is out of bounds, only " + strconv.Itoa(len(args)) + " argument(s) exist")
146 return nil, false
147 }
148 return args[value], true
149 }
150
151 // Not an args placeholder, ignore
152 return nil, false
153 })
154 return repl
155 }
156
157 var (
158 argsRegexpIndexDeprecated = regexp.MustCompile(`args\.(.+)`)
159 argsRegexpIndex = regexp.MustCompile(`args\[(.+)]`)
160 )