@marcel91200 / caddy Mirror · read-only / commits / 7243454a
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

fastcgi: `php_fastcgi` subdirectives to override shortcut behaviour (#3255)

* fastcgi: Add new php_fastcgi subdirectives to override the shortcut * fastcgi: Support "index off" to disable redir and try_files * fastcgi: Remove whitespace to satisfy linter * fastcgi: Run gofmt * fastcgi: Make a new dispenser instead of using rewind * fastcgi: Some fmt * fastcgi: Add a couple adapt tests * fastcgi: Clean up for loops * fastcgi: Move adapt tests to separate files

Francis Lavoie committed May 18, 2020 at 14:15 UTC 7243454a96d6dcbe504af7287de1e68ab4b80c83
3 files changed +306 -39
caddytest/integration/caddyfile_adapt/php_fastcgi_index_off.txt new
+66
@@ -0,0 +1,66 @@
1 +:8884
2 +
3 +php_fastcgi localhost:9000 {
4 + # some php_fastcgi-specific subdirectives
5 + split .php .php5
6 + env VAR1 value1
7 + env VAR2 value2
8 + root /var/www
9 + index off
10 +
11 + # passed through to reverse_proxy (directive order doesn't matter!)
12 + lb_policy random
13 +}
14 +----------
15 +{
16 + "apps": {
17 + "http": {
18 + "servers": {
19 + "srv0": {
20 + "listen": [
21 + ":8884"
22 + ],
23 + "routes": [
24 + {
25 + "match": [
26 + {
27 + "path": [
28 + "*.php",
29 + "*.php5"
30 + ]
31 + }
32 + ],
33 + "handle": [
34 + {
35 + "handler": "reverse_proxy",
36 + "load_balancing": {
37 + "selection_policy": {
38 + "policy": "random"
39 + }
40 + },
41 + "transport": {
42 + "env": {
43 + "VAR1": "value1",
44 + "VAR2": "value2"
45 + },
46 + "protocol": "fastcgi",
47 + "root": "/var/www",
48 + "split_path": [
49 + ".php",
50 + ".php5"
51 + ]
52 + },
53 + "upstreams": [
54 + {
55 + "dial": "localhost:9000"
56 + }
57 + ]
58 + }
59 + ]
60 + }
61 + ]
62 + }
63 + }
64 + }
65 + }
66 +}
\ No newline at end of file
caddytest/integration/caddyfile_adapt/php_fastcgi_subdirectives.txt new
+118
@@ -0,0 +1,118 @@
1 +:8884
2 +
3 +php_fastcgi localhost:9000 {
4 + # some php_fastcgi-specific subdirectives
5 + split .php .php5
6 + env VAR1 value1
7 + env VAR2 value2
8 + root /var/www
9 + index index.php5
10 +
11 + # passed through to reverse_proxy (directive order doesn't matter!)
12 + lb_policy random
13 +}
14 +----------
15 +{
16 + "apps": {
17 + "http": {
18 + "servers": {
19 + "srv0": {
20 + "listen": [
21 + ":8884"
22 + ],
23 + "routes": [
24 + {
25 + "match": [
26 + {
27 + "file": {
28 + "try_files": [
29 + "{http.request.uri.path}/index.php5"
30 + ]
31 + },
32 + "not": [
33 + {
34 + "path": [
35 + "*/"
36 + ]
37 + }
38 + ]
39 + }
40 + ],
41 + "handle": [
42 + {
43 + "handler": "static_response",
44 + "headers": {
45 + "Location": [
46 + "{http.request.uri.path}/"
47 + ]
48 + },
49 + "status_code": 308
50 + }
51 + ]
52 + },
53 + {
54 + "match": [
55 + {
56 + "file": {
57 + "try_files": [
58 + "{http.request.uri.path}",
59 + "{http.request.uri.path}/index.php5",
60 + "index.php5"
61 + ],
62 + "split_path": [
63 + ".php",
64 + ".php5"
65 + ]
66 + }
67 + }
68 + ],
69 + "handle": [
70 + {
71 + "handler": "rewrite",
72 + "uri": "{http.matchers.file.relative}"
73 + }
74 + ]
75 + },
76 + {
77 + "match": [
78 + {
79 + "path": [
80 + "*.php",
81 + "*.php5"
82 + ]
83 + }
84 + ],
85 + "handle": [
86 + {
87 + "handler": "reverse_proxy",
88 + "load_balancing": {
89 + "selection_policy": {
90 + "policy": "random"
91 + }
92 + },
93 + "transport": {
94 + "env": {
95 + "VAR1": "value1",
96 + "VAR2": "value2"
97 + },
98 + "protocol": "fastcgi",
99 + "root": "/var/www",
100 + "split_path": [
101 + ".php",
102 + ".php5"
103 + ]
104 + },
105 + "upstreams": [
106 + {
107 + "dial": "localhost:9000"
108 + }
109 + ]
110 + }
111 + ]
112 + }
113 + ]
114 + }
115 + }
116 + }
117 + }
118 +}
\ No newline at end of file
modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
+122 -39
@@ -123,47 +123,133 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
123 return nil, h.ArgErr()
124 }
125
126 - // route to redirect to canonical path if index PHP file
127 - redirMatcherSet := caddy.ModuleMap{
128 - "file": h.JSON(fileserver.MatchFile{
129 - TryFiles: []string{"{http.request.uri.path}/index.php"},
130 - }),
131 - "not": h.JSON(caddyhttp.MatchNot{
132 - MatcherSetsRaw: []caddy.ModuleMap{
133 - {
134 - "path": h.JSON(caddyhttp.MatchPath{"*/"}),
135 - },
136 - },
137 - }),
138 - }
139 - redirHandler := caddyhttp.StaticResponse{
140 - StatusCode: caddyhttp.WeakString(strconv.Itoa(http.StatusPermanentRedirect)),
141 - Headers: http.Header{"Location": []string{"{http.request.uri.path}/"}},
142 - }
143 - redirRoute := caddyhttp.Route{
144 - MatcherSetsRaw: []caddy.ModuleMap{redirMatcherSet},
145 - HandlersRaw: []json.RawMessage{caddyconfig.JSONModuleObject(redirHandler, "handler", "static_response", nil)},
146 - }
126 + // set up the transport for FastCGI, and specifically PHP
127 + fcgiTransport := Transport{}
128
148 - // route to rewrite to PHP index file
149 - rewriteMatcherSet := caddy.ModuleMap{
150 - "file": h.JSON(fileserver.MatchFile{
151 - TryFiles: []string{"{http.request.uri.path}", "{http.request.uri.path}/index.php", "index.php"},
152 - SplitPath: []string{".php"},
153 - }),
154 - }
155 - rewriteHandler := rewrite.Rewrite{
156 - URI: "{http.matchers.file.relative}",
129 + // set up the set of file extensions allowed to execute PHP code
130 + extensions := []string{".php"}
131 +
132 + // set the default index file for the try_files rewrites
133 + indexFile := "index.php"
134 +
135 + // make a new dispenser from the remaining tokens so that we
136 + // can reset the dispenser back to this point for the
137 + // reverse_proxy unmarshaler to read from it as well
138 + dispenser := h.NewFromNextSegment()
139 +
140 + // read the subdirectives that we allow as overrides to
141 + // the php_fastcgi shortcut
142 + // NOTE: we delete the tokens as we go so that the reverse_proxy
143 + // unmarshal doesn't see these subdirectives which it cannot handle
144 + for dispenser.Next() {
145 + for dispenser.NextBlock(0) {
146 + switch dispenser.Val() {
147 + case "root":
148 + if !dispenser.NextArg() {
149 + return nil, dispenser.ArgErr()
150 + }
151 + fcgiTransport.Root = dispenser.Val()
152 + dispenser.Delete()
153 + dispenser.Delete()
154 +
155 + case "split":
156 + extensions = dispenser.RemainingArgs()
157 + dispenser.Delete()
158 + for range extensions {
159 + dispenser.Delete()
160 + }
161 + if len(extensions) == 0 {
162 + return nil, dispenser.ArgErr()
163 + }
164 +
165 + case "env":
166 + args := dispenser.RemainingArgs()
167 + dispenser.Delete()
168 + for range args {
169 + dispenser.Delete()
170 + }
171 + if len(args) != 2 {
172 + return nil, dispenser.ArgErr()
173 + }
174 + if fcgiTransport.EnvVars == nil {
175 + fcgiTransport.EnvVars = make(map[string]string)
176 + }
177 + fcgiTransport.EnvVars[args[0]] = args[1]
178 +
179 + case "index":
180 + args := dispenser.RemainingArgs()
181 + dispenser.Delete()
182 + for range args {
183 + dispenser.Delete()
184 + }
185 + if len(args) != 1 {
186 + return nil, dispenser.ArgErr()
187 + }
188 + indexFile = args[0]
189 + }
190 + }
191 }
158 - rewriteRoute := caddyhttp.Route{
159 - MatcherSetsRaw: []caddy.ModuleMap{rewriteMatcherSet},
160 - HandlersRaw: []json.RawMessage{caddyconfig.JSONModuleObject(rewriteHandler, "handler", "rewrite", nil)},
192 +
193 + // reset the dispenser after we're done so that the reverse_proxy
194 + // unmarshaler can read it from the start
195 + dispenser.Reset()
196 +
197 + // set up a route list that we'll append to
198 + routes := caddyhttp.RouteList{}
199 +
200 + // set the list of allowed path segments on which to split
201 + fcgiTransport.SplitPath = extensions
202 +
203 + // if the index is turned off, we skip the redirect and try_files
204 + if indexFile != "off" {
205 + // route to redirect to canonical path if index PHP file
206 + redirMatcherSet := caddy.ModuleMap{
207 + "file": h.JSON(fileserver.MatchFile{
208 + TryFiles: []string{"{http.request.uri.path}/" + indexFile},
209 + }),
210 + "not": h.JSON(caddyhttp.MatchNot{
211 + MatcherSetsRaw: []caddy.ModuleMap{
212 + {
213 + "path": h.JSON(caddyhttp.MatchPath{"*/"}),
214 + },
215 + },
216 + }),
217 + }
218 + redirHandler := caddyhttp.StaticResponse{
219 + StatusCode: caddyhttp.WeakString(strconv.Itoa(http.StatusPermanentRedirect)),
220 + Headers: http.Header{"Location": []string{"{http.request.uri.path}/"}},
221 + }
222 + redirRoute := caddyhttp.Route{
223 + MatcherSetsRaw: []caddy.ModuleMap{redirMatcherSet},
224 + HandlersRaw: []json.RawMessage{caddyconfig.JSONModuleObject(redirHandler, "handler", "static_response", nil)},
225 + }
226 +
227 + // route to rewrite to PHP index file
228 + rewriteMatcherSet := caddy.ModuleMap{
229 + "file": h.JSON(fileserver.MatchFile{
230 + TryFiles: []string{"{http.request.uri.path}", "{http.request.uri.path}/" + indexFile, indexFile},
231 + SplitPath: extensions,
232 + }),
233 + }
234 + rewriteHandler := rewrite.Rewrite{
235 + URI: "{http.matchers.file.relative}",
236 + }
237 + rewriteRoute := caddyhttp.Route{
238 + MatcherSetsRaw: []caddy.ModuleMap{rewriteMatcherSet},
239 + HandlersRaw: []json.RawMessage{caddyconfig.JSONModuleObject(rewriteHandler, "handler", "rewrite", nil)},
240 + }
241 +
242 + routes = append(routes, redirRoute, rewriteRoute)
243 }
244
245 // route to actually reverse proxy requests to PHP files;
246 // match only requests that are for PHP files
247 + pathList := []string{}
248 + for _, ext := range extensions {
249 + pathList = append(pathList, "*"+ext)
250 + }
251 rpMatcherSet := caddy.ModuleMap{
166 - "path": h.JSON([]string{"*.php"}),
252 + "path": h.JSON(pathList),
253 }
254
255 // if the user specified a matcher token, use that
@@ -176,9 +262,6 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
262 return nil, err
263 }
264
179 - // set up the transport for FastCGI, and specifically PHP
180 - fcgiTransport := Transport{SplitPath: []string{".php"}}
181 -
265 // create the reverse proxy handler which uses our FastCGI transport
266 rpHandler := &reverseproxy.Handler{
267 TransportRaw: caddyconfig.JSONModuleObject(fcgiTransport, "protocol", "fastcgi", nil),
@@ -188,7 +271,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
271 // using the reverse_proxy directive syntax
272 // TODO: this can overwrite our fcgiTransport that we encoded and
273 // set on the rpHandler... even with a non-fastcgi transport!
191 - err = rpHandler.UnmarshalCaddyfile(h.Dispenser)
274 + err = rpHandler.UnmarshalCaddyfile(dispenser)
275 if err != nil {
276 return nil, err
277 }
@@ -201,7 +284,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
284 }
285
286 subroute := caddyhttp.Subroute{
204 - Routes: caddyhttp.RouteList{redirRoute, rewriteRoute, rpRoute},
287 + Routes: append(routes, rpRoute),
288 }
289
290 // the user's matcher is a prerequisite for ours, so