From e34ff21a7183969afb4150f1f7a1f71b9a1dd0d6 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Thu, 22 Aug 2019 14:26:33 -0600 Subject: caddyfile: Allow handler order to be customized --- caddyconfig/httpcaddyfile/global.go | 53 ------------------------ caddyconfig/httpcaddyfile/httptype.go | 29 ++++++++----- caddyconfig/httpcaddyfile/options.go | 76 +++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 63 deletions(-) delete mode 100644 caddyconfig/httpcaddyfile/global.go create mode 100644 caddyconfig/httpcaddyfile/options.go diff --git a/caddyconfig/httpcaddyfile/global.go b/caddyconfig/httpcaddyfile/global.go deleted file mode 100644 index 067d06e..0000000 --- a/caddyconfig/httpcaddyfile/global.go +++ /dev/null @@ -1,53 +0,0 @@ -// 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 ( - "strconv" - - "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" -) - -func parseHTTPPort(d *caddyfile.Dispenser) (int, error) { - var httpPort int - for d.Next() { - var httpPortStr string - if !d.AllArgs(&httpPortStr) { - return 0, d.ArgErr() - } - var err error - httpPort, err = strconv.Atoi(httpPortStr) - if err != nil { - return 0, d.Errf("converting port '%s' to integer value: %v", httpPortStr, err) - } - } - return httpPort, nil -} - -func parseHTTPSPort(d *caddyfile.Dispenser) (int, error) { - var httpsPort int - for d.Next() { - var httpsPortStr string - if !d.AllArgs(&httpsPortStr) { - return 0, d.ArgErr() - } - var err error - httpsPort, err = strconv.Atoi(httpsPortStr) - if err != nil { - return 0, d.Errf("converting port '%s' to integer value: %v", httpsPortStr, err) - } - } - return httpsPort, nil -} diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go index 047d559..ecf6e94 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -66,6 +66,8 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock, val, err = parseHTTPPort(caddyfile.NewDispenser(segment)) case "https_port": val, err = parseHTTPSPort(caddyfile.NewDispenser(segment)) + case "handler_order": + val, err = parseHandlerOrder(caddyfile.NewDispenser(segment)) default: return nil, warnings, fmt.Errorf("unrecognized parameter name: %s", dir) } @@ -148,7 +150,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock, // each pairing of listener addresses to list of server // blocks is basically a server definition - servers, err := st.serversFromPairings(pairings, &warnings) + servers, err := st.serversFromPairings(pairings, options, &warnings) if err != nil { return nil, warnings, err } @@ -230,7 +232,11 @@ func (st *ServerType) hostsFromServerBlockKeys(sb caddyfile.ServerBlock) ([]stri // serversFromPairings creates the servers for each pairing of addresses // to server blocks. Each pairing is essentially a server definition. -func (st *ServerType) serversFromPairings(pairings []sbAddrAssociation, warnings *[]caddyconfig.Warning) (map[string]*caddyhttp.Server, error) { +func (st *ServerType) serversFromPairings( + pairings []sbAddrAssociation, + options map[string]interface{}, + warnings *[]caddyconfig.Warning, +) (map[string]*caddyhttp.Server, error) { servers := make(map[string]*caddyhttp.Server) for i, p := range pairings { @@ -289,16 +295,19 @@ func (st *ServerType) serversFromPairings(pairings []sbAddrAssociation, warnings siteVarSubroute.Routes = append(siteVarSubroute.Routes, cfgVal.Value.(caddyhttp.Route)) } - // set up each handler directive + // set up each handler directive - the order of the handlers + // as they are added to the routes depends on user preference dirRoutes := sblock.pile["route"] - // TODO: The ordering here depends on... if there is a list of - // directives to use, then sort by that, otherwise just use in - // the order they appear in the slice (which is the order they - // appeared in the Caddyfile) - sortByList := true - if sortByList { + handlerOrder, ok := options["handler_order"].([]string) + if !ok { + handlerOrder = defaultDirectiveOrder + } + if len(handlerOrder) == 1 && handlerOrder[0] == "appearance" { + handlerOrder = nil + } + if handlerOrder != nil { dirPositions := make(map[string]int) - for i, dir := range defaultDirectiveOrder { + for i, dir := range handlerOrder { dirPositions[dir] = i } sort.SliceStable(dirRoutes, func(i, j int) bool { diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go new file mode 100644 index 0000000..f99ce51 --- /dev/null +++ b/caddyconfig/httpcaddyfile/options.go @@ -0,0 +1,76 @@ +// 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 ( + "strconv" + + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" +) + +func parseHTTPPort(d *caddyfile.Dispenser) (int, error) { + var httpPort int + for d.Next() { + var httpPortStr string + if !d.AllArgs(&httpPortStr) { + return 0, d.ArgErr() + } + var err error + httpPort, err = strconv.Atoi(httpPortStr) + if err != nil { + return 0, d.Errf("converting port '%s' to integer value: %v", httpPortStr, err) + } + } + return httpPort, nil +} + +func parseHTTPSPort(d *caddyfile.Dispenser) (int, error) { + var httpsPort int + for d.Next() { + var httpsPortStr string + if !d.AllArgs(&httpsPortStr) { + return 0, d.ArgErr() + } + var err error + httpsPort, err = strconv.Atoi(httpsPortStr) + if err != nil { + return 0, d.Errf("converting port '%s' to integer value: %v", httpsPortStr, err) + } + } + return httpsPort, nil +} + +func parseHandlerOrder(d *caddyfile.Dispenser) ([]string, error) { + if !d.Next() { + return nil, d.ArgErr() + } + order := d.RemainingArgs() + if len(order) == 1 && order[0] == "appearance" { + return []string{"appearance"}, nil + } + if len(order) > 0 && d.NextBlock() { + return nil, d.Err("cannot open block if there are arguments") + } + for d.NextBlock() { + order = append(order, d.Val()) + if d.NextArg() { + return nil, d.ArgErr() + } + } + if len(order) == 0 { + return nil, d.ArgErr() + } + return order, nil +} -- cgit v1.2.3