mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-27 10:49:47 +08:00
170 lines
4.5 KiB
Go
170 lines
4.5 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
|
|
"github.com/mholt/caddy/app"
|
|
"github.com/mholt/caddy/config/parse"
|
|
"github.com/mholt/caddy/config/setup"
|
|
"github.com/mholt/caddy/middleware"
|
|
"github.com/mholt/caddy/server"
|
|
)
|
|
|
|
const (
|
|
DefaultHost = "0.0.0.0"
|
|
DefaultPort = "2015"
|
|
DefaultRoot = "."
|
|
|
|
// DefaultConfigFile is the name of the configuration file that is loaded
|
|
// by default if no other file is specified.
|
|
DefaultConfigFile = "Caddyfile"
|
|
)
|
|
|
|
func Load(filename string, input io.Reader) ([]server.Config, error) {
|
|
var configs []server.Config
|
|
|
|
// turn off timestamp for parsing
|
|
flags := log.Flags()
|
|
log.SetFlags(0)
|
|
|
|
serverBlocks, err := parse.ServerBlocks(filename, input)
|
|
if err != nil {
|
|
return configs, err
|
|
}
|
|
|
|
// Each server block represents a single server/address.
|
|
// Iterate each server block and make a config for each one,
|
|
// executing the directives that were parsed.
|
|
for _, sb := range serverBlocks {
|
|
config := server.Config{
|
|
Host: sb.Host,
|
|
Port: sb.Port,
|
|
Root: Root,
|
|
Middleware: make(map[string][]middleware.Middleware),
|
|
ConfigFile: filename,
|
|
AppName: app.Name,
|
|
AppVersion: app.Version,
|
|
}
|
|
|
|
// It is crucial that directives are executed in the proper order.
|
|
for _, 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, which is the
|
|
// server config and the dispenser containing only
|
|
// this directive's tokens.
|
|
controller := &setup.Controller{
|
|
Config: &config,
|
|
Dispenser: parse.NewDispenserTokens(filename, tokens),
|
|
}
|
|
|
|
midware, err := dir.setup(controller)
|
|
if err != nil {
|
|
return configs, err
|
|
}
|
|
if midware != nil {
|
|
// TODO: For now, we only support the default path scope /
|
|
config.Middleware["/"] = append(config.Middleware["/"], midware)
|
|
}
|
|
}
|
|
}
|
|
|
|
if config.Port == "" {
|
|
config.Port = Port
|
|
}
|
|
|
|
configs = append(configs, config)
|
|
}
|
|
|
|
// restore logging settings
|
|
log.SetFlags(flags)
|
|
|
|
return configs, nil
|
|
}
|
|
|
|
// ArrangeBindings groups configurations by their bind address. For example,
|
|
// a server that should listen on localhost and another on 127.0.0.1 will
|
|
// be grouped into the same address: 127.0.0.1. It will return an error
|
|
// if the address lookup fails or if a TLS listener is configured on the
|
|
// same address as a plaintext HTTP listener. The return value is a map of
|
|
// bind address to list of configs that would become VirtualHosts on that
|
|
// server.
|
|
func ArrangeBindings(allConfigs []server.Config) (map[*net.TCPAddr][]server.Config, error) {
|
|
addresses := make(map[*net.TCPAddr][]server.Config)
|
|
|
|
// Group configs by bind address
|
|
for _, conf := range allConfigs {
|
|
newAddr, err := net.ResolveTCPAddr("tcp", conf.Address())
|
|
if err != nil {
|
|
return addresses, errors.New("could not serve " + conf.Address() + " - " + err.Error())
|
|
}
|
|
|
|
// Make sure to compare the string representation of the address,
|
|
// not the pointer, since a new *TCPAddr is created each time.
|
|
var existing bool
|
|
for addr := range addresses {
|
|
if addr.String() == newAddr.String() {
|
|
addresses[addr] = append(addresses[addr], conf)
|
|
existing = true
|
|
break
|
|
}
|
|
}
|
|
if !existing {
|
|
addresses[newAddr] = append(addresses[newAddr], conf)
|
|
}
|
|
}
|
|
|
|
// Don't allow HTTP and HTTPS to be served on the same address
|
|
for _, configs := range addresses {
|
|
isTLS := configs[0].TLS.Enabled
|
|
for _, config := range configs {
|
|
if config.TLS.Enabled != isTLS {
|
|
thisConfigProto, otherConfigProto := "HTTP", "HTTP"
|
|
if config.TLS.Enabled {
|
|
thisConfigProto = "HTTPS"
|
|
}
|
|
if configs[0].TLS.Enabled {
|
|
otherConfigProto = "HTTPS"
|
|
}
|
|
return addresses, fmt.Errorf("configuration error: Cannot multiplex %s (%s) and %s (%s) on same address",
|
|
configs[0].Address(), otherConfigProto, config.Address(), thisConfigProto)
|
|
}
|
|
}
|
|
}
|
|
|
|
return addresses, nil
|
|
}
|
|
|
|
// validDirective returns true if d is a valid
|
|
// directive; false otherwise.
|
|
func validDirective(d string) bool {
|
|
for _, dir := range directiveOrder {
|
|
if dir.name == d {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Default makes a default configuration which
|
|
// is empty except for root, host, and port,
|
|
// which are essentials for serving the cwd.
|
|
func Default() server.Config {
|
|
return server.Config{
|
|
Root: Root,
|
|
Host: Host,
|
|
Port: Port,
|
|
}
|
|
}
|
|
|
|
// These three defaults are configurable through the command line
|
|
var (
|
|
Root = DefaultRoot
|
|
Host = DefaultHost
|
|
Port = DefaultPort
|
|
)
|