mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-04 03:27:23 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			169 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.4 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 = "."
 | 
						|
 | 
						|
	// The default configuration file to load if none 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
 | 
						|
)
 |