From 829a0f34d0d029f5c24050b5df1b714886df9c73 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Sun, 3 Jan 2016 16:46:26 -0700 Subject: [PATCH] Preserve and clean up original host input in Caddyfile-JSON conversions --- caddy/caddyfile/json.go | 25 ++++++++++++++---------- caddy/caddyfile/json_test.go | 37 +++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/caddy/caddyfile/json.go b/caddy/caddyfile/json.go index fb04b5565..e1213c27d 100644 --- a/caddy/caddyfile/json.go +++ b/caddy/caddyfile/json.go @@ -28,7 +28,7 @@ func ToJSON(caddyfile []byte) ([]byte, error) { // Fill up host list for _, host := range sb.HostList() { - block.Hosts = append(block.Hosts, strings.TrimSuffix(host, ":")) + block.Hosts = append(block.Hosts, standardizeScheme(host)) } // Extract directives deterministically by sorting them @@ -62,7 +62,6 @@ func ToJSON(caddyfile []byte) ([]byte, error) { // but only one line at a time, to be used at the top-level of // a server block only (where the first token on each line is a // directive) - not to be used at any other nesting level. -// goes to end of line func constructLine(d *parse.Dispenser) []interface{} { var args []interface{} @@ -80,8 +79,8 @@ func constructLine(d *parse.Dispenser) []interface{} { } // constructBlock recursively processes tokens into a -// JSON-encodable structure. -// goes to end of block +// JSON-encodable structure. To be used in a directive's +// block. Goes to end of block. func constructBlock(d *parse.Dispenser) [][]interface{} { block := [][]interface{}{} @@ -110,15 +109,10 @@ func FromJSON(jsonBytes []byte) ([]byte, error) { result += "\n\n" } for i, host := range sb.Hosts { - if hostname, port, err := net.SplitHostPort(host); err == nil { - if port == "http" || port == "https" { - host = port + "://" + hostname - } - } if i > 0 { result += ", " } - result += strings.TrimSuffix(host, ":") + result += standardizeScheme(host) } result += jsonToText(sb.Body, 1) } @@ -170,6 +164,17 @@ func jsonToText(scope interface{}, depth int) string { return result } +// standardizeScheme turns an address like host:https into https://host, +// or "host:" into "host". +func standardizeScheme(addr string) string { + if hostname, port, err := net.SplitHostPort(addr); err == nil { + if port == "http" || port == "https" { + addr = port + "://" + hostname + } + } + return strings.TrimSuffix(addr, ":") +} + // Caddyfile encapsulates a slice of ServerBlocks. type Caddyfile []ServerBlock diff --git a/caddy/caddyfile/json_test.go b/caddy/caddyfile/json_test.go index 024792638..2e44ae2a2 100644 --- a/caddy/caddyfile/json_test.go +++ b/caddy/caddyfile/json_test.go @@ -63,7 +63,7 @@ baz" { // 8 caddyfile: `http://host, https://host { }`, - json: `[{"hosts":["host:http","host:https"],"body":[]}]`, // hosts in JSON are always host:port format (if port is specified), for consistency + json: `[{"hosts":["http://host","https://host"],"body":[]}]`, // hosts in JSON are always host:port format (if port is specified), for consistency }, { // 9 caddyfile: `host { @@ -124,3 +124,38 @@ func TestFromJSON(t *testing.T) { } } } + +func TestStandardizeAddress(t *testing.T) { + // host:https should be converted to https://host + output, err := ToJSON([]byte(`host:https`)) + if err != nil { + t.Fatal(err) + } + if expected, actual := `[{"hosts":["https://host"],"body":[]}]`, string(output); expected != actual { + t.Errorf("Expected:\n'%s'\nActual:\n'%s'", expected, actual) + } + + output, err = FromJSON([]byte(`[{"hosts":["https://host"],"body":[]}]`)) + if err != nil { + t.Fatal(err) + } + if expected, actual := "https://host {\n}", string(output); expected != actual { + t.Errorf("Expected:\n'%s'\nActual:\n'%s'", expected, actual) + } + + // host: should be converted to just host + output, err = ToJSON([]byte(`host:`)) + if err != nil { + t.Fatal(err) + } + if expected, actual := `[{"hosts":["host"],"body":[]}]`, string(output); expected != actual { + t.Errorf("Expected:\n'%s'\nActual:\n'%s'", expected, actual) + } + output, err = FromJSON([]byte(`[{"hosts":["host:"],"body":[]}]`)) + if err != nil { + t.Fatal(err) + } + if expected, actual := "host {\n}", string(output); expected != actual { + t.Errorf("Expected:\n'%s'\nActual:\n'%s'", expected, actual) + } +}