0
Fork 0
mirror of https://github.com/caddyserver/caddy.git synced 2024-12-23 22:27:38 -05:00

Parser separate scheme/port, refactor config loading

By separating scheme and port at the parser, we are able to set the port appropriately and also keep the semantics of the scheme being specified by the user later on. The parser also stores an address' original input. Also, the config refactor makes it possible to partially load a config - valuable for determining which ones will need Let's Encrypt integration turned on during a restart.
This commit is contained in:
Matthew Holt 2016-01-03 16:41:29 -07:00
parent b0397df719
commit 946ff5e87b
7 changed files with 188 additions and 169 deletions

View file

@ -21,25 +21,22 @@ const (
DefaultConfigFile = "Caddyfile"
)
// loadConfigs reads input (named filename) and parses it, returning the
// server configurations in the order they appeared in the input. As part
// of this, it activates Let's Encrypt for the configs that are produced.
// Thus, the returned configs are already optimally configured optimally
// for HTTPS.
func loadConfigs(filename string, input io.Reader) ([]server.Config, error) {
// 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, err
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, err
return nil, nil, 0, err
}
}
@ -56,6 +53,7 @@ func loadConfigs(filename string, input io.Reader) ([]server.Config, error) {
config := server.Config{
Host: addr.Host,
Port: addr.Port,
Scheme: addr.Scheme,
Root: Root,
Middleware: make(map[string][]middleware.Middleware),
ConfigFile: filename,
@ -88,7 +86,7 @@ func loadConfigs(filename string, input io.Reader) ([]server.Config, error) {
// execute setup function and append middleware handler, if any
midware, err := dir.setup(controller)
if err != nil {
return nil, err
return nil, nil, lastDirectiveIndex, err
}
if midware != nil {
// TODO: For now, we only support the default path scope /
@ -109,22 +107,31 @@ func loadConfigs(filename string, input io.Reader) ([]server.Config, error) {
}
}
return configs, serverBlocks, lastDirectiveIndex, nil
}
// loadConfigs reads input (named filename) and parses it, returning the
// server configurations in the order they appeared in the input. As part
// of this, it activates Let's Encrypt for the configs that are produced.
// Thus, the returned configs are already optimally configured for HTTPS.
func loadConfigs(filename string, input io.Reader) ([]server.Config, error) {
configs, serverBlocks, lastDirectiveIndex, err := loadConfigsUpToIncludingTLS(filename, input)
if err != nil {
return nil, err
}
// Now we have all the configs, but they have only been set up to the
// point of tls. We need to activate Let's Encrypt before setting up
// the rest of the middlewares so they have correct information regarding
// TLS configuration, if necessary. (this call is append-only, so our
// iterations below shouldn't be affected)
// TLS configuration, if necessary. (this only appends, so our iterations
// over server blocks below shouldn't be affected)
if !IsRestart() && !Quiet {
fmt.Print("Activating privacy features...")
}
configs, err = letsencrypt.Activate(configs)
if err != nil {
if !Quiet {
fmt.Println()
}
return nil, err
}
if !IsRestart() && !Quiet {
} else if !IsRestart() && !Quiet {
fmt.Println(" done.")
}
@ -277,44 +284,17 @@ func arrangeBindings(allConfigs []server.Config) (bindingGroup, error) {
// but execution may continue. The second error, if not nil, is a real
// problem and the server should not be started.
//
// This function handles edge cases gracefully. If a port name like
// "http" or "https" is unknown to the system, this function will
// change them to 80 or 443 respectively. If a hostname fails to
// resolve, that host can still be served but will be listening on
// the wildcard host instead. This function takes care of this for you.
// This function does not handle edge cases like port "http" or "https" if
// they are not known to the system. It does, however, serve on the wildcard
// host if resolving the address of the specific hostname fails.
func resolveAddr(conf server.Config) (resolvAddr *net.TCPAddr, warnErr, fatalErr error) {
bindHost := conf.BindHost
// TODO: Do we even need the port? Maybe we just need to look up the host.
resolvAddr, warnErr = net.ResolveTCPAddr("tcp", net.JoinHostPort(bindHost, conf.Port))
resolvAddr, warnErr = net.ResolveTCPAddr("tcp", net.JoinHostPort(conf.BindHost, conf.Port))
if warnErr != nil {
// Most likely the host lookup failed or the port is unknown
tryPort := conf.Port
switch errVal := warnErr.(type) {
case *net.AddrError:
if errVal.Err == "unknown port" {
// some odd Linux machines don't support these port names; see issue #136
switch conf.Port {
case "http":
tryPort = "80"
case "https":
tryPort = "443"
}
}
resolvAddr, fatalErr = net.ResolveTCPAddr("tcp", net.JoinHostPort(bindHost, tryPort))
if fatalErr != nil {
return
}
default:
// the hostname probably couldn't be resolved, just bind to wildcard then
resolvAddr, fatalErr = net.ResolveTCPAddr("tcp", net.JoinHostPort("0.0.0.0", tryPort))
if fatalErr != nil {
return
}
// the hostname probably couldn't be resolved, just bind to wildcard then
resolvAddr, fatalErr = net.ResolveTCPAddr("tcp", net.JoinHostPort("", conf.Port))
if fatalErr != nil {
return
}
return
}
return
@ -334,12 +314,12 @@ func validDirective(d string) bool {
// DefaultInput returns the default Caddyfile input
// to use when it is otherwise empty or missing.
// It uses the default host and port (depends on
// host, e.g. localhost is 2015, otherwise https) and
// host, e.g. localhost is 2015, otherwise 443) and
// root.
func DefaultInput() CaddyfileInput {
port := Port
if letsencrypt.HostQualifies(Host) {
port = "https"
if letsencrypt.HostQualifies(Host) && port == DefaultPort {
port = "443"
}
return CaddyfileInput{
Contents: []byte(fmt.Sprintf("%s:%s\nroot %s", Host, port, Root)),

View file

@ -13,10 +13,10 @@ func TestDefaultInput(t *testing.T) {
t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual)
}
// next few tests simulate user providing -host flag
// next few tests simulate user providing -host and/or -port flags
Host = "not-localhost.com"
if actual, expected := string(DefaultInput().Body()), "not-localhost.com:https\nroot ."; actual != expected {
if actual, expected := string(DefaultInput().Body()), "not-localhost.com:443\nroot ."; actual != expected {
t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual)
}
@ -29,6 +29,18 @@ func TestDefaultInput(t *testing.T) {
if actual, expected := string(DefaultInput().Body()), "127.0.1.1:2015\nroot ."; actual != expected {
t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual)
}
Host = "not-localhost.com"
Port = "1234"
if actual, expected := string(DefaultInput().Body()), "not-localhost.com:1234\nroot ."; actual != expected {
t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual)
}
Host = DefaultHost
Port = "1234"
if actual, expected := string(DefaultInput().Body()), ":1234\nroot ."; actual != expected {
t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual)
}
}
func TestResolveAddr(t *testing.T) {
@ -51,14 +63,14 @@ func TestResolveAddr(t *testing.T) {
{server.Config{Host: "localhost", Port: "80"}, false, false, "<nil>", 80},
{server.Config{BindHost: "localhost", Port: "1234"}, false, false, "127.0.0.1", 1234},
{server.Config{BindHost: "127.0.0.1", Port: "1234"}, false, false, "127.0.0.1", 1234},
{server.Config{BindHost: "should-not-resolve", Port: "1234"}, true, false, "0.0.0.0", 1234},
{server.Config{BindHost: "should-not-resolve", Port: "1234"}, true, false, "<nil>", 1234},
{server.Config{BindHost: "localhost", Port: "http"}, false, false, "127.0.0.1", 80},
{server.Config{BindHost: "localhost", Port: "https"}, false, false, "127.0.0.1", 443},
{server.Config{BindHost: "", Port: "1234"}, false, false, "<nil>", 1234},
{server.Config{BindHost: "localhost", Port: "abcd"}, false, true, "", 0},
{server.Config{BindHost: "127.0.0.1", Host: "should-not-be-used", Port: "1234"}, false, false, "127.0.0.1", 1234},
{server.Config{BindHost: "localhost", Host: "should-not-be-used", Port: "1234"}, false, false, "127.0.0.1", 1234},
{server.Config{BindHost: "should-not-resolve", Host: "localhost", Port: "1234"}, true, false, "0.0.0.0", 1234},
{server.Config{BindHost: "should-not-resolve", Host: "localhost", Port: "1234"}, true, false, "<nil>", 1234},
} {
actualAddr, warnErr, fatalErr := resolveAddr(test.config)

View file

@ -8,7 +8,7 @@ import "io"
// If checkDirectives is true, only valid directives will be allowed
// otherwise we consider it a parse error. Server blocks are returned
// in the order in which they appear.
func ServerBlocks(filename string, input io.Reader, checkDirectives bool) ([]serverBlock, error) {
func ServerBlocks(filename string, input io.Reader, checkDirectives bool) ([]ServerBlock, error) {
p := parser{Dispenser: NewDispenser(filename, input)}
p.checkDirectives = checkDirectives
blocks, err := p.parseAll()

View file

@ -1,6 +1,7 @@
package parse
import (
"fmt"
"net"
"os"
"path/filepath"
@ -9,13 +10,13 @@ import (
type parser struct {
Dispenser
block serverBlock // current server block being parsed
block ServerBlock // current server block being parsed
eof bool // if we encounter a valid EOF in a hard place
checkDirectives bool // if true, directives must be known
}
func (p *parser) parseAll() ([]serverBlock, error) {
var blocks []serverBlock
func (p *parser) parseAll() ([]ServerBlock, error) {
var blocks []ServerBlock
for p.Next() {
err := p.parseOne()
@ -31,7 +32,7 @@ func (p *parser) parseAll() ([]serverBlock, error) {
}
func (p *parser) parseOne() error {
p.block = serverBlock{Tokens: make(map[string][]token)}
p.block = ServerBlock{Tokens: make(map[string][]token)}
err := p.begin()
if err != nil {
@ -99,11 +100,11 @@ func (p *parser) addresses() error {
}
// Parse and save this address
host, port, err := standardAddress(tkn)
addr, err := standardAddress(tkn)
if err != nil {
return err
}
p.block.Addresses = append(p.block.Addresses, address{host, port})
p.block.Addresses = append(p.block.Addresses, addr)
}
// Advance token and possibly break out of loop or return error
@ -273,39 +274,57 @@ func (p *parser) closeCurlyBrace() error {
return nil
}
// standardAddress turns the accepted host and port patterns
// into a format accepted by net.Dial.
func standardAddress(str string) (host, port string, err error) {
var schemePort, splitPort string
// standardAddress parses an address string into a structured format with separate
// scheme, host, and port portions, as well as the original input string.
func standardAddress(str string) (address, error) {
var scheme string
var err error
// first check for scheme and strip it off
input := str
if strings.HasPrefix(str, "https://") {
schemePort = "https"
scheme = "https"
str = str[8:]
} else if strings.HasPrefix(str, "http://") {
schemePort = "http"
scheme = "http"
str = str[7:]
}
host, splitPort, err = net.SplitHostPort(str)
// separate host and port
host, port, err := net.SplitHostPort(str)
if err != nil {
host, splitPort, err = net.SplitHostPort(str + ":") // tack on empty port
}
if err != nil {
// ¯\_(ツ)_/¯
host = str
host, port, err = net.SplitHostPort(str + ":")
// no error check here; return err at end of function
}
if splitPort != "" {
port = splitPort
} else {
port = schemePort
// see if we can set port based off scheme
if port == "" {
if scheme == "http" {
port = "80"
} else if scheme == "https" {
port = "443"
}
}
return
// repeated or conflicting scheme is confusing, so error
if scheme != "" && (port == "http" || port == "https") {
return address{}, fmt.Errorf("[%s] scheme specified twice in address", str)
}
// standardize http and https ports to their respective port numbers
if port == "http" {
scheme = "http"
port = "80"
} else if port == "https" {
scheme = "https"
port = "443"
}
return address{Original: input, Scheme: scheme, Host: host, Port: port}, err
}
// replaceEnvVars replaces environment variables that appear in the token
// and understands both the Unix $SYNTAX and Windows %SYNTAX%.
// and understands both the $UNIX and %WINDOWS% syntaxes.
func replaceEnvVars(s string) string {
s = replaceEnvReferences(s, "{%", "%}")
s = replaceEnvReferences(s, "{$", "}")
@ -330,26 +349,26 @@ func replaceEnvReferences(s, refStart, refEnd string) string {
}
type (
// serverBlock associates tokens with a list of addresses
// ServerBlock associates tokens with a list of addresses
// and groups tokens by directive name.
serverBlock struct {
ServerBlock struct {
Addresses []address
Tokens map[string][]token
}
address struct {
Host, Port string
Original, Scheme, Host, Port string
}
)
// HostList converts the list of addresses (hosts)
// that are associated with this server block into
// a slice of strings. Each string is a host:port
// combination.
func (sb serverBlock) HostList() []string {
// HostList converts the list of addresses that are
// associated with this server block into a slice of
// strings, where each address is as it was originally
// read from the input.
func (sb ServerBlock) HostList() []string {
sbHosts := make([]string, len(sb.Addresses))
for j, addr := range sb.Addresses {
sbHosts[j] = net.JoinHostPort(addr.Host, addr.Port)
sbHosts[j] = addr.Original
}
return sbHosts
}

View file

@ -8,51 +8,55 @@ import (
func TestStandardAddress(t *testing.T) {
for i, test := range []struct {
input string
host, port string
shouldErr bool
input string
scheme, host, port string
shouldErr bool
}{
{`localhost`, "localhost", "", false},
{`localhost:1234`, "localhost", "1234", false},
{`localhost:`, "localhost", "", false},
{`0.0.0.0`, "0.0.0.0", "", false},
{`127.0.0.1:1234`, "127.0.0.1", "1234", false},
{`:1234`, "", "1234", false},
{`[::1]`, "::1", "", false},
{`[::1]:1234`, "::1", "1234", false},
{`:`, "", "", false},
{`localhost:http`, "localhost", "http", false},
{`localhost:https`, "localhost", "https", false},
{`:http`, "", "http", false},
{`:https`, "", "https", false},
{`http://localhost`, "localhost", "http", false},
{`https://localhost`, "localhost", "https", false},
{`http://127.0.0.1`, "127.0.0.1", "http", false},
{`https://127.0.0.1`, "127.0.0.1", "https", false},
{`http://[::1]`, "::1", "http", false},
{`http://localhost:1234`, "localhost", "1234", false},
{`https://127.0.0.1:1234`, "127.0.0.1", "1234", false},
{`http://[::1]:1234`, "::1", "1234", false},
{``, "", "", false},
{`::1`, "::1", "", true},
{`localhost::`, "localhost::", "", true},
{`#$%@`, "#$%@", "", true},
{`localhost`, "", "localhost", "", false},
{`localhost:1234`, "", "localhost", "1234", false},
{`localhost:`, "", "localhost", "", false},
{`0.0.0.0`, "", "0.0.0.0", "", false},
{`127.0.0.1:1234`, "", "127.0.0.1", "1234", false},
{`:1234`, "", "", "1234", false},
{`[::1]`, "", "::1", "", false},
{`[::1]:1234`, "", "::1", "1234", false},
{`:`, "", "", "", false},
{`localhost:http`, "http", "localhost", "80", false},
{`localhost:https`, "https", "localhost", "443", false},
{`:http`, "http", "", "80", false},
{`:https`, "https", "", "443", false},
{`http://localhost:https`, "", "", "", true}, // conflict
{`http://localhost:http`, "", "", "", true}, // repeated scheme
{`http://localhost`, "http", "localhost", "80", false},
{`https://localhost`, "https", "localhost", "443", false},
{`http://127.0.0.1`, "http", "127.0.0.1", "80", false},
{`https://127.0.0.1`, "https", "127.0.0.1", "443", false},
{`http://[::1]`, "http", "::1", "80", false},
{`http://localhost:1234`, "http", "localhost", "1234", false},
{`https://127.0.0.1:1234`, "https", "127.0.0.1", "1234", false},
{`http://[::1]:1234`, "http", "::1", "1234", false},
{``, "", "", "", false},
{`::1`, "", "::1", "", true},
{`localhost::`, "", "localhost::", "", true},
{`#$%@`, "", "#$%@", "", true},
} {
host, port, err := standardAddress(test.input)
actual, err := standardAddress(test.input)
if err != nil && !test.shouldErr {
t.Errorf("Test %d: Expected no error, but had error: %v", i, err)
t.Errorf("Test %d (%s): Expected no error, but had error: %v", i, test.input, err)
}
if err == nil && test.shouldErr {
t.Errorf("Test %d: Expected error, but had none", i)
t.Errorf("Test %d (%s): Expected error, but had none", i, test.input)
}
if host != test.host {
t.Errorf("Test %d: Expected host '%s', got '%s'", i, test.host, host)
if actual.Scheme != test.scheme {
t.Errorf("Test %d (%s): Expected scheme '%s', got '%s'", i, test.input, test.scheme, actual.Scheme)
}
if port != test.port {
t.Errorf("Test %d: Expected port '%s', got '%s'", i, test.port, port)
if actual.Host != test.host {
t.Errorf("Test %d (%s): Expected host '%s', got '%s'", i, test.input, test.host, actual.Host)
}
if actual.Port != test.port {
t.Errorf("Test %d (%s): Expected port '%s', got '%s'", i, test.input, test.port, actual.Port)
}
}
}
@ -60,7 +64,7 @@ func TestStandardAddress(t *testing.T) {
func TestParseOneAndImport(t *testing.T) {
setupParseTests()
testParseOne := func(input string) (serverBlock, error) {
testParseOne := func(input string) (ServerBlock, error) {
p := testParser(input)
p.Next() // parseOne doesn't call Next() to start, so we must
err := p.parseOne()
@ -74,19 +78,19 @@ func TestParseOneAndImport(t *testing.T) {
tokens map[string]int // map of directive name to number of tokens expected
}{
{`localhost`, false, []address{
{"localhost", ""},
{"localhost", "", "localhost", ""},
}, map[string]int{}},
{`localhost
dir1`, false, []address{
{"localhost", ""},
{"localhost", "", "localhost", ""},
}, map[string]int{
"dir1": 1,
}},
{`localhost:1234
dir1 foo bar`, false, []address{
{"localhost", "1234"},
{"localhost:1234", "", "localhost", "1234"},
}, map[string]int{
"dir1": 3,
}},
@ -94,7 +98,7 @@ func TestParseOneAndImport(t *testing.T) {
{`localhost {
dir1
}`, false, []address{
{"localhost", ""},
{"localhost", "", "localhost", ""},
}, map[string]int{
"dir1": 1,
}},
@ -103,7 +107,7 @@ func TestParseOneAndImport(t *testing.T) {
dir1 foo bar
dir2
}`, false, []address{
{"localhost", "1234"},
{"localhost:1234", "", "localhost", "1234"},
}, map[string]int{
"dir1": 3,
"dir2": 1,
@ -111,8 +115,8 @@ func TestParseOneAndImport(t *testing.T) {
{`http://localhost https://localhost
dir1 foo bar`, false, []address{
{"localhost", "http"},
{"localhost", "https"},
{"http://localhost", "http", "localhost", "80"},
{"https://localhost", "https", "localhost", "443"},
}, map[string]int{
"dir1": 3,
}},
@ -120,8 +124,8 @@ func TestParseOneAndImport(t *testing.T) {
{`http://localhost https://localhost {
dir1 foo bar
}`, false, []address{
{"localhost", "http"},
{"localhost", "https"},
{"http://localhost", "http", "localhost", "80"},
{"https://localhost", "https", "localhost", "443"},
}, map[string]int{
"dir1": 3,
}},
@ -129,22 +133,22 @@ func TestParseOneAndImport(t *testing.T) {
{`http://localhost, https://localhost {
dir1 foo bar
}`, false, []address{
{"localhost", "http"},
{"localhost", "https"},
{"http://localhost", "http", "localhost", "80"},
{"https://localhost", "https", "localhost", "443"},
}, map[string]int{
"dir1": 3,
}},
{`http://localhost, {
}`, true, []address{
{"localhost", "http"},
{"http://localhost", "http", "localhost", "80"},
}, map[string]int{}},
{`host1:80, http://host2.com
dir1 foo bar
dir2 baz`, false, []address{
{"host1", "80"},
{"host2.com", "http"},
{"host1:80", "", "host1", "80"},
{"http://host2.com", "http", "host2.com", "80"},
}, map[string]int{
"dir1": 3,
"dir2": 2,
@ -153,9 +157,9 @@ func TestParseOneAndImport(t *testing.T) {
{`http://host1.com,
http://host2.com,
https://host3.com`, false, []address{
{"host1.com", "http"},
{"host2.com", "http"},
{"host3.com", "https"},
{"http://host1.com", "http", "host1.com", "80"},
{"http://host2.com", "http", "host2.com", "80"},
{"https://host3.com", "https", "host3.com", "443"},
}, map[string]int{}},
{`http://host1.com:1234, https://host2.com
@ -163,8 +167,8 @@ func TestParseOneAndImport(t *testing.T) {
bar baz
}
dir2`, false, []address{
{"host1.com", "1234"},
{"host2.com", "https"},
{"http://host1.com:1234", "http", "host1.com", "1234"},
{"https://host2.com", "https", "host2.com", "443"},
}, map[string]int{
"dir1": 6,
"dir2": 1,
@ -177,7 +181,7 @@ func TestParseOneAndImport(t *testing.T) {
dir2 {
foo bar
}`, false, []address{
{"127.0.0.1", ""},
{"127.0.0.1", "", "127.0.0.1", ""},
}, map[string]int{
"dir1": 5,
"dir2": 5,
@ -185,13 +189,13 @@ func TestParseOneAndImport(t *testing.T) {
{`127.0.0.1
unknown_directive`, true, []address{
{"127.0.0.1", ""},
{"127.0.0.1", "", "127.0.0.1", ""},
}, map[string]int{}},
{`localhost
dir1 {
foo`, true, []address{
{"localhost", ""},
{"localhost", "", "localhost", ""},
}, map[string]int{
"dir1": 3,
}},
@ -199,7 +203,7 @@ func TestParseOneAndImport(t *testing.T) {
{`localhost
dir1 {
}`, false, []address{
{"localhost", ""},
{"localhost", "", "localhost", ""},
}, map[string]int{
"dir1": 3,
}},
@ -207,7 +211,7 @@ func TestParseOneAndImport(t *testing.T) {
{`localhost
dir1 {
} }`, true, []address{
{"localhost", ""},
{"localhost", "", "localhost", ""},
}, map[string]int{
"dir1": 3,
}},
@ -219,7 +223,7 @@ func TestParseOneAndImport(t *testing.T) {
}
}
dir2 foo bar`, false, []address{
{"localhost", ""},
{"localhost", "", "localhost", ""},
}, map[string]int{
"dir1": 7,
"dir2": 3,
@ -230,7 +234,7 @@ func TestParseOneAndImport(t *testing.T) {
{`localhost
dir1 arg1
import import_test1.txt`, false, []address{
{"localhost", ""},
{"localhost", "", "localhost", ""},
}, map[string]int{
"dir1": 2,
"dir2": 3,
@ -238,7 +242,7 @@ func TestParseOneAndImport(t *testing.T) {
}},
{`import import_test2.txt`, false, []address{
{"host1", ""},
{"host1", "", "host1", ""},
}, map[string]int{
"dir1": 1,
"dir2": 2,
@ -301,23 +305,23 @@ func TestParseAll(t *testing.T) {
addresses [][]address // addresses per server block, in order
}{
{`localhost`, false, [][]address{
{{"localhost", ""}},
{{"localhost", "", "localhost", ""}},
}},
{`localhost:1234`, false, [][]address{
[]address{{"localhost", "1234"}},
[]address{{"localhost:1234", "", "localhost", "1234"}},
}},
{`localhost:1234 {
}
localhost:2015 {
}`, false, [][]address{
[]address{{"localhost", "1234"}},
[]address{{"localhost", "2015"}},
[]address{{"localhost:1234", "", "localhost", "1234"}},
[]address{{"localhost:2015", "", "localhost", "2015"}},
}},
{`localhost:1234, http://host2`, false, [][]address{
[]address{{"localhost", "1234"}, {"host2", "http"}},
[]address{{"localhost:1234", "", "localhost", "1234"}, {"http://host2", "http", "host2", "80"}},
}},
{`localhost:1234, http://host2,`, true, [][]address{}},
@ -326,8 +330,8 @@ func TestParseAll(t *testing.T) {
}
https://host3.com, https://host4.com {
}`, false, [][]address{
[]address{{"host1.com", "http"}, {"host2.com", "http"}},
[]address{{"host3.com", "https"}, {"host4.com", "https"}},
[]address{{"http://host1.com", "http", "host1.com", "80"}, {"http://host2.com", "http", "host2.com", "80"}},
[]address{{"https://host3.com", "https", "host3.com", "443"}, {"https://host4.com", "https", "host4.com", "443"}},
}},
} {
p := testParser(test.input)

View file

@ -17,6 +17,9 @@ type Config struct {
// The port to listen on
Port string
// The protocol (http/https) to serve with this config; only set if user explicitly specifies it
Scheme string
// The directory from which to serve files
Root string
@ -62,10 +65,11 @@ func (c Config) Address() string {
// TLSConfig describes how TLS should be configured and used.
type TLSConfig struct {
Enabled bool
Certificate string
Key string
LetsEncryptEmail string
Enabled bool
Certificate string
Key string
LetsEncryptEmail string
//DisableHTTPRedir bool // TODO: not a good idea - should we really allow it?
OCSPStaple []byte
Ciphers []uint16
ProtocolMinVersion uint16

View file

@ -18,8 +18,8 @@ func TestConfigAddress(t *testing.T) {
t.Errorf("Expected '%s' but got '%s'", expected, actual)
}
cfg = Config{Host: "::1", Port: "https"}
if actual, expected := cfg.Address(), "[::1]:https"; expected != actual {
cfg = Config{Host: "::1", Port: "443"}
if actual, expected := cfg.Address(), "[::1]:443"; expected != actual {
t.Errorf("Expected '%s' but got '%s'", expected, actual)
}
}