// loadConfigsUpToIncludingTLS loads the configs from input with name filename and returns them, // the parsed server blocks, the index of the last directive it processed, and an error (if any). func loadConfigsUpToIncludingTLS(filename string, input io.Reader) ([]server.Config, []parse.ServerBlock, int, error) { var configs []server.Config // Each server block represents similar hosts/addresses, since they // were grouped together in the Caddyfile. serverBlocks, err := parse.ServerBlocks(filename, input, true) if err != nil { return nil, nil, 0, err } if len(serverBlocks) == 0 { newInput := DefaultInput() serverBlocks, err = parse.ServerBlocks(newInput.Path(), bytes.NewReader(newInput.Body()), true) if err != nil { return nil, nil, 0, err } } var lastDirectiveIndex int // we set up directives in two parts; this stores where we left off // Iterate each server block and make a config for each one, // executing the directives that were parsed in order up to the tls // directive; this is because we must activate Let's Encrypt. for i, sb := range serverBlocks { onces := makeOnces() storages := makeStorages() for j, addr := range sb.Addresses { config := server.Config{ Host: addr.Host, Port: addr.Port, Scheme: addr.Scheme, Root: Root, ConfigFile: filename, AppName: AppName, AppVersion: AppVersion, } // It is crucial that directives are executed in the proper order. for k, dir := range directiveOrder { // Execute directive if it is in the server block if tokens, ok := sb.Tokens[dir.name]; ok { // Each setup function gets a controller, from which setup functions // get access to the config, tokens, and other state information useful // to set up its own host only. controller := &setup.Controller{ Config: &config, Dispenser: parse.NewDispenserTokens(filename, tokens), OncePerServerBlock: func(f func() error) error { var err error onces[dir.name].Do(func() { err = f() }) return err }, ServerBlockIndex: i, ServerBlockHostIndex: j, ServerBlockHosts: sb.HostList(), ServerBlockStorage: storages[dir.name], } // execute setup function and append middleware handler, if any midware, err := dir.setup(controller) if err != nil { return nil, nil, lastDirectiveIndex, err } if midware != nil { config.Middleware = append(config.Middleware, midware) } storages[dir.name] = controller.ServerBlockStorage // persist for this server block } // Stop after TLS setup, since we need to activate Let's Encrypt before continuing; // it makes some changes to the configs that middlewares might want to know about. if dir.name == "tls" { lastDirectiveIndex = k break } } configs = append(configs, config) } } return configs, serverBlocks, lastDirectiveIndex, nil }