| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | // 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 httpcaddyfile | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2020-01-15 13:51:12 -07:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2020-02-25 21:56:43 -07:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/caddyserver/caddy/v2" | 
					
						
							|  |  |  | 	"github.com/caddyserver/caddy/v2/caddyconfig" | 
					
						
							|  |  |  | 	"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" | 
					
						
							|  |  |  | 	"github.com/caddyserver/caddy/v2/modules/caddyhttp" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 12:09:54 -07:00
										 |  |  | // directiveOrder specifies the order | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | // to apply directives in HTTP routes. | 
					
						
							| 
									
										
										
										
											2020-01-16 12:09:54 -07:00
										 |  |  | var directiveOrder = []string{ | 
					
						
							| 
									
										
										
										
											2020-01-17 11:38:49 -07:00
										 |  |  | 	"redir", | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	"rewrite", | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:32:38 -07:00
										 |  |  | 	"root", | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-12 15:46:13 -07:00
										 |  |  | 	"strip_prefix", | 
					
						
							|  |  |  | 	"strip_suffix", | 
					
						
							|  |  |  | 	"uri_replace", | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	"try_files", | 
					
						
							| 
									
										
										
										
											2020-01-17 11:38:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 22:24:20 -07:00
										 |  |  | 	// middleware handlers that typically wrap responses | 
					
						
							| 
									
										
										
										
											2019-10-10 14:37:27 -06:00
										 |  |  | 	"basicauth", | 
					
						
							| 
									
										
										
										
											2020-01-22 09:33:53 -07:00
										 |  |  | 	"header", | 
					
						
							| 
									
										
										
										
											2019-09-11 18:48:37 -06:00
										 |  |  | 	"request_header", | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	"encode", | 
					
						
							|  |  |  | 	"templates", | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"handle", | 
					
						
							| 
									
										
										
										
											2020-01-09 14:00:32 -07:00
										 |  |  | 	"route", | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 22:24:20 -07:00
										 |  |  | 	// handlers that typically respond to requests | 
					
						
							| 
									
										
										
										
											2019-09-16 11:04:18 -06:00
										 |  |  | 	"respond", | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	"reverse_proxy", | 
					
						
							| 
									
										
										
										
											2019-09-11 12:02:35 -06:00
										 |  |  | 	"php_fastcgi", | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	"file_server", | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | // directiveIsOrdered returns true if dir is | 
					
						
							|  |  |  | // a known, ordered (sorted) directive. | 
					
						
							|  |  |  | func directiveIsOrdered(dir string) bool { | 
					
						
							|  |  |  | 	for _, d := range directiveOrder { | 
					
						
							|  |  |  | 		if d == dir { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | // RegisterDirective registers a unique directive dir with an | 
					
						
							|  |  |  | // associated unmarshaling (setup) function. When directive dir | 
					
						
							|  |  |  | // is encountered in a Caddyfile, setupFunc will be called to | 
					
						
							|  |  |  | // unmarshal its tokens. | 
					
						
							|  |  |  | func RegisterDirective(dir string, setupFunc UnmarshalFunc) { | 
					
						
							|  |  |  | 	if _, ok := registeredDirectives[dir]; ok { | 
					
						
							|  |  |  | 		panic("directive " + dir + " already registered") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	registeredDirectives[dir] = setupFunc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RegisterHandlerDirective is like RegisterDirective, but for | 
					
						
							|  |  |  | // directives which specifically output only an HTTP handler. | 
					
						
							| 
									
										
										
										
											2019-12-12 15:27:09 -07:00
										 |  |  | // Directives registered with this function will always have | 
					
						
							|  |  |  | // an optional matcher token as the first argument. | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) { | 
					
						
							|  |  |  | 	RegisterDirective(dir, func(h Helper) ([]ConfigValue, error) { | 
					
						
							|  |  |  | 		if !h.Next() { | 
					
						
							|  |  |  | 			return nil, h.ArgErr() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		matcherSet, ok, err := h.MatcherToken() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if ok { | 
					
						
							| 
									
										
										
										
											2019-11-04 13:43:39 -07:00
										 |  |  | 			// strip matcher token; we don't need to | 
					
						
							|  |  |  | 			// use the return value here because a | 
					
						
							|  |  |  | 			// new dispenser should have been made | 
					
						
							|  |  |  | 			// solely for this directive's tokens, | 
					
						
							|  |  |  | 			// with no other uses of same slice | 
					
						
							|  |  |  | 			h.Dispenser.Delete() | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		h.Dispenser.Reset() // pretend this lookahead never happened | 
					
						
							|  |  |  | 		val, err := setupFunc(h) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return h.NewRoute(matcherSet, val), nil | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Helper is a type which helps setup a value from | 
					
						
							|  |  |  | // Caddyfile tokens. | 
					
						
							|  |  |  | type Helper struct { | 
					
						
							|  |  |  | 	*caddyfile.Dispenser | 
					
						
							| 
									
										
										
										
											2020-03-05 05:58:49 +13:00
										 |  |  | 	// State stores intermediate variables during caddyfile adaptation. | 
					
						
							|  |  |  | 	State        map[string]interface{} | 
					
						
							| 
									
										
										
										
											2020-01-16 11:29:20 -07:00
										 |  |  | 	options      map[string]interface{} | 
					
						
							|  |  |  | 	warnings     *[]caddyconfig.Warning | 
					
						
							|  |  |  | 	matcherDefs  map[string]caddy.ModuleMap | 
					
						
							|  |  |  | 	parentBlock  caddyfile.ServerBlock | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | 	groupCounter counter | 
					
						
							| 
									
										
										
										
											2019-08-21 15:50:02 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-30 09:11:30 -06:00
										 |  |  | // Option gets the option keyed by name. | 
					
						
							|  |  |  | func (h Helper) Option(name string) interface{} { | 
					
						
							|  |  |  | 	return h.options[name] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-21 15:50:02 -06:00
										 |  |  | // Caddyfiles returns the list of config files from | 
					
						
							|  |  |  | // which tokens in the current server block were loaded. | 
					
						
							|  |  |  | func (h Helper) Caddyfiles() []string { | 
					
						
							|  |  |  | 	// first obtain set of names of files involved | 
					
						
							|  |  |  | 	// in this server block, without duplicates | 
					
						
							|  |  |  | 	files := make(map[string]struct{}) | 
					
						
							|  |  |  | 	for _, segment := range h.parentBlock.Segments { | 
					
						
							|  |  |  | 		for _, token := range segment { | 
					
						
							|  |  |  | 			files[token.File] = struct{}{} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// then convert the set into a slice | 
					
						
							|  |  |  | 	filesSlice := make([]string, 0, len(files)) | 
					
						
							|  |  |  | 	for file := range files { | 
					
						
							|  |  |  | 		filesSlice = append(filesSlice, file) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return filesSlice | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // JSON converts val into JSON. Any errors are added to warnings. | 
					
						
							| 
									
										
										
										
											2019-12-12 15:27:09 -07:00
										 |  |  | func (h Helper) JSON(val interface{}) json.RawMessage { | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	return caddyconfig.JSON(val, h.warnings) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | // MatcherToken assumes the next argument token is (possibly) a matcher, | 
					
						
							|  |  |  | // and if so, returns the matcher set along with a true value. If the next | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | // token is not a matcher, nil and false is returned. Note that a true | 
					
						
							|  |  |  | // value may be returned with a nil matcher set if it is a catch-all. | 
					
						
							| 
									
										
										
										
											2019-12-10 13:36:46 -07:00
										 |  |  | func (h Helper) MatcherToken() (caddy.ModuleMap, bool, error) { | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	if !h.NextArg() { | 
					
						
							|  |  |  | 		return nil, false, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return matcherSetFromMatcherToken(h.Dispenser.Token(), h.matcherDefs, h.warnings) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-27 21:03:45 -07:00
										 |  |  | // ExtractMatcherSet is like MatcherToken, except this is a higher-level | 
					
						
							|  |  |  | // method that returns the matcher set described by the matcher token, | 
					
						
							|  |  |  | // or nil if there is none, and deletes the matcher token from the | 
					
						
							|  |  |  | // dispenser and resets it as if this look-ahead never happened. Useful | 
					
						
							|  |  |  | // when wrapping a route (one or more handlers) in a user-defined matcher. | 
					
						
							|  |  |  | func (h Helper) ExtractMatcherSet() (caddy.ModuleMap, error) { | 
					
						
							|  |  |  | 	matcherSet, hasMatcher, err := h.MatcherToken() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if hasMatcher { | 
					
						
							|  |  |  | 		h.Dispenser.Delete() // strip matcher token | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	h.Dispenser.Reset() // pretend this lookahead never happened | 
					
						
							|  |  |  | 	return matcherSet, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | // NewRoute returns config values relevant to creating a new HTTP route. | 
					
						
							| 
									
										
										
										
											2019-12-10 13:36:46 -07:00
										 |  |  | func (h Helper) NewRoute(matcherSet caddy.ModuleMap, | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	handler caddyhttp.MiddlewareHandler) []ConfigValue { | 
					
						
							| 
									
										
										
										
											2019-12-12 15:27:09 -07:00
										 |  |  | 	mod, err := caddy.GetModule(caddy.GetModuleID(handler)) | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-12-12 15:27:09 -07:00
										 |  |  | 		*h.warnings = append(*h.warnings, caddyconfig.Warning{ | 
					
						
							|  |  |  | 			File:    h.File(), | 
					
						
							|  |  |  | 			Line:    h.Line(), | 
					
						
							|  |  |  | 			Message: err.Error(), | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-10 13:36:46 -07:00
										 |  |  | 	var matcherSetsRaw []caddy.ModuleMap | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	if matcherSet != nil { | 
					
						
							|  |  |  | 		matcherSetsRaw = append(matcherSetsRaw, matcherSet) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return []ConfigValue{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Class: "route", | 
					
						
							|  |  |  | 			Value: caddyhttp.Route{ | 
					
						
							|  |  |  | 				MatcherSetsRaw: matcherSetsRaw, | 
					
						
							| 
									
										
										
										
											2019-12-10 13:36:46 -07:00
										 |  |  | 				HandlersRaw:    []json.RawMessage{caddyconfig.JSONModuleObject(handler, "handler", mod.ID.Name(), h.warnings)}, | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 12:09:54 -07:00
										 |  |  | // GroupRoutes adds the routes (caddyhttp.Route type) in vals to the | 
					
						
							|  |  |  | // same group, if there is more than one route in vals. | 
					
						
							| 
									
										
										
										
											2020-01-16 11:29:20 -07:00
										 |  |  | func (h Helper) GroupRoutes(vals []ConfigValue) { | 
					
						
							|  |  |  | 	// ensure there's at least two routes; group of one is pointless | 
					
						
							|  |  |  | 	var count int | 
					
						
							|  |  |  | 	for _, v := range vals { | 
					
						
							|  |  |  | 		if _, ok := v.Value.(caddyhttp.Route); ok { | 
					
						
							|  |  |  | 			count++ | 
					
						
							|  |  |  | 			if count > 1 { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if count < 2 { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// now that we know the group will have some effect, do it | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | 	groupName := h.groupCounter.nextGroup() | 
					
						
							| 
									
										
										
										
											2020-01-16 12:09:54 -07:00
										 |  |  | 	for i := range vals { | 
					
						
							| 
									
										
										
										
											2020-01-16 11:29:20 -07:00
										 |  |  | 		if route, ok := vals[i].Value.(caddyhttp.Route); ok { | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | 			route.Group = groupName | 
					
						
							| 
									
										
										
										
											2020-01-16 11:29:20 -07:00
										 |  |  | 			vals[i].Value = route | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | // NewBindAddresses returns config values relevant to adding | 
					
						
							|  |  |  | // listener bind addresses to the config. | 
					
						
							|  |  |  | func (h Helper) NewBindAddresses(addrs []string) []ConfigValue { | 
					
						
							|  |  |  | 	return []ConfigValue{{Class: "bind", Value: addrs}} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ConfigValue represents a value to be added to the final | 
					
						
							|  |  |  | // configuration, or a value to be consulted when building | 
					
						
							|  |  |  | // the final configuration. | 
					
						
							|  |  |  | type ConfigValue struct { | 
					
						
							|  |  |  | 	// The kind of value this is. As the config is | 
					
						
							|  |  |  | 	// being built, the adapter will look in the | 
					
						
							|  |  |  | 	// "pile" for values belonging to a certain | 
					
						
							|  |  |  | 	// class when it is setting up a certain part | 
					
						
							|  |  |  | 	// of the config. The associated value will be | 
					
						
							|  |  |  | 	// type-asserted and placed accordingly. | 
					
						
							|  |  |  | 	Class string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The value to be used when building the config. | 
					
						
							|  |  |  | 	// Generally its type is associated with the | 
					
						
							|  |  |  | 	// name of the Class. | 
					
						
							|  |  |  | 	Value interface{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	directive string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | func sortRoutes(routes []ConfigValue) { | 
					
						
							| 
									
										
										
										
											2020-01-16 12:09:54 -07:00
										 |  |  | 	dirPositions := make(map[string]int) | 
					
						
							|  |  |  | 	for i, dir := range directiveOrder { | 
					
						
							|  |  |  | 		dirPositions[dir] = i | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-15 13:51:12 -07:00
										 |  |  | 	// while we are sorting, we will need to decode a route's path matcher | 
					
						
							|  |  |  | 	// in order to sub-sort by path length; we can amortize this operation | 
					
						
							|  |  |  | 	// for efficiency by storing the decoded matchers in a slice | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | 	decodedMatchers := make([]caddyhttp.MatchPath, len(routes)) | 
					
						
							| 
									
										
										
										
											2020-01-15 13:51:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | 	sort.SliceStable(routes, func(i, j int) bool { | 
					
						
							|  |  |  | 		iDir, jDir := routes[i].directive, routes[j].directive | 
					
						
							| 
									
										
										
										
											2020-01-15 13:51:12 -07:00
										 |  |  | 		if iDir == jDir { | 
					
						
							|  |  |  | 			// directives are the same; sub-sort by path matcher length | 
					
						
							|  |  |  | 			// if there's only one matcher set and one path (common case) | 
					
						
							| 
									
										
										
										
											2020-01-16 17:08:52 -07:00
										 |  |  | 			iRoute, ok := routes[i].Value.(caddyhttp.Route) | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				return false | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			jRoute, ok := routes[j].Value.(caddyhttp.Route) | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				return false | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-01-15 13:51:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 13:38:12 -07:00
										 |  |  | 			// use already-decoded matcher, or decode if it's the first time seeing it | 
					
						
							|  |  |  | 			iPM, jPM := decodedMatchers[i], decodedMatchers[j] | 
					
						
							|  |  |  | 			if iPM == nil && len(iRoute.MatcherSetsRaw) == 1 { | 
					
						
							|  |  |  | 				var pathMatcher caddyhttp.MatchPath | 
					
						
							|  |  |  | 				_ = json.Unmarshal(iRoute.MatcherSetsRaw[0]["path"], &pathMatcher) | 
					
						
							|  |  |  | 				decodedMatchers[i] = pathMatcher | 
					
						
							|  |  |  | 				iPM = pathMatcher | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if jPM == nil && len(jRoute.MatcherSetsRaw) == 1 { | 
					
						
							|  |  |  | 				var pathMatcher caddyhttp.MatchPath | 
					
						
							|  |  |  | 				_ = json.Unmarshal(jRoute.MatcherSetsRaw[0]["path"], &pathMatcher) | 
					
						
							|  |  |  | 				decodedMatchers[j] = pathMatcher | 
					
						
							|  |  |  | 				jPM = pathMatcher | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 13:49:51 -07:00
										 |  |  | 			// sort by longer path (more specific) first; missing | 
					
						
							|  |  |  | 			// path matchers are treated as zero-length paths | 
					
						
							|  |  |  | 			var iPathLen, jPathLen int | 
					
						
							|  |  |  | 			if iPM != nil { | 
					
						
							|  |  |  | 				iPathLen = len(iPM[0]) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if jPM != nil { | 
					
						
							|  |  |  | 				jPathLen = len(jPM[0]) | 
					
						
							| 
									
										
										
										
											2020-01-15 13:51:12 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-02-28 13:49:51 -07:00
										 |  |  | 			return iPathLen > jPathLen | 
					
						
							| 
									
										
										
										
											2020-01-15 13:51:12 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return dirPositions[iDir] < dirPositions[jDir] | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 22:24:20 -07:00
										 |  |  | // parseSegmentAsSubroute parses the segment such that its subdirectives | 
					
						
							|  |  |  | // are themselves treated as directives, from which a subroute is built | 
					
						
							|  |  |  | // and returned. | 
					
						
							|  |  |  | func parseSegmentAsSubroute(h Helper) (caddyhttp.MiddlewareHandler, error) { | 
					
						
							|  |  |  | 	var allResults []ConfigValue | 
					
						
							| 
									
										
										
										
											2020-02-25 21:56:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 22:24:20 -07:00
										 |  |  | 	for h.Next() { | 
					
						
							| 
									
										
										
										
											2020-02-25 21:56:43 -07:00
										 |  |  | 		// slice the linear list of tokens into top-level segments | 
					
						
							|  |  |  | 		var segments []caddyfile.Segment | 
					
						
							| 
									
										
										
										
											2020-02-16 22:24:20 -07:00
										 |  |  | 		for nesting := h.Nesting(); h.NextBlock(nesting); { | 
					
						
							| 
									
										
										
										
											2020-02-25 21:56:43 -07:00
										 |  |  | 			segments = append(segments, h.NextSegment()) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-02-16 22:24:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-25 21:56:43 -07:00
										 |  |  | 		// copy existing matcher definitions so we can augment | 
					
						
							|  |  |  | 		// new ones that are defined only in this scope | 
					
						
							|  |  |  | 		matcherDefs := make(map[string]caddy.ModuleMap, len(h.matcherDefs)) | 
					
						
							|  |  |  | 		for key, val := range h.matcherDefs { | 
					
						
							|  |  |  | 			matcherDefs[key] = val | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// find and extract any embedded matcher definitions in this scope | 
					
						
							|  |  |  | 		for i, seg := range segments { | 
					
						
							|  |  |  | 			if strings.HasPrefix(seg.Directive(), matcherPrefix) { | 
					
						
							|  |  |  | 				err := parseMatcherDefinitions(caddyfile.NewDispenser(seg), matcherDefs) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					return nil, err | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				segments = append(segments[:i], segments[i+1:]...) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// with matchers ready to go, evaluate each directive's segment | 
					
						
							|  |  |  | 		for _, seg := range segments { | 
					
						
							|  |  |  | 			dir := seg.Directive() | 
					
						
							| 
									
										
										
										
											2020-02-16 22:24:20 -07:00
										 |  |  | 			dirFunc, ok := registeredDirectives[dir] | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				return nil, h.Errf("unrecognized directive: %s", dir) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			subHelper := h | 
					
						
							| 
									
										
										
										
											2020-02-25 21:56:43 -07:00
										 |  |  | 			subHelper.Dispenser = caddyfile.NewDispenser(seg) | 
					
						
							|  |  |  | 			subHelper.matcherDefs = matcherDefs | 
					
						
							| 
									
										
										
										
											2020-02-16 22:24:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			results, err := dirFunc(subHelper) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, h.Errf("parsing caddyfile tokens for '%s': %v", dir, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for _, result := range results { | 
					
						
							|  |  |  | 				result.directive = dir | 
					
						
							|  |  |  | 				allResults = append(allResults, result) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-25 21:56:43 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return buildSubroute(allResults, h.groupCounter) | 
					
						
							| 
									
										
										
										
											2020-02-16 22:24:20 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | // serverBlock pairs a Caddyfile server block | 
					
						
							|  |  |  | // with a "pile" of config values, keyed by class | 
					
						
							|  |  |  | // name. | 
					
						
							|  |  |  | type serverBlock struct { | 
					
						
							|  |  |  | 	block caddyfile.ServerBlock | 
					
						
							|  |  |  | 	pile  map[string][]ConfigValue // config values obtained from directives | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type ( | 
					
						
							|  |  |  | 	// UnmarshalFunc is a function which can unmarshal Caddyfile | 
					
						
							|  |  |  | 	// tokens into zero or more config values using a Helper type. | 
					
						
							|  |  |  | 	// These are passed in a call to RegisterDirective. | 
					
						
							|  |  |  | 	UnmarshalFunc func(h Helper) ([]ConfigValue, error) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// UnmarshalHandlerFunc is like UnmarshalFunc, except the | 
					
						
							|  |  |  | 	// output of the unmarshaling is an HTTP handler. This | 
					
						
							|  |  |  | 	// function does not need to deal with HTTP request matching | 
					
						
							|  |  |  | 	// which is abstracted away. Since writing HTTP handlers | 
					
						
							|  |  |  | 	// with Caddyfile support is very common, this is a more | 
					
						
							|  |  |  | 	// convenient way to add a handler to the chain since a lot | 
					
						
							|  |  |  | 	// of the details common to HTTP handlers are taken care of | 
					
						
							|  |  |  | 	// for you. These are passed to a call to | 
					
						
							|  |  |  | 	// RegisterHandlerDirective. | 
					
						
							|  |  |  | 	UnmarshalHandlerFunc func(h Helper) (caddyhttp.MiddlewareHandler, error) | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var registeredDirectives = make(map[string]UnmarshalFunc) |