Skip to content

Commit 3e1fd2a

Browse files
authored
httpcaddyfile: Wrap site block in subroute if host matcher used (#5130)
* httpcaddyfile: Wrap site block in subroute if host matcher used (fix #5124) * Correct boolean logic (oops)
1 parent 33f60da commit 3e1fd2a

File tree

4 files changed

+116
-81
lines changed

4 files changed

+116
-81
lines changed

caddyconfig/httpcaddyfile/httptype.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -907,11 +907,32 @@ func appendSubrouteToRouteList(routeList caddyhttp.RouteList,
907907
return routeList
908908
}
909909

910+
// No need to wrap the handlers in a subroute if this is the only server block
911+
// and there is no matcher for it (doing so would produce unnecessarily nested
912+
// JSON), *unless* there is a host matcher within this site block; if so, then
913+
// we still need to wrap in a subroute because otherwise the host matcher from
914+
// the inside of the site block would be a top-level host matcher, which is
915+
// subject to auto-HTTPS (cert management), and using a host matcher within
916+
// a site block is a valid, common pattern for excluding domains from cert
917+
// management, leading to unexpected behavior; see issue #5124.
918+
wrapInSubroute := true
910919
if len(matcherSetsEnc) == 0 && len(p.serverBlocks) == 1 {
911-
// no need to wrap the handlers in a subroute if this is
912-
// the only server block and there is no matcher for it
913-
routeList = append(routeList, subroute.Routes...)
914-
} else {
920+
var hasHostMatcher bool
921+
outer:
922+
for _, route := range subroute.Routes {
923+
for _, ms := range route.MatcherSetsRaw {
924+
for matcherName := range ms {
925+
if matcherName == "host" {
926+
hasHostMatcher = true
927+
break outer
928+
}
929+
}
930+
}
931+
}
932+
wrapInSubroute = hasHostMatcher
933+
}
934+
935+
if wrapInSubroute {
915936
route := caddyhttp.Route{
916937
// the semantics of a site block in the Caddyfile dictate
917938
// that only the first matching one is evaluated, since
@@ -929,7 +950,10 @@ func appendSubrouteToRouteList(routeList caddyhttp.RouteList,
929950
if len(route.MatcherSetsRaw) > 0 || len(route.HandlersRaw) > 0 {
930951
routeList = append(routeList, route)
931952
}
953+
} else {
954+
routeList = append(routeList, subroute.Routes...)
932955
}
956+
933957
return routeList
934958
}
935959

caddytest/integration/caddyfile_adapt/global_server_options_multi.txt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
timeouts {
44
idle 90s
55
}
6-
protocol {
7-
strict_sni_host insecure_off
8-
}
6+
strict_sni_host insecure_off
97
}
108
servers :80 {
119
timeouts {
@@ -16,9 +14,7 @@
1614
timeouts {
1715
idle 30s
1816
}
19-
protocol {
20-
strict_sni_host
21-
}
17+
strict_sni_host
2218
}
2319
}
2420

caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.txt

Lines changed: 85 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
:8884
22

3-
@api host example.com
4-
php_fastcgi @api localhost:9000
3+
# the use of a host matcher here should cause this
4+
# site block to be wrapped in a subroute, even though
5+
# the site block does not have a hostname; this is
6+
# to prevent auto-HTTPS from picking up on this host
7+
# matcher because it is not a key on the site block
8+
@test host example.com
9+
php_fastcgi @test localhost:9000
510
----------
611
{
712
"apps": {
@@ -13,96 +18,106 @@ php_fastcgi @api localhost:9000
1318
],
1419
"routes": [
1520
{
16-
"match": [
17-
{
18-
"host": [
19-
"example.com"
20-
]
21-
}
22-
],
2321
"handle": [
2422
{
2523
"handler": "subroute",
2624
"routes": [
2725
{
2826
"handle": [
2927
{
30-
"handler": "static_response",
31-
"headers": {
32-
"Location": [
33-
"{http.request.orig_uri.path}/"
34-
]
35-
},
36-
"status_code": 308
37-
}
38-
],
39-
"match": [
40-
{
41-
"file": {
42-
"try_files": [
43-
"{http.request.uri.path}/index.php"
44-
]
45-
},
46-
"not": [
28+
"handler": "subroute",
29+
"routes": [
4730
{
48-
"path": [
49-
"*/"
31+
"handle": [
32+
{
33+
"handler": "static_response",
34+
"headers": {
35+
"Location": [
36+
"{http.request.orig_uri.path}/"
37+
]
38+
},
39+
"status_code": 308
40+
}
41+
],
42+
"match": [
43+
{
44+
"file": {
45+
"try_files": [
46+
"{http.request.uri.path}/index.php"
47+
]
48+
},
49+
"not": [
50+
{
51+
"path": [
52+
"*/"
53+
]
54+
}
55+
]
56+
}
5057
]
51-
}
52-
]
53-
}
54-
]
55-
},
56-
{
57-
"handle": [
58-
{
59-
"handler": "rewrite",
60-
"uri": "{http.matchers.file.relative}"
61-
}
62-
],
63-
"match": [
64-
{
65-
"file": {
66-
"split_path": [
67-
".php"
68-
],
69-
"try_files": [
70-
"{http.request.uri.path}",
71-
"{http.request.uri.path}/index.php",
72-
"index.php"
73-
]
74-
}
75-
}
76-
]
77-
},
78-
{
79-
"handle": [
80-
{
81-
"handler": "reverse_proxy",
82-
"transport": {
83-
"protocol": "fastcgi",
84-
"split_path": [
85-
".php"
86-
]
87-
},
88-
"upstreams": [
58+
},
8959
{
90-
"dial": "localhost:9000"
60+
"handle": [
61+
{
62+
"handler": "rewrite",
63+
"uri": "{http.matchers.file.relative}"
64+
}
65+
],
66+
"match": [
67+
{
68+
"file": {
69+
"split_path": [
70+
".php"
71+
],
72+
"try_files": [
73+
"{http.request.uri.path}",
74+
"{http.request.uri.path}/index.php",
75+
"index.php"
76+
]
77+
}
78+
}
79+
]
80+
},
81+
{
82+
"handle": [
83+
{
84+
"handler": "reverse_proxy",
85+
"transport": {
86+
"protocol": "fastcgi",
87+
"split_path": [
88+
".php"
89+
]
90+
},
91+
"upstreams": [
92+
{
93+
"dial": "localhost:9000"
94+
}
95+
]
96+
}
97+
],
98+
"match": [
99+
{
100+
"path": [
101+
"*.php"
102+
]
103+
}
104+
]
91105
}
92106
]
93107
}
94108
],
95109
"match": [
96110
{
97-
"path": [
98-
"*.php"
111+
"host": [
112+
"example.com"
99113
]
100114
}
101115
]
102116
}
103117
]
104118
}
105-
]
119+
],
120+
"terminal": true
106121
}
107122
]
108123
}

modules/caddyhttp/app.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func init() {
6666
// `{http.request.orig_uri}` | The request's original URI
6767
// `{http.request.port}` | The port part of the request's Host header
6868
// `{http.request.proto}` | The protocol of the request
69-
// `{http.request.remote.host}` | The host part of the remote client's address
69+
// `{http.request.remote.host}` | The host (IP) part of the remote client's address
7070
// `{http.request.remote.port}` | The port part of the remote client's address
7171
// `{http.request.remote}` | The address of the remote client
7272
// `{http.request.scheme}` | The request scheme

0 commit comments

Comments
 (0)