@marcel91200 / caddy Mirror · read-only / commits / aad9f90c
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

httpcaddyfile: Fix address parsing; don't infer port at parse-time

Before, listener ports could be wrong because ParseAddress doesn't know about the user-configured HTTP/HTTPS ports, instead hard-coding port 80 or 443, which could be wrong if the user changed them to something else. Now we defer port and scheme validation/inference to a later part of building the output JSON.

Matthew Holt committed Jan 19, 2020 at 11:51 UTC aad9f90cad23d709075073fd59214a51249de386
3 files changed +39 -31
caddyconfig/httpcaddyfile/addresses.go
+28 -20
@@ -72,7 +72,8 @@ import (
72 // repetition may be undesirable, so call consolidateAddrMappings() to map
73 // multiple addresses to the same lists of server blocks (a many:many mapping).
74 // (Doing this is essentially a map-reduce technique.)
75 -func (st *ServerType) mapAddressToServerBlocks(originalServerBlocks []serverBlock) (map[string][]serverBlock, error) {
75 +func (st *ServerType) mapAddressToServerBlocks(originalServerBlocks []serverBlock,
76 + options map[string]interface{}) (map[string][]serverBlock, error) {
77 sbmap := make(map[string][]serverBlock)
78
79 for i, sblock := range originalServerBlocks {
@@ -87,7 +88,7 @@ func (st *ServerType) mapAddressToServerBlocks(originalServerBlocks []serverBloc
88 // arguments to the 'bind' directive (although they will all have
89 // the same port, since the port is defined by the key or is implicit
90 // through automatic HTTPS)
90 - addrs, err := st.listenerAddrsForServerBlockKey(sblock, key)
91 + addrs, err := st.listenerAddrsForServerBlockKey(sblock, key, options)
92 if err != nil {
93 return nil, fmt.Errorf("server block %d, key %d (%s): determining listener address: %v", i, j, key, err)
94 }
@@ -153,20 +154,43 @@ func (st *ServerType) consolidateAddrMappings(addrToServerBlocks map[string][]se
154 return sbaddrs
155 }
156
156 -func (st *ServerType) listenerAddrsForServerBlockKey(sblock serverBlock, key string) ([]string, error) {
157 +func (st *ServerType) listenerAddrsForServerBlockKey(sblock serverBlock, key string,
158 + options map[string]interface{}) ([]string, error) {
159 addr, err := ParseAddress(key)
160 if err != nil {
161 return nil, fmt.Errorf("parsing key: %v", err)
162 }
163 addr = addr.Normalize()
164
165 + // figure out the HTTP and HTTPS ports; either
166 + // use defaults, or override with user config
167 + httpPort, httpsPort := strconv.Itoa(certmagic.HTTPPort), strconv.Itoa(certmagic.HTTPSPort)
168 + if hport, ok := options["http_port"]; ok {
169 + httpPort = strconv.Itoa(hport.(int))
170 + }
171 + if hsport, ok := options["https_port"]; ok {
172 + httpsPort = strconv.Itoa(hsport.(int))
173 + }
174 +
175 lnPort := DefaultPort
176 if addr.Port != "" {
177 // port explicitly defined
178 lnPort = addr.Port
179 + } else if addr.Scheme != "" {
180 + // port inferred from scheme
181 + if addr.Scheme == "http" {
182 + lnPort = httpPort
183 + } else if addr.Scheme == "https" {
184 + lnPort = httpsPort
185 + }
186 } else if certmagic.HostQualifies(addr.Host) {
187 // automatic HTTPS
169 - lnPort = strconv.Itoa(certmagic.HTTPSPort)
188 + lnPort = httpsPort
189 + }
190 +
191 + // error if scheme and port combination violate convention
192 + if (addr.Scheme == "http" && lnPort == httpsPort) || (addr.Scheme == "https" && lnPort == httpPort) {
193 + return nil, fmt.Errorf("[%s] scheme and port violate convention", key)
194 }
195
196 // the bind directive specifies hosts, but is optional
@@ -245,17 +269,6 @@ func ParseAddress(str string) (Address, error) {
269 a.Path = "/" + hostSplit[1]
270 }
271
248 - httpPort, httpsPort := strconv.Itoa(certmagic.HTTPPort), strconv.Itoa(certmagic.HTTPSPort)
249 -
250 - // see if we can set port based off scheme
251 - if a.Port == "" {
252 - if a.Scheme == "http" {
253 - a.Port = httpPort
254 - } else if a.Scheme == "https" {
255 - a.Port = httpsPort
256 - }
257 - }
258 -
272 // make sure port is valid
273 if a.Port != "" {
274 if portNum, err := strconv.Atoi(a.Port); err != nil {
@@ -265,11 +278,6 @@ func ParseAddress(str string) (Address, error) {
278 }
279 }
280
268 - // error if scheme and port combination violate convention
269 - if (a.Scheme == "http" && a.Port == httpsPort) || (a.Scheme == "https" && a.Port == httpPort) {
270 - return Address{}, fmt.Errorf("[%s] scheme and port violate convention", str)
271 - }
272 -
281 return a, nil
282 }
283
caddyconfig/httpcaddyfile/addresses_test.go
+10 -10
@@ -28,17 +28,17 @@ func TestParseAddress(t *testing.T) {
28 {`http://localhost:https`, "", "", "", "", true}, // conflict
29 {`http://localhost:http`, "", "", "", "", true}, // repeated scheme
30 {`host:https/path`, "", "", "", "", true},
31 - {`http://localhost:443`, "", "", "", "", true}, // not conventional
32 - {`https://localhost:80`, "", "", "", "", true}, // not conventional
33 - {`http://localhost`, "http", "localhost", "80", "", false},
34 - {`https://localhost`, "https", "localhost", "443", "", false},
35 - {`http://{env.APP_DOMAIN}`, "http", "{env.APP_DOMAIN}", "80", "", false},
31 + {`http://localhost:443`, "http", "localhost", "443", "", false}, // NOTE: not conventional
32 + {`https://localhost:80`, "https", "localhost", "80", "", false}, // NOTE: not conventional
33 + {`http://localhost`, "http", "localhost", "", "", false},
34 + {`https://localhost`, "https", "localhost", "", "", false},
35 + {`http://{env.APP_DOMAIN}`, "http", "{env.APP_DOMAIN}", "", "", false},
36 {`{env.APP_DOMAIN}:80`, "", "{env.APP_DOMAIN}", "80", "", false},
37 {`{env.APP_DOMAIN}/path`, "", "{env.APP_DOMAIN}", "", "/path", false},
38 {`example.com/{env.APP_PATH}`, "", "example.com", "", "/{env.APP_PATH}", false},
39 - {`http://127.0.0.1`, "http", "127.0.0.1", "80", "", false},
40 - {`https://127.0.0.1`, "https", "127.0.0.1", "443", "", false},
41 - {`http://[::1]`, "http", "::1", "80", "", false},
39 + {`http://127.0.0.1`, "http", "127.0.0.1", "", "", false},
40 + {`https://127.0.0.1`, "https", "127.0.0.1", "", "", false},
41 + {`http://[::1]`, "http", "::1", "", "", false},
42 {`http://localhost:1234`, "http", "localhost", "1234", "", false},
43 {`https://127.0.0.1:1234`, "https", "127.0.0.1", "1234", "", false},
44 {`http://[::1]:1234`, "http", "::1", "1234", "", false},
@@ -47,10 +47,10 @@ func TestParseAddress(t *testing.T) {
47 {`localhost::`, "", "localhost::", "", "", false},
48 {`#$%@`, "", "#$%@", "", "", false}, // don't want to presume what the hostname could be
49 {`host/path`, "", "host", "", "/path", false},
50 - {`http://host/`, "http", "host", "80", "/", false},
50 + {`http://host/`, "http", "host", "", "/", false},
51 {`//asdf`, "", "", "", "//asdf", false},
52 {`:1234/asdf`, "", "", "1234", "/asdf", false},
53 - {`http://host/path`, "http", "host", "80", "/path", false},
53 + {`http://host/path`, "http", "host", "", "/path", false},
54 {`https://host:443/path/foo`, "https", "host", "443", "/path/foo", false},
55 {`host:80/path`, "", "host", "80", "/path", false},
56 {`/path`, "", "", "", "/path", false},
caddyconfig/httpcaddyfile/httptype.go
+1 -1
@@ -159,7 +159,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
159 }
160
161 // map
162 - sbmap, err := st.mapAddressToServerBlocks(serverBlocks)
162 + sbmap, err := st.mapAddressToServerBlocks(serverBlocks, options)
163 if err != nil {
164 return nil, warnings, err
165 }