diff options
Diffstat (limited to 'caddyconfig/httpcaddyfile/builtins.go')
-rw-r--r-- | caddyconfig/httpcaddyfile/builtins.go | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go new file mode 100644 index 0000000..7e51e46 --- /dev/null +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -0,0 +1,257 @@ +// 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" + "fmt" + "html" + "net/http" + + "github.com/caddyserver/caddy/v2/caddyconfig" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/caddyserver/caddy/v2/modules/caddyhttp" + "github.com/caddyserver/caddy/v2/modules/caddytls" +) + +func (st *ServerType) parseRoot( + tkns []caddyfile.Token, + matcherDefs map[string]map[string]json.RawMessage, + warnings *[]caddyconfig.Warning, +) ([]caddyhttp.Route, error) { + var routes []caddyhttp.Route + + matchersAndTokens, err := st.tokensToMatcherSets(tkns, matcherDefs, warnings) + if err != nil { + return nil, err + } + + for _, mst := range matchersAndTokens { + d := caddyfile.NewDispenser("Caddyfile", mst.tokens) + + var root string + for d.Next() { + if !d.NextArg() { + return nil, d.ArgErr() + } + root = d.Val() + if d.NextArg() { + return nil, d.ArgErr() + } + } + + varsHandler := caddyhttp.VarsMiddleware{"root": root} + route := caddyhttp.Route{ + Handle: []json.RawMessage{ + caddyconfig.JSONModuleObject(varsHandler, "handler", "vars", warnings), + }, + } + if mst.matcherSet != nil { + route.MatcherSets = []map[string]json.RawMessage{mst.matcherSet} + } + + routes = append(routes, route) + } + + return routes, nil +} + +func (st *ServerType) parseRedir( + tkns []caddyfile.Token, + matcherDefs map[string]map[string]json.RawMessage, + warnings *[]caddyconfig.Warning, +) ([]caddyhttp.Route, error) { + var routes []caddyhttp.Route + + matchersAndTokens, err := st.tokensToMatcherSets(tkns, matcherDefs, warnings) + if err != nil { + return nil, err + } + + for _, mst := range matchersAndTokens { + var route caddyhttp.Route + + d := caddyfile.NewDispenser("Caddyfile", mst.tokens) + + for d.Next() { + if !d.NextArg() { + return nil, d.ArgErr() + } + to := d.Val() + + var code string + if d.NextArg() { + code = d.Val() + } + if code == "permanent" { + code = "301" + } + if code == "temporary" || code == "" { + code = "307" + } + var body string + if code == "meta" { + // Script tag comes first since that will better imitate a redirect in the browser's + // history, but the meta tag is a fallback for most non-JS clients. + const metaRedir = `<!DOCTYPE html> +<html> + <head> + <title>Redirecting...</title> + <script>window.location.replace("%s");</script> + <meta http-equiv="refresh" content="0; URL='%s'"> + </head> + <body>Redirecting to <a href="%s">%s</a>...</body> +</html> +` + safeTo := html.EscapeString(to) + body = fmt.Sprintf(metaRedir, safeTo, safeTo, safeTo, safeTo) + } + + handler := caddyhttp.StaticResponse{ + StatusCode: caddyhttp.WeakString(code), + Headers: http.Header{"Location": []string{to}}, + Body: body, + } + + route.Handle = append(route.Handle, + caddyconfig.JSONModuleObject(handler, "handler", "static_response", warnings)) + } + + if mst.matcherSet != nil { + route.MatcherSets = []map[string]json.RawMessage{mst.matcherSet} + } + + routes = append(routes, route) + } + + return routes, nil +} + +func (st *ServerType) parseTLSAutomationManager(d *caddyfile.Dispenser) (caddytls.ACMEManagerMaker, error) { + var m caddytls.ACMEManagerMaker + + for d.Next() { + firstLine := d.RemainingArgs() + if len(firstLine) == 1 && firstLine[0] != "off" { + m.Email = firstLine[0] + } + + var hasBlock bool + for d.NextBlock() { + hasBlock = true + switch d.Val() { + case "ca": + arg := d.RemainingArgs() + if len(arg) != 1 { + return m, d.ArgErr() + } + m.CA = arg[0] + // TODO: other properties + } + } + + // a naked tls directive is not allowed + if len(firstLine) == 0 && !hasBlock { + return m, d.ArgErr() + } + } + + return m, nil +} + +func (st *ServerType) parseTLSCerts(d *caddyfile.Dispenser) (map[string]caddytls.CertificateLoader, error) { + var fileLoader caddytls.FileLoader + var folderLoader caddytls.FolderLoader + + for d.Next() { + // file loader + firstLine := d.RemainingArgs() + if len(firstLine) == 2 { + fileLoader = append(fileLoader, caddytls.CertKeyFilePair{ + Certificate: firstLine[0], + Key: firstLine[1], + // TODO: tags, for enterprise module's certificate selection + }) + } + + // folder loader + for d.NextBlock() { + if d.Val() == "load" { + folderLoader = append(folderLoader, d.RemainingArgs()...) + } + } + } + + // put configured loaders into the map + loaders := make(map[string]caddytls.CertificateLoader) + if len(fileLoader) > 0 { + loaders["load_files"] = fileLoader + } + if len(folderLoader) > 0 { + loaders["load_folders"] = folderLoader + } + + return loaders, nil +} + +func (st *ServerType) parseTLSConnPolicy(d *caddyfile.Dispenser) (*caddytls.ConnectionPolicy, error) { + cp := new(caddytls.ConnectionPolicy) + + for d.Next() { + for d.NextBlock() { + switch d.Val() { + case "protocols": + args := d.RemainingArgs() + if len(args) == 0 { + return nil, d.SyntaxErr("one or two protocols") + } + if len(args) > 0 { + if _, ok := caddytls.SupportedProtocols[args[0]]; !ok { + return nil, d.Errf("Wrong protocol name or protocol not supported: '%s'", args[0]) + } + cp.ProtocolMin = args[0] + } + if len(args) > 1 { + if _, ok := caddytls.SupportedProtocols[args[1]]; !ok { + return nil, d.Errf("Wrong protocol name or protocol not supported: '%s'", args[1]) + } + cp.ProtocolMax = args[1] + } + case "ciphers": + for d.NextArg() { + if _, ok := caddytls.SupportedCipherSuites[d.Val()]; !ok { + return nil, d.Errf("Wrong cipher suite name or cipher suite not supported: '%s'", d.Val()) + } + cp.CipherSuites = append(cp.CipherSuites, d.Val()) + } + case "curves": + for d.NextArg() { + if _, ok := caddytls.SupportedCurves[d.Val()]; !ok { + return nil, d.Errf("Wrong curve name or curve not supported: '%s'", d.Val()) + } + cp.Curves = append(cp.Curves, d.Val()) + } + case "alpn": + args := d.RemainingArgs() + if len(args) == 0 { + return nil, d.ArgErr() + } + cp.ALPN = args + } + } + } + + return cp, nil +} |