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
caddyhttp: Fix auto redirects for catch-all HTTPS sites
Prior logic was not setting up redirects for the case when domain names are not known, but the server still clearly has TLS enabled.
Matthew Holt committed
Apr 24, 2020 at 17:36 UTC
ebf07f853bfbc54821fc35c0cfba97111ae70866
1 file changed
+29
-16
modules/caddyhttp/autohttps.go
+29
-16
@@ -129,6 +129,7 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er
129
}
130
131
// find all qualifying domain names (deduplicated) in this server
132
+ // (this is where we need the provisioned, decoded request matchers)
133
serverDomainSet := make(map[string]struct{})
134
for routeIdx, route := range srv.Routes {
135
for matcherSetIdx, matcherSet := range route.MatcherSets {
@@ -150,9 +151,14 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er
151
}
152
}
153
153
- // nothing more to do here if there are no
154
- // domains that qualify for automatic HTTPS
155
- if len(serverDomainSet) == 0 {
154
+ // nothing more to do here if there are no domains that qualify for
155
+ // automatic HTTPS or there are no explicit TLS connection policies;
156
+ // if there is at least one domain but no TLS conn policy, we'll add
157
+ // one below; if there is a TLS conn policy (meaning TLS is enabled)
158
+ // and no domains, it could be a catch-all with on-demand TLS, and
159
+ // in that case we would still need HTTP->HTTPS redirects, which we
160
+ // do below
161
+ if len(serverDomainSet) == 0 || len(srv.TLSConnPolicies) == 0 {
162
continue
163
}
164
@@ -207,6 +213,17 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er
213
return fmt.Errorf("%s: invalid listener address: %v", srvName, addr)
214
}
215
216
+ // this address might not have a hostname, i.e. might be a
217
+ // catch-all address for a particular port; we need to keep
218
+ // track if it is, so we can set up redirects for it anyway
219
+ // (e.g. the user might have enabled on-demand TLS); we use
220
+ // an empty string to indicate a catch-all, which we have to
221
+ // treat special later
222
+ if len(serverDomainSet) == 0 {
223
+ redirDomains[""] = addr
224
+ continue
225
+ }
226
+
227
// ...and associate it with each domain in this server
228
for d := range serverDomainSet {
229
// if this domain is used on more than one HTTPS-enabled
@@ -258,11 +275,6 @@ uniqueDomainsLoop:
275
return err
276
}
277
261
- // we're done if there are no HTTP->HTTPS redirects to add
262
- if len(redirDomains) == 0 {
263
- return nil
264
- }
265
-
278
// we need to reduce the mapping, i.e. group domains by address
279
// since new routes are appended to servers by their address
280
domainsByAddr := make(map[string][]string)
@@ -275,17 +287,18 @@ uniqueDomainsLoop:
287
// and the routes for those servers which actually
288
// respond with the redirects
289
redirServerAddrs := make(map[string]struct{})
278
- var redirRoutes RouteList
279
-
290
redirServers := make(map[string][]Route)
291
+ var redirRoutes RouteList
292
293
for addrStr, domains := range domainsByAddr {
283
- // build the matcher set for this redirect route
284
- // (note that we happen to bypass Provision and
285
- // Validate steps for these matcher modules)
286
- matcherSet := MatcherSet{
287
- MatchProtocol("http"),
288
- MatchHost(domains),
294
+ // build the matcher set for this redirect route; (note that we happen
295
+ // to bypass Provision and Validate steps for these matcher modules)
296
+ matcherSet := MatcherSet{MatchProtocol("http")}
297
+ // match on known domain names, unless it's our special case of a
298
+ // catch-all which is an empty string (common among catch-all sites
299
+ // that enable on-demand TLS for yet-unknown domain names)
300
+ if !(len(domains) == 1 && domains[0] == "") {
301
+ matcherSet = append(matcherSet, MatchHost(domains))
302
}
303
304
// build the address to which to redirect