// ParseRoller parses roller contents out of c. func ParseRoller(c *caddy.Controller) (*LogRoller, error) { var size, age, keep int // This is kind of a hack to support nested blocks: // As we are already in a block: either log or errors, // c.nesting > 0 but, as soon as c meets a }, it thinks // the block is over and return false for c.NextBlock. for c.NextBlock() { what := c.Val() if !c.NextArg() { return nil, c.ArgErr() } value := c.Val() var err error switch what { case "size": size, err = strconv.Atoi(value) case "age": age, err = strconv.Atoi(value) case "keep": keep, err = strconv.Atoi(value) } if err != nil { return nil, err } } return &LogRoller{ MaxSize: size, MaxAge: age, MaxBackups: keep, LocalTime: true, }, nil }
// Assert only one arg and return it func StringArg(c *caddy.Controller) (string, error) { args := c.RemainingArgs() if len(args) != 1 { return "", c.ArgErr() } return args[0], nil }
func singleArg(c *caddy.Controller, desc string) (string, error) { args := c.RemainingArgs() if len(args) != 1 { return "", c.Errf("%s expects exactly one argument", desc) } return args[0], nil }
// setup configures a new Git service routine. func setup(c *caddy.Controller) error { git, err := parse(c) if err != nil { return err } // repos configured with webhooks var hookRepos []*Repo // functions to execute at startup var startupFuncs []func() error // loop through all repos and and start monitoring for i := range git { repo := git.Repo(i) // If a HookUrl is set, we switch to event based pulling. // Install the url handler if repo.Hook.URL != "" { hookRepos = append(hookRepos, repo) startupFuncs = append(startupFuncs, func() error { return repo.Pull() }) } else { startupFuncs = append(startupFuncs, func() error { // Start service routine in background Start(repo) // Do a pull right away to return error return repo.Pull() }) } } // ensure the functions are executed once per server block // for cases like server1.com, server2.com { ... } c.OncePerServerBlock(func() error { for i := range startupFuncs { c.OnStartup(startupFuncs[i]) } return nil }) // if there are repo(s) with webhook // return handler if len(hookRepos) > 0 { webhook := &WebHook{Repos: hookRepos} httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler { webhook.Next = next return webhook }) } return nil }
// setup sets up the logging middleware. func setup(c *caddy.Controller) error { rules, err := logParse(c) if err != nil { return err } // Open the log files for writing when the server starts c.OnStartup(func() error { for i := 0; i < len(rules); i++ { var err error var writer io.Writer if rules[i].OutputFile == "stdout" { writer = os.Stdout } else if rules[i].OutputFile == "stderr" { writer = os.Stderr } else if rules[i].OutputFile == "syslog" { writer, err = gsyslog.NewLogger(gsyslog.LOG_INFO, "LOCAL0", "caddy") if err != nil { return err } } else { var file *os.File file, err = os.OpenFile(rules[i].OutputFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) if err != nil { return err } if rules[i].Roller != nil { file.Close() rules[i].Roller.Filename = rules[i].OutputFile writer = rules[i].Roller.GetLogWriter() } else { rules[i].file = file writer = file } } rules[i].Log = log.New(writer, "", 0) } return nil }) // When server stops, close any open log files c.OnShutdown(func() error { for _, rule := range rules { if rule.file != nil { rule.file.Close() } } return nil }) httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler { return Logger{Next: next, Rules: rules, ErrorFunc: httpserver.DefaultErrorFunc} }) return nil }
// setup configures a new errors middleware instance. func setup(c *caddy.Controller) error { handler, err := errorsParse(c) if err != nil { return err } // Open the log file for writing when the server starts c.OnStartup(func() error { var err error var writer io.Writer switch handler.LogFile { case "visible": handler.Debug = true case "stdout": writer = os.Stdout case "stderr": writer = os.Stderr case "syslog": writer, err = gsyslog.NewLogger(gsyslog.LOG_ERR, "LOCAL0", "caddy") if err != nil { return err } default: if handler.LogFile == "" { writer = os.Stderr // default break } var file *os.File file, err = os.OpenFile(handler.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) if err != nil { return err } if handler.LogRoller != nil { file.Close() handler.LogRoller.Filename = handler.LogFile writer = handler.LogRoller.GetLogWriter() } else { writer = file } } handler.Log = log.New(writer, "", 0) return nil }) httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler { handler.Next = next return handler }) return nil }
// GetConfig gets the SiteConfig that corresponds to c. // If none exist (should only happen in tests), then a // new, empty one will be created. func GetConfig(c *caddy.Controller) *SiteConfig { ctx := c.Context().(*httpContext) if cfg, ok := ctx.keysToSiteConfigs[c.Key]; ok { return cfg } // we should only get here during tests because directive // actions typically skip the server blocks where we make // the configs ctx.saveConfig(c.Key, &SiteConfig{Root: Root, TLS: new(caddytls.Config)}) return GetConfig(c) }
func browseParse(c *caddy.Controller) ([]Config, error) { var configs []Config cfg := httpserver.GetConfig(c) appendCfg := func(bc Config) error { for _, c := range configs { if c.PathScope == bc.PathScope { return fmt.Errorf("duplicate browsing config for %s", c.PathScope) } } configs = append(configs, bc) return nil } for c.Next() { var bc Config // First argument is directory to allow browsing; default is site root if c.NextArg() { bc.PathScope = c.Val() } else { bc.PathScope = "/" } bc.Root = http.Dir(cfg.Root) // Second argument would be the template file to use var tplText string if c.NextArg() { tplBytes, err := ioutil.ReadFile(c.Val()) if err != nil { return configs, err } tplText = string(tplBytes) } else { tplText = defaultTemplate } // Build the template tpl, err := template.New("listing").Parse(tplText) if err != nil { return configs, err } bc.Template = tpl // Save configuration err = appendCfg(bc) if err != nil { return configs, err } } return configs, nil }
// setup used internally by Caddy to set up this middleware func setup(c *caddy.Controller) error { mc, err := parse(c) if err != nil { return err } if c.ServerBlockKeyIndex == 0 { // only run when the first hostname has been loaded. if mc.maillog, err = mc.maillog.Init(c.ServerBlockKeys...); err != nil { return err } if err = mc.loadFromEnv(); err != nil { return err } if err = mc.loadPGPKeys(); err != nil { return err } if err = mc.loadTemplate(); err != nil { return err } if err = mc.pingSMTP(); err != nil { return err } c.ServerBlockStorage = newHandler(mc, startMailDaemon(mc)) } c.OnShutdown(func() error { if moh, ok := c.ServerBlockStorage.(*handler); ok { if moh.reqPipe != nil { close(moh.reqPipe) moh.reqPipe = nil } } return nil }) fmt.Printf("%#v\n\n", c) if moh, ok := c.ServerBlockStorage.(*handler); ok { // moh = mailOutHandler ;-) httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler { moh.Next = next return moh }) return nil } return errors.New("[mailout] Could not create the middleware handler") }
// extParse sets up an instance of extension middleware // from a middleware controller and returns a list of extensions. func extParse(c *caddy.Controller) ([]string, error) { var exts []string for c.Next() { // At least one extension is required if !c.NextArg() { return exts, c.ArgErr() } exts = append(exts, c.Val()) // Tack on any other extensions that may have been listed exts = append(exts, c.RemainingArgs()...) } return exts, nil }
// registerCallback registers a callback function to execute by // using c to parse the directive. It registers the callback // to be executed using registerFunc. func registerCallback(c *caddy.Controller, registerFunc func(func() error)) error { var funcs []func() error for c.Next() { args := c.RemainingArgs() if len(args) == 0 { return c.ArgErr() } nonblock := false if len(args) > 1 && args[len(args)-1] == "&" { // Run command in background; non-blocking nonblock = true args = args[:len(args)-1] } command, args, err := caddy.SplitCommandAndArgs(strings.Join(args, " ")) if err != nil { return c.Err(err.Error()) } fn := func() error { cmd := exec.Command(command, args...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if nonblock { log.Printf("[INFO] Nonblocking Command:\"%s %s\"", command, strings.Join(args, " ")) return cmd.Start() } log.Printf("[INFO] Blocking Command:\"%s %s\"", command, strings.Join(args, " ")) return cmd.Run() } funcs = append(funcs, fn) } return c.OncePerServerBlock(func() error { for _, fn := range funcs { registerFunc(fn) } return nil }) }
func Setup(c *caddy.Controller) error { var m *module for c.Next() { if m != nil { return c.Err("cannot specify realip more than once") } m = &module{ Header: "X-Forwarded-For", } if err := parse(m, c); err != nil { return err } } httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler { m.next = next return m }) return nil }
func internalParse(c *caddy.Controller) ([]string, error) { var paths []string for c.Next() { if !c.NextArg() { return paths, c.ArgErr() } paths = append(paths, c.Val()) } return paths, nil }
// ipfilterParse parses all ipfilter {} blocks to an IPFConfig func ipfilterParse(c *caddy.Controller) (IPFConfig, error) { var config IPFConfig var hasCountryCodes, hasRanges bool for c.Next() { path, err := ipfilterParseSingle(&config, c) if err != nil { return config, err } if len(path.CountryCodes) != 0 { hasCountryCodes = true } if len(path.Nets) != 0 { hasRanges = true } config.Paths = append(config.Paths, path) } // having a database is mandatory if you are blocking by country codes. if hasCountryCodes && config.DBHandler == nil { return config, c.Err("ipfilter: Database is required to block/allow by country") } // needs atleast one of the three. if !hasCountryCodes && !hasRanges { return config, c.Err("ipfilter: No IPs or Country codes has been provided") } return config, nil }
// IfMatcherKeyword checks if the next value in the dispenser is a keyword for 'if' config block. // If true, remaining arguments in the dispinser are cleard to keep the dispenser valid for use. func IfMatcherKeyword(c *caddy.Controller) bool { if c.Val() == "if" || c.Val() == "if_op" { // clear remainig args c.RemainingArgs() return true } return false }
func jsonpParse(c *caddy.Controller) ([]string, error) { var paths []string if db1 { fmt.Printf("jsonpParse called\n") } for c.Next() { if !c.NextArg() { return paths, c.ArgErr() } paths = append(paths, c.Val()) } return paths, nil }
func setupRoot(c *caddy.Controller) error { config := httpserver.GetConfig(c) for c.Next() { if !c.NextArg() { return c.ArgErr() } config.Root = c.Val() } // Check if root path exists _, err := os.Stat(config.Root) if err != nil { if os.IsNotExist(err) { // Allow this, because the folder might appear later. // But make sure the user knows! log.Printf("[WARNING] Root path does not exist: %s", config.Root) } else { return c.Errf("Unable to access root path '%s': %v", config.Root, err) } } return nil }
func setupBind(c *caddy.Controller) error { config := httpserver.GetConfig(c) for c.Next() { if !c.Args(&config.ListenHost) { return c.ArgErr() } config.TLS.ListenHost = config.ListenHost // necessary for ACME challenges, see issue #309 } return nil }
func markdownParse(c *caddy.Controller) ([]*Config, error) { var mdconfigs []*Config for c.Next() { md := &Config{ Renderer: blackfriday.HtmlRenderer(0, "", ""), Extensions: make(map[string]struct{}), Template: GetDefaultTemplate(), } // Get the path scope args := c.RemainingArgs() switch len(args) { case 0: md.PathScope = "/" case 1: md.PathScope = args[0] default: return mdconfigs, c.ArgErr() } // Load any other configuration parameters for c.NextBlock() { if err := loadParams(c, md); err != nil { return mdconfigs, err } } // If no extensions were specified, assume some defaults if len(md.Extensions) == 0 { md.Extensions[".md"] = struct{}{} md.Extensions[".markdown"] = struct{}{} md.Extensions[".mdown"] = struct{}{} } mdconfigs = append(mdconfigs, md) } return mdconfigs, nil }
func BoolArg(c *caddy.Controller) (bool, error) { args := c.RemainingArgs() if len(args) > 1 { return false, c.ArgErr() } if len(args) == 0 { return true, nil } switch args[0] { case "false": return false, nil case "true": return true, nil default: return false, c.Errf("Unexpected bool value: %s", args[0]) } }
func expVarParse(c *caddy.Controller) (Resource, error) { var resource Resource var err error for c.Next() { args := c.RemainingArgs() switch len(args) { case 0: resource = Resource(defaultExpvarPath) case 1: resource = Resource(args[0]) default: return resource, c.ArgErr() } } return resource, err }
// statusParse parses status directive func statusParse(c *caddy.Controller) ([]httpserver.HandlerConfig, error) { var rules []httpserver.HandlerConfig for c.Next() { hadBlock := false args := c.RemainingArgs() switch len(args) { case 1: status, err := strconv.Atoi(args[0]) if err != nil { return rules, c.Errf("Expecting a numeric status code, got '%s'", args[0]) } for c.NextBlock() { hadBlock = true basePath := c.Val() for _, cfg := range rules { rule := cfg.(*Rule) if rule.Base == basePath { return rules, c.Errf("Duplicate path: '%s'", basePath) } } rule := NewRule(basePath, status) rules = append(rules, rule) if c.NextArg() { return rules, c.ArgErr() } } if !hadBlock { return rules, c.ArgErr() } case 2: status, err := strconv.Atoi(args[0]) if err != nil { return rules, c.Errf("Expecting a numeric status code, got '%s'", args[0]) } basePath := args[1] for _, cfg := range rules { rule := cfg.(*Rule) if rule.Base == basePath { return rules, c.Errf("Duplicate path: '%s'", basePath) } } rule := NewRule(basePath, status) rules = append(rules, rule) default: return rules, c.ArgErr() } } return rules, nil }
func rewriteParse(c *caddy.Controller) ([]httpserver.HandlerConfig, error) { var rules []httpserver.HandlerConfig for c.Next() { var rule Rule var err error var base = "/" var pattern, to string var ext []string args := c.RemainingArgs() var matcher httpserver.RequestMatcher switch len(args) { case 1: base = args[0] fallthrough case 0: // Integrate request matcher for 'if' conditions. matcher, err = httpserver.SetupIfMatcher(c) if err != nil { return nil, err } for c.NextBlock() { if httpserver.IfMatcherKeyword(c) { continue } switch c.Val() { case "r", "regexp": if !c.NextArg() { return nil, c.ArgErr() } pattern = c.Val() case "to": args1 := c.RemainingArgs() if len(args1) == 0 { return nil, c.ArgErr() } to = strings.Join(args1, " ") case "ext": args1 := c.RemainingArgs() if len(args1) == 0 { return nil, c.ArgErr() } ext = args1 default: return nil, c.ArgErr() } } // ensure to is specified if to == "" { return nil, c.ArgErr() } if rule, err = NewComplexRule(base, pattern, to, ext, matcher); err != nil { return nil, err } rules = append(rules, rule) // the only unhandled case is 2 and above default: rule = NewSimpleRule(args[0], strings.Join(args[1:], " ")) rules = append(rules, rule) } } return rules, nil }
func parse(m *module, c *caddy.Controller) (err error) { args := c.RemainingArgs() if len(args) == 1 && args[0] == "cloudflare" { addCloudflareIps(m) if c.NextBlock() { return c.Err("No realip subblocks allowed if using preset.") } } else if len(args) != 0 { return c.ArgErr() } for c.NextBlock() { var err error switch c.Val() { case "header": m.Header, err = StringArg(c) case "from": var cidr *net.IPNet cidr, err = CidrArg(c) m.From = append(m.From, cidr) case "strict": m.Strict, err = BoolArg(c) default: return c.Errf("Unknown realip arg: %s", c.Val()) } if err != nil { return err } } return nil }
func errorsParse(c *caddy.Controller) (*ErrorHandler, error) { // Very important that we make a pointer because the startup // function that opens the log file must have access to the // same instance of the handler, not a copy. handler := &ErrorHandler{ErrorPages: make(map[int]string)} cfg := httpserver.GetConfig(c) optionalBlock := func() (bool, error) { var hadBlock bool for c.NextBlock() { hadBlock = true what := c.Val() if !c.NextArg() { return hadBlock, c.ArgErr() } where := c.Val() if what == "log" { if where == "visible" { handler.Debug = true } else { handler.LogFile = where if c.NextArg() { if c.Val() == "{" { c.IncrNest() logRoller, err := httpserver.ParseRoller(c) if err != nil { return hadBlock, err } handler.LogRoller = logRoller } } } } else { // Error page; ensure it exists where = filepath.Join(cfg.Root, where) f, err := os.Open(where) if err != nil { log.Printf("[WARNING] Unable to open error page '%s': %v", where, err) } f.Close() if what == "*" { if handler.GenericErrorPage != "" { return hadBlock, c.Errf("Duplicate status code entry: %s", what) } handler.GenericErrorPage = where } else { whatInt, err := strconv.Atoi(what) if err != nil { return hadBlock, c.Err("Expecting a numeric status code or '*', got '" + what + "'") } if _, exists := handler.ErrorPages[whatInt]; exists { return hadBlock, c.Errf("Duplicate status code entry: %s", what) } handler.ErrorPages[whatInt] = where } } } return hadBlock, nil } for c.Next() { // weird hack to avoid having the handler values overwritten. if c.Val() == "}" { continue } // Configuration may be in a block hadBlock, err := optionalBlock() if err != nil { return handler, err } // Otherwise, the only argument would be an error log file name or 'visible' if !hadBlock { if c.NextArg() { if c.Val() == "visible" { handler.Debug = true } else { handler.LogFile = c.Val() } } } } return handler, nil }
func webSocketParse(c *caddy.Controller) ([]Config, error) { var websocks []Config var respawn bool optionalBlock := func() (hadBlock bool, err error) { for c.NextBlock() { hadBlock = true if c.Val() == "respawn" { respawn = true } else { return true, c.Err("Expected websocket configuration parameter in block") } } return } for c.Next() { var val, path, command string // Path or command; not sure which yet if !c.NextArg() { return nil, c.ArgErr() } val = c.Val() // Extra configuration may be in a block hadBlock, err := optionalBlock() if err != nil { return nil, err } if !hadBlock { // The next argument on this line will be the command or an open curly brace if c.NextArg() { path = val command = c.Val() } else { path = "/" command = val } // Okay, check again for optional block _, err = optionalBlock() if err != nil { return nil, err } } // Split command into the actual command and its arguments cmd, args, err := caddy.SplitCommandAndArgs(command) if err != nil { return nil, err } websocks = append(websocks, Config{ Path: path, Command: cmd, Arguments: args, Respawn: respawn, // TODO: This isn't used currently }) } return websocks, nil }
func NoArgs(c *caddy.Controller) error { if len(c.RemainingArgs()) != 0 { return c.ArgErr() } return nil }
// loadCertsInDir loads all the certificates/keys in dir, as long as // the file ends with .pem. This method of loading certificates is // modeled after haproxy, which expects the certificate and key to // be bundled into the same file: // https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#5.1-crt // // This function may write to the log as it walks the directory tree. func loadCertsInDir(c *caddy.Controller, dir string) error { return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { log.Printf("[WARNING] Unable to traverse into %s; skipping", path) return nil } if info.IsDir() { return nil } if strings.HasSuffix(strings.ToLower(info.Name()), ".pem") { certBuilder, keyBuilder := new(bytes.Buffer), new(bytes.Buffer) var foundKey bool // use only the first key in the file bundle, err := ioutil.ReadFile(path) if err != nil { return err } for { // Decode next block so we can see what type it is var derBlock *pem.Block derBlock, bundle = pem.Decode(bundle) if derBlock == nil { break } if derBlock.Type == "CERTIFICATE" { // Re-encode certificate as PEM, appending to certificate chain pem.Encode(certBuilder, derBlock) } else if derBlock.Type == "EC PARAMETERS" { // EC keys generated from openssl can be composed of two blocks: // parameters and key (parameter block should come first) if !foundKey { // Encode parameters pem.Encode(keyBuilder, derBlock) // Key must immediately follow derBlock, bundle = pem.Decode(bundle) if derBlock == nil || derBlock.Type != "EC PRIVATE KEY" { return c.Errf("%s: expected elliptic private key to immediately follow EC parameters", path) } pem.Encode(keyBuilder, derBlock) foundKey = true } } else if derBlock.Type == "PRIVATE KEY" || strings.HasSuffix(derBlock.Type, " PRIVATE KEY") { // RSA key if !foundKey { pem.Encode(keyBuilder, derBlock) foundKey = true } } else { return c.Errf("%s: unrecognized PEM block type: %s", path, derBlock.Type) } } certPEMBytes, keyPEMBytes := certBuilder.Bytes(), keyBuilder.Bytes() if len(certPEMBytes) == 0 { return c.Errf("%s: failed to parse PEM data", path) } if len(keyPEMBytes) == 0 { return c.Errf("%s: no private key block found", path) } err = cacheUnmanagedCertificatePEMBytes(certPEMBytes, keyPEMBytes) if err != nil { return c.Errf("%s: failed to load cert and key for '%s': %v", path, c.Key, err) } log.Printf("[INFO] Successfully loaded TLS assets from %s", path) } return nil }) }
// setupTLS sets up the TLS configuration and installs certificates that // are specified by the user in the config file. All the automatic HTTPS // stuff comes later outside of this function. func setupTLS(c *caddy.Controller) error { configGetter, ok := configGetters[c.ServerType()] if !ok { return fmt.Errorf("no caddytls.ConfigGetter for %s server type; must call RegisterConfigGetter", c.ServerType()) } config := configGetter(c) if config == nil { return fmt.Errorf("no caddytls.Config to set up for %s", c.Key) } config.Enabled = true for c.Next() { var certificateFile, keyFile, loadDir, maxCerts string args := c.RemainingArgs() switch len(args) { case 1: // even if the email is one of the special values below, // it is still necessary for future analysis that we store // that value in the ACMEEmail field. config.ACMEEmail = args[0] // user can force-disable managed TLS this way if args[0] == "off" { config.Enabled = false return nil } // user might want a temporary, in-memory, self-signed cert if args[0] == "self_signed" { config.SelfSigned = true } case 2: certificateFile = args[0] keyFile = args[1] config.Manual = true } // Optional block with extra parameters var hadBlock bool for c.NextBlock() { hadBlock = true switch c.Val() { case "key_type": arg := c.RemainingArgs() value, ok := supportedKeyTypes[strings.ToUpper(arg[0])] if !ok { return c.Errf("Wrong key type name or key type not supported: '%s'", c.Val()) } config.KeyType = value case "protocols": args := c.RemainingArgs() if len(args) == 1 { value, ok := supportedProtocols[strings.ToLower(args[0])] if !ok { return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0]) } config.ProtocolMinVersion, config.ProtocolMaxVersion = value, value } else { value, ok := supportedProtocols[strings.ToLower(args[0])] if !ok { return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0]) } config.ProtocolMinVersion = value value, ok = supportedProtocols[strings.ToLower(args[1])] if !ok { return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[1]) } config.ProtocolMaxVersion = value if config.ProtocolMinVersion > config.ProtocolMaxVersion { return c.Errf("Minimum protocol version cannot be higher than maximum (reverse the order)") } } case "ciphers": for c.NextArg() { value, ok := supportedCiphersMap[strings.ToUpper(c.Val())] if !ok { return c.Errf("Wrong cipher name or cipher not supported: '%s'", c.Val()) } config.Ciphers = append(config.Ciphers, value) } case "clients": clientCertList := c.RemainingArgs() if len(clientCertList) == 0 { return c.ArgErr() } listStart, mustProvideCA := 1, true switch clientCertList[0] { case "request": config.ClientAuth = tls.RequestClientCert mustProvideCA = false case "require": config.ClientAuth = tls.RequireAnyClientCert mustProvideCA = false case "verify_if_given": config.ClientAuth = tls.VerifyClientCertIfGiven default: config.ClientAuth = tls.RequireAndVerifyClientCert listStart = 0 } if mustProvideCA && len(clientCertList) <= listStart { return c.ArgErr() } config.ClientCerts = clientCertList[listStart:] case "load": c.Args(&loadDir) config.Manual = true case "max_certs": c.Args(&maxCerts) config.OnDemand = true case "dns": args := c.RemainingArgs() if len(args) != 1 { return c.ArgErr() } dnsProvName := args[0] if _, ok := dnsProviders[dnsProvName]; !ok { return c.Errf("Unsupported DNS provider '%s'", args[0]) } config.DNSProvider = args[0] case "storage": args := c.RemainingArgs() if len(args) != 1 { return c.ArgErr() } storageProvName := args[0] if _, ok := storageProviders[storageProvName]; !ok { return c.Errf("Unsupported Storage provider '%s'", args[0]) } config.StorageProvider = args[0] default: return c.Errf("Unknown keyword '%s'", c.Val()) } } // tls requires at least one argument if a block is not opened if len(args) == 0 && !hadBlock { return c.ArgErr() } // set certificate limit if on-demand TLS is enabled if maxCerts != "" { maxCertsNum, err := strconv.Atoi(maxCerts) if err != nil || maxCertsNum < 1 { return c.Err("max_certs must be a positive integer") } config.OnDemandState.MaxObtain = int32(maxCertsNum) } // don't try to load certificates unless we're supposed to if !config.Enabled || !config.Manual { continue } // load a single certificate and key, if specified if certificateFile != "" && keyFile != "" { err := cacheUnmanagedCertificatePEMFile(certificateFile, keyFile) if err != nil { return c.Errf("Unable to load certificate and key files for '%s': %v", c.Key, err) } log.Printf("[INFO] Successfully loaded TLS assets from %s and %s", certificateFile, keyFile) } // load a directory of certificates, if specified if loadDir != "" { err := loadCertsInDir(c, loadDir) if err != nil { return err } } } SetDefaultTLSParams(config) // generate self-signed cert if needed if config.SelfSigned { err := makeSelfSignedCert(config) if err != nil { return fmt.Errorf("self-signed: %v", err) } } return nil }
func setupMaxRequestBody(c *caddy.Controller) error { config := httpserver.GetConfig(c) if !c.Next() { return c.ArgErr() } args := c.RemainingArgs() argList := []pathLimitUnparsed{} switch len(args) { case 0: // Format: { <path> <limit> ... } for c.NextBlock() { path := c.Val() if !c.NextArg() { // Uneven pairing of path/limit return c.ArgErr() } argList = append(argList, pathLimitUnparsed{ Path: path, Limit: c.Val(), }) } case 1: // Format: <limit> argList = []pathLimitUnparsed{{ Path: "/", Limit: args[0], }} case 2: // Format: <path> <limit> argList = []pathLimitUnparsed{{ Path: args[0], Limit: args[1], }} default: return c.ArgErr() } pathLimit, err := parseArguments(argList) if err != nil { return c.ArgErr() } SortPathLimits(pathLimit) config.MaxRequestBodySizes = pathLimit return nil }