Skip to content
Newer
Older
100644 766 lines (601 sloc) 19.8 KB
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* Cherokee
4 *
5 * Authors:
6 * Alvaro Lopez Ortega <alvaro@alobbs.com>
7 *
9393e55 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@597 5dc97367-97…
alobbs authored
8 * Copyright (C) 2001-2007 Alvaro Lopez Ortega
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General Public
12 * License as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 */
24
25 #include "common-internal.h"
26 #include "handler_fcgi.h"
27 #include "header.h"
28 #include "connection-protected.h"
29 #include "util.h"
30 #include "thread.h"
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
31 #include "source_interpreter.h"
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
32
33 #include "fastcgi.h"
34
35 #define POST_PACKAGE_LEN 32600
36 #define ENTRIES "fcgi,handler"
37
38
39 #define set_env(cgi,key,val,len) \
40 set_env_pair (cgi, key, sizeof(key)-1, val, len)
41
42
43 static void set_env_pair (cherokee_handler_cgi_base_t *cgi_base,
44 char *key, int key_len,
45 char *val, int val_len);
46
b69d2e0 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@476 5dc97367-97…
alobbs authored
47 /* Plug-in initialization
48 */
49 PLUGIN_INFO_HANDLER_EASIEST_INIT (fcgi, http_get | http_post | http_head);
50
51
52 /* Methods implementation
53 */
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
54 static ret_t
55 process_package (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *inbuf, cherokee_buffer_t *outbuf)
56 {
57 FCGI_Header *header;
58 FCGI_EndRequestBody *ending;
59 cherokee_connection_t *conn = HANDLER_CONN(hdl);
60
61 cuint_t len;
62 char *data;
63 cint_t return_val;
64 cuint_t type;
65 cuint_t id;
66 cuint_t padding;
67
68 /* Is there enough information?
69 */
70 if (inbuf->len < sizeof(FCGI_Header))
71 return ret_ok;
72
73 /* At least there is a header
74 */
75 header = (FCGI_Header *)inbuf->buf;
76
77 if (header->version != 1) {
78 cherokee_buffer_print_debug (inbuf, -1);
79 PRINT_ERROR_S ("Parsing error: unknown version\n");
80 return ret_error;
81 }
82
83 if (header->type != FCGI_STDERR &&
84 header->type != FCGI_STDOUT &&
85 header->type != FCGI_END_REQUEST)
86 {
87 cherokee_buffer_print_debug (inbuf, -1);
88 PRINT_ERROR_S ("Parsing error: unknown type\n");
89 return ret_error;
90 }
91
92 /* Read the header
93 */
94 type = header->type;
95 padding = header->paddingLength;
96 id = (header->requestIdB0 | (header->requestIdB1 << 8));
97 len = (header->contentLengthB0 | (header->contentLengthB1 << 8));
98 data = inbuf->buf + FCGI_HEADER_LEN;
99
b13f4bf @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@446 5dc97367-97…
alobbs authored
100 /* printf ("have %d, hdr=%d exp_len=%d pad=%d\n", inbuf->len, FCGI_HEADER_LEN, len, padding); */
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
101
102 /* Is the package complete?
103 */
104 if (len + padding > inbuf->len - FCGI_HEADER_LEN) {
b13f4bf @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@446 5dc97367-97…
alobbs authored
105 /* printf ("Incomplete: %d < %d\n", len + padding, inbuf->len - FCGI_HEADER_LEN); */
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
106 return ret_ok;
107 }
108
109 /* It has received the full package content
110 */
111 switch (type) {
112 case FCGI_STDERR:
b13f4bf @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@446 5dc97367-97…
alobbs authored
113 /* printf ("READ:STDERR (%d): %s", len, data?data:""); */
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
114
115 if (CONN_VSRV(conn)->logger != NULL) {
116 cherokee_buffer_t tmp = CHEROKEE_BUF_INIT;
117
118 cherokee_buffer_add (&tmp, data, len);
119 cherokee_logger_write_string (CONN_VSRV(conn)->logger, "%s", tmp.buf);
120 PRINT_ERROR ("%s\n", tmp.buf);
121 cherokee_buffer_mrproper (&tmp);
122 }
123 break;
124
125 case FCGI_STDOUT:
b13f4bf @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@446 5dc97367-97…
alobbs authored
126 /* printf ("READ:STDOUT eof=%d: %d", CGI_BASE(hdl)->got_eof, len); */
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
127 cherokee_buffer_add (outbuf, data, len);
128 break;
129
130 case FCGI_END_REQUEST:
131 ending = (FCGI_EndRequestBody *)data;
132
133 return_val = ((ending->appStatusB0) |
134 (ending->appStatusB0 << 8) |
135 (ending->appStatusB0 << 16) |
136 (ending->appStatusB0 << 24));
137
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
138 HDL_CGI_BASE(hdl)->got_eof = true;
b13f4bf @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@446 5dc97367-97…
alobbs authored
139 /* printf ("READ:END"); */
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
140 break;
141
142 default:
143 SHOULDNT_HAPPEN;
144 }
145
146 cherokee_buffer_move_to_begin (inbuf, len + FCGI_HEADER_LEN + padding);
b13f4bf @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@446 5dc97367-97…
alobbs authored
147 /* printf ("- FCGI quedan %d\n", inbuf->len); */
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
148 return ret_eagain;
149 }
150
151
152 static ret_t
153 process_buffer (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *inbuf, cherokee_buffer_t *outbuf)
154 {
155 ret_t ret;
156
157 do {
158 ret = process_package (hdl, inbuf, outbuf);
159 } while (ret == ret_eagain);
160
161 if (ret == ret_ok) {
162 if (cherokee_buffer_is_empty (outbuf))
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
163 return (HDL_CGI_BASE(hdl)->got_eof) ? ret_eof : ret_eagain;
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
164 }
165
166 return ret;
167 }
168
169 static ret_t
170 read_from_fcgi (cherokee_handler_cgi_base_t *cgi, cherokee_buffer_t *buffer)
171 {
172 ret_t ret;
173 size_t read = 0;
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
174 cherokee_handler_fcgi_t *fcgi = HDL_FCGI(cgi);
ba212a4 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@467 5dc97367-97…
alobbs authored
175
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
176 ret = cherokee_socket_read (&fcgi->socket, &fcgi->write_buffer, DEFAULT_READ_SIZE, &read);
177
178 switch (ret) {
179 case ret_eagain:
180 cherokee_thread_deactive_to_polling (HANDLER_THREAD(cgi), HANDLER_CONN(cgi),
181 fcgi->socket.socket, 0, false);
182 return ret_eagain;
183
184 case ret_ok:
185 ret = process_buffer (fcgi, &fcgi->write_buffer, buffer);
186 TRACE (ENTRIES, "%d bytes readed, buffer.len %d\n", read, buffer->len);
187 if ((ret == ret_ok) && cgi->got_eof && (buffer->len > 0))
188 return ret_eof_have_data;
189 return ret;
190
191 case ret_eof:
192 case ret_error:
193 cgi->got_eof = true;
194 return ret;
195
196 default:
197 RET_UNKNOWN(ret);
198 }
199
200 SHOULDNT_HAPPEN;
2e0ea0e @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@430 5dc97367-97…
alobbs authored
201 return ret_error;
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
202 }
203
204
b6c69ad @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@269 5dc97367-97…
alobbs authored
205 static ret_t
be04810 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@283 5dc97367-97…
alobbs authored
206 props_free (cherokee_handler_fcgi_props_t *props)
207 {
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
208 if (props->balancer != NULL)
209 cherokee_balancer_free (props->balancer);
623deda @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@294 5dc97367-97…
alobbs authored
210
211 return cherokee_handler_cgi_base_props_free (PROP_CGI_BASE(props));
be04810 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@283 5dc97367-97…
alobbs authored
212 }
213
214
b69d2e0 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@476 5dc97367-97…
alobbs authored
215 ret_t
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
216 cherokee_handler_fcgi_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
b6c69ad @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@269 5dc97367-97…
alobbs authored
217 {
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
218 ret_t ret;
ee8023f @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@384 5dc97367-97…
alobbs authored
219 cherokee_list_t *i;
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
220 cherokee_handler_fcgi_props_t *props;
b6c69ad @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@269 5dc97367-97…
alobbs authored
221
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
222 /* Instance a new property object
223 */
224 if (*_props == NULL) {
225 CHEROKEE_NEW_STRUCT (n, handler_fcgi_props);
be04810 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@283 5dc97367-97…
alobbs authored
226
b69d2e0 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@476 5dc97367-97…
alobbs authored
227 cherokee_handler_cgi_base_props_init_base (PROP_CGI_BASE(n),
228 MODULE_PROPS_FREE(props_free));
229
230 INIT_LIST_HEAD (&n->server_list);
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
231 n->balancer = NULL;
232
233 *_props = MODULE_PROPS(n);
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
234 }
235
236 props = PROP_FCGI(*_props);
237
238 /* Parse the configuration tree
239 */
b6c69ad @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@269 5dc97367-97…
alobbs authored
240 cherokee_config_node_foreach (i, conf) {
241 cherokee_config_node_t *subconf = CONFIG_NODE(i);
242
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
243 if (equal_buf_str (&subconf->key, "balancer")) {
244 ret = cherokee_balancer_instance (&subconf->val, subconf, srv, &props->balancer);
b6c69ad @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@269 5dc97367-97…
alobbs authored
245 if (ret != ret_ok) return ret;
246 }
247 }
248
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
249 /* Init base class
250 */
251 ret = cherokee_handler_cgi_base_configure (conf, srv, _props);
252 if (ret != ret_ok) return ret;
253
254 /* Final checks
255 */
256 if (props->balancer == NULL) {
257 PRINT_ERROR_S ("ERROR: fcgi handler needs a balancer\n");
258 return ret_error;
259 }
260
261 return ret_ok;
b6c69ad @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@269 5dc97367-97…
alobbs authored
262 }
263
264
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
265 ret_t
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
266 cherokee_handler_fcgi_new (cherokee_handler_t **hdl, void *cnt, cherokee_module_props_t *props)
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
267 {
268 CHEROKEE_NEW_STRUCT (n, handler_fcgi);
269
270 /* Init the base class
271 */
b69d2e0 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@476 5dc97367-97…
alobbs authored
272 cherokee_handler_cgi_base_init (HDL_CGI_BASE(n), cnt, PLUGIN_INFO_HANDLER_PTR(fcgi),
273 HANDLER_PROPS(props), set_env_pair, read_from_fcgi);
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
274
275 /* Virtual methods
276 */
277 MODULE(n)->init = (handler_func_init_t) cherokee_handler_fcgi_init;
423d6fa @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@370 5dc97367-97…
alobbs authored
278 MODULE(n)->free = (module_func_free_t) cherokee_handler_fcgi_free;
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
279
280 /* Virtual methods: implemented by handler_cgi_base
281 */
282 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_cgi_base_step;
283 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_cgi_base_add_headers;
284
285 /* Properties
286 */
287 n->post_phase = fcgi_post_init;
288 n->post_len = 0;
289
290 cherokee_socket_init (&n->socket);
ba212a4 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@467 5dc97367-97…
alobbs authored
291 cherokee_socket_set_nodelay (&n->socket);
292
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
293 cherokee_buffer_init (&n->write_buffer);
294 cherokee_buffer_ensure_size (&n->write_buffer, 512);
295
296 /* Return the object
297 */
298 *hdl = HANDLER(n);
299 return ret_ok;
300 }
301
302
303 ret_t
304 cherokee_handler_fcgi_free (cherokee_handler_fcgi_t *hdl)
305 {
483759d @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@466 5dc97367-97…
alobbs authored
306 TRACE (ENTRIES, "fcgi handler free: %p\n", hdl);
307
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
308 cherokee_socket_close (&hdl->socket);
309 cherokee_socket_mrproper (&hdl->socket);
310
311 cherokee_buffer_mrproper (&hdl->write_buffer);
312
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
313 return cherokee_handler_cgi_base_free (HDL_CGI_BASE(hdl));
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
314 }
315
316
317 static void
318 fcgi_build_header (FCGI_Header *hdr, cuchar_t type, cushort_t request_id, cuint_t content_length, cuchar_t padding)
319 {
320 hdr->version = FCGI_VERSION_1;
321 hdr->type = type;
322 hdr->requestIdB0 = (cuchar_t) request_id;
323 hdr->requestIdB1 = (cuchar_t) (request_id >> 8) & 0xff;
324 hdr->contentLengthB0 = (cuchar_t) (content_length % 256);
325 hdr->contentLengthB1 = (cuchar_t) (content_length / 256);
326 hdr->paddingLength = padding;
327 hdr->reserved = 0;
328 }
329
330 static void
331 fcgi_build_request_body (FCGI_BeginRequestRecord *request)
332 {
333 request->body.roleB0 = FCGI_RESPONDER;
334 request->body.roleB1 = 0;
335 request->body.flags = 0;
336 request->body.reserved[0] = 0;
337 request->body.reserved[1] = 0;
338 request->body.reserved[2] = 0;
339 request->body.reserved[3] = 0;
340 request->body.reserved[4] = 0;
341 }
342
343 static void
344 set_env_pair (cherokee_handler_cgi_base_t *cgi_base,
345 char *key, int key_len,
346 char *val, int val_len)
347 {
348 int len;
349 FCGI_BeginRequestRecord request;
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
350 cherokee_handler_fcgi_t *hdl = HDL_FCGI(cgi_base);
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
351 cherokee_buffer_t *buf = &hdl->write_buffer;
352
353 len = key_len + val_len;
354 len += key_len > 127 ? 4 : 1;
355 len += val_len > 127 ? 4 : 1;
356
357 fcgi_build_header (&request.header, FCGI_PARAMS, 1, len, 0);
358
359 cherokee_buffer_ensure_size (buf, buf->len + sizeof(FCGI_Header) + key_len + val_len);
360 cherokee_buffer_add (buf, (void *)&request.header, sizeof(FCGI_Header));
361
362 if (key_len <= 127) {
363 buf->buf[buf->len++] = key_len;
364 } else {
365 buf->buf[buf->len++] = ((key_len >> 24) & 0xff) | 0x80;
366 buf->buf[buf->len++] = (key_len >> 16) & 0xff;
367 buf->buf[buf->len++] = (key_len >> 8) & 0xff;
368 buf->buf[buf->len++] = (key_len >> 0) & 0xff;
369 }
370
371 if (val_len <= 127) {
372 buf->buf[buf->len++] = val_len;
373 } else {
374 buf->buf[buf->len++] = ((val_len >> 24) & 0xff) | 0x80;
375 buf->buf[buf->len++] = (val_len >> 16) & 0xff;
376 buf->buf[buf->len++] = (val_len >> 8) & 0xff;
377 buf->buf[buf->len++] = (val_len >> 0) & 0xff;
378 }
379
380 cherokee_buffer_add (buf, key, key_len);
381 cherokee_buffer_add (buf, val, val_len);
382 }
383
384
385 static ret_t
386 add_extra_fcgi_env (cherokee_handler_fcgi_t *hdl, cuint_t *last_header_offset)
387 {
388 ret_t ret;
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
389 cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(hdl);
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
390 cherokee_buffer_t buffer = CHEROKEE_BUF_INIT;
391 cherokee_connection_t *conn = HANDLER_CONN(hdl);
392
393 /* CONTENT_LENGTH
394 */
395 ret = cherokee_header_copy_known (&conn->header, header_content_length, &buffer);
396 if (ret == ret_ok)
397 set_env (cgi_base, "CONTENT_LENGTH", buffer.buf, buffer.len);
398
399 /* Add PATH_TRANSLATED only it there is pathinfo
400 */
401 #if 0
402 if (! cherokee_buffer_is_empty (&conn->pathinfo)) {
403 cherokee_buffer_add_buffer (&buffer, &conn->local_directory);
404 cherokee_buffer_add_buffer (&buffer, &conn->pathinfo);
405
406 set_env (cgi_base, "PATH_TRANSLATED", buffer.buf, buffer.len);
407 TRACE (ENTRIES, "PATH_TRANSLATED '%s'\n", cgi_base->executable.buf);
408 }
409 #endif
410
411 /* The last one
412 */
413 *last_header_offset = hdl->write_buffer.len;
414
415 set_env (cgi_base, "SCRIPT_FILENAME", cgi_base->executable.buf, cgi_base->executable.len);
416 TRACE (ENTRIES, "SCRIPT_FILENAME '%s'\n", cgi_base->executable.buf);
417
418 cherokee_buffer_mrproper (&buffer);
419 return ret_ok;
420 }
421
422
423 static void
424 fixup_padding (cherokee_buffer_t *buf, cuint_t last_header_offset)
425 {
426 cuint_t rest;
427 cuint_t pad;
428 static char padding[8] = {0, 0, 0, 0, 0, 0, 0, 0};
429 FCGI_Header *last_header;
430
431 if (buf->len <= 0)
432 return;
433 last_header = (FCGI_Header *) (buf->buf + last_header_offset);
434 rest = buf->len % 8;
435 pad = 8 - rest;
436
437 if (rest == 0)
438 return;
439
440 last_header->paddingLength = pad;
441
442 cherokee_buffer_ensure_size (buf, buf->len + pad);
443 cherokee_buffer_add (buf, padding, pad);
444 }
445
446 static void
447 add_empty_packet (cherokee_handler_fcgi_t *hdl, cuint_t type)
448 {
449 FCGI_BeginRequestRecord request;
450
451 fcgi_build_header (&request.header, type, 1, 0, 0);
452 cherokee_buffer_add (&hdl->write_buffer, (void *)&request.header, sizeof(FCGI_Header));
453
454 TRACE (ENTRIES, "empty packet type=%d, len=%d\n", type, hdl->write_buffer.len);
455 }
456
457
458 static ret_t
459 build_header (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *buffer)
460 {
461 FCGI_BeginRequestRecord request;
462 cuint_t last_header_offset;
2e0ea0e @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@430 5dc97367-97…
alobbs authored
463 cherokee_connection_t *conn = HANDLER_CONN(hdl);
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
464
465 /* Take care here, if the connection is reinjected, it
466 * shouldn't parse the arguments again.
467 */
468 if (conn->arguments == NULL)
469 cherokee_connection_parse_args (conn);
470
471 cherokee_buffer_clean (buffer);
472
473 /* FCGI_BEGIN_REQUEST
474 */
475 fcgi_build_header (&request.header, FCGI_BEGIN_REQUEST, 1, sizeof(request.body), 0);
476 fcgi_build_request_body (&request);
477
478 cherokee_buffer_add (buffer, (void *)&request, sizeof(FCGI_BeginRequestRecord));
479 TRACE (ENTRIES, "Added FCGI_BEGIN_REQUEST, len=%d\n", buffer->len);
480
481 /* Add enviroment variables
482 */
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
483 cherokee_handler_cgi_base_build_envp (HDL_CGI_BASE(hdl), conn);
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
484
485 add_extra_fcgi_env (hdl, &last_header_offset);
486 fixup_padding (buffer, last_header_offset);
487
488 /* There are not more parameters
489 */
490 add_empty_packet (hdl, FCGI_PARAMS);
491
492 TRACE (ENTRIES, "Added FCGI_PARAMS, len=%d\n", buffer->len);
493 return ret_ok;
494 }
495
496
497 static ret_t
498 connect_to_server (cherokee_handler_fcgi_t *hdl)
499 {
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
500 ret_t ret;
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
501 int try = 0;
502 cherokee_source_t *src = NULL;
503 cherokee_connection_t *conn = HANDLER_CONN(hdl);
b69d2e0 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@476 5dc97367-97…
alobbs authored
504 cherokee_handler_fcgi_props_t *props = HANDLER_FCGI_PROPS(hdl);
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
505
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
506 ret = cherokee_balancer_dispatch (props->balancer, conn, &src);
507 if (ret != ret_ok) return ret;
508
509 ret = cherokee_source_connect (src, &hdl->socket);
510 if (ret != ret_ok) {
511 cherokee_source_interpreter_t *src_int = SOURCE_INT(src);
512
513 ret = cherokee_source_interpreter_spawn (src_int);
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
514 if (ret != ret_ok) {
7c237a1 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@501 5dc97367-97…
alobbs authored
515 if (src_int->interpreter.buf)
516 TRACE (ENTRIES, "Couldn't spawn: %s\n", src_int->interpreter.buf);
517 else
518 TRACE (ENTRIES, "There was no interpreter to be spawned %s", "\n");
519 return ret_error;
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
520 }
2e0ea0e @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@430 5dc97367-97…
alobbs authored
521
522 while (true) {
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
523 ret = cherokee_source_connect (src, &hdl->socket);
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
524 if (ret == ret_ok) break;
525
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
526 TRACE (ENTRIES, "Couldn't connect: %s, try %d\n", src->host.buf ? src->host.buf : src->unix_socket.buf, try);
45ead25 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@428 5dc97367-97…
alobbs authored
527
2e0ea0e @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@430 5dc97367-97…
alobbs authored
528 if (try++ >= 3)
45ead25 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@428 5dc97367-97…
alobbs authored
529 return ret;
530
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
531 sleep (1);
532 }
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
533
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
534 }
7b0e48a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@387 5dc97367-97…
alobbs authored
535
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
536 TRACE (ENTRIES, "Connected sucessfully try=%d, fd=%d\n", try, hdl->socket.socket);
ba212a4 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@467 5dc97367-97…
alobbs authored
537
538 cherokee_fd_set_nonblocking (SOCKET_FD(&hdl->socket));
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
539 return ret_ok;
540 }
541
542
543 static ret_t
544 do_send (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *buffer)
545 {
2e0ea0e @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@430 5dc97367-97…
alobbs authored
546 ret_t ret;
b69d2e0 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@476 5dc97367-97…
alobbs authored
547 size_t written;
2e0ea0e @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@430 5dc97367-97…
alobbs authored
548 cherokee_connection_t *conn = HANDLER_CONN(hdl);
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
549
550 ret = cherokee_socket_write (&hdl->socket, buffer, &written);
ba212a4 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@467 5dc97367-97…
alobbs authored
551 switch (ret) {
552 case ret_ok:
3cbd17a @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@475 5dc97367-97…
alobbs authored
553 break;
ba212a4 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@467 5dc97367-97…
alobbs authored
554 case ret_eagain:
b69d2e0 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@476 5dc97367-97…
alobbs authored
555 if (written > 0)
556 break;
ba212a4 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@467 5dc97367-97…
alobbs authored
557 return ret_eagain;
558 default:
2e0ea0e @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@430 5dc97367-97…
alobbs authored
559 conn->error_code = http_bad_gateway;
ba212a4 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@467 5dc97367-97…
alobbs authored
560 return ret_error;
2e0ea0e @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@430 5dc97367-97…
alobbs authored
561 }
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
562
563 cherokee_buffer_move_to_begin (buffer, written);
564
565 TRACE (ENTRIES, "sent remaining=%d\n", buffer->len);
566
567 if (! cherokee_buffer_is_empty (buffer))
568 return ret_eagain;
569
570 return ret_ok;
571 }
572
573
574 static ret_t
f11857f @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@600 5dc97367-97…
alobbs authored
575 send_no_post (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *buf)
576 {
577 switch (hdl->post_phase) {
578 case fcgi_post_init:
579 add_empty_packet (hdl, FCGI_STDIN);
580 hdl->post_phase = fcgi_post_write;
581
582 case fcgi_post_write:
583 return do_send (hdl, buf);
584
585 default:
586 SHOULDNT_HAPPEN;
587 }
588 return ret_error;
589 }
590
591
592 static ret_t
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
593 send_post (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *buf)
594 {
595 ret_t ret;
596 cherokee_connection_t *conn = HANDLER_CONN(hdl);
597 static FCGI_Header empty_header = {0,0,0,0,0,0,0,0};
598
599 switch (hdl->post_phase) {
600 case fcgi_post_init:
601 TRACE (ENTRIES, "Post %s\n", "init");
602
603 /* Init the POST storing object
604 */
605 cherokee_post_walk_reset (&conn->post);
606 cherokee_post_get_len (&conn->post, &hdl->post_len);
607
608 if (hdl->post_len <= 0)
609 return ret_ok;
610
611 hdl->post_phase = fcgi_post_read;
612
613 case fcgi_post_read:
614 TRACE (ENTRIES, "Post %s\n", "read");
615
616 /* Add space for the header, it'll filled out later on..
617 */
618 if (cherokee_buffer_is_empty (buf)) {
619 cherokee_buffer_add (buf, (char *)&empty_header, sizeof (FCGI_Header));
620 }
621
622 /* Take a chunck of post
623 */
624 ret = cherokee_post_walk_read (&conn->post, buf, POST_PACKAGE_LEN);
625 switch (ret) {
626 case ret_ok:
627 case ret_eagain:
628 break;
629 case ret_error:
630 return ret;
631 default:
632 RET_UNKNOWN(ret);
633 return ret_error;
634 }
635
636 TRACE (ENTRIES, "Post buffer.len %d\n", buf->len);
637
638 /* Complete the header
639 */
640 if (buf->len > sizeof(FCGI_Header)) {
641 fcgi_build_header ((FCGI_Header *)buf->buf, FCGI_STDIN, 1,
642 buf->len - sizeof(FCGI_Header), 0);
643 }
644
645 /* Close STDIN if it was the last chunck
646 */
647 ret = cherokee_post_walk_finished (&conn->post);
648 if (ret == ret_ok) {
649 add_empty_packet (hdl, FCGI_STDIN);
650 }
651
652 hdl->post_phase = fcgi_post_write;
653
654 case fcgi_post_write:
655 TRACE (ENTRIES, "Post write, buf.len=%d (header len %d)\n", buf->len, sizeof(FCGI_Header));
656
657 if (! cherokee_buffer_is_empty (buf)) {
658 ret = do_send (hdl, buf);
659 switch (ret) {
660 case ret_ok:
661 break;
662 case ret_eagain:
663 return ret_eagain;
664 case ret_eof:
665 case ret_error:
666 return ret_error;
667 default:
668 RET_UNKNOWN(ret);
669 return ret_error;
670 }
671 }
672
673 if (! cherokee_buffer_is_empty (buf))
674 return ret_eagain;
675
676 ret = cherokee_post_walk_finished (&conn->post);
677 switch (ret) {
678 case ret_ok:
679 break;
680 case ret_error:
681 return ret_error;
682 case ret_eagain:
683 hdl->post_phase = fcgi_post_read;
684 return ret_eagain;
685 default:
686 RET_UNKNOWN(ret);
687 return ret_error;
688 }
689
690 TRACE (ENTRIES, "Post %s\n", "finished");
691 return ret_ok;
692
693 default:
694 SHOULDNT_HAPPEN;
695 }
696
697 return ret_error;
698 }
699
700
701 ret_t
702 cherokee_handler_fcgi_init (cherokee_handler_fcgi_t *hdl)
703 {
704 ret_t ret;
705 cherokee_connection_t *conn = HANDLER_CONN(hdl);
f11857f @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@600 5dc97367-97…
alobbs authored
706
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
707 switch (HDL_CGI_BASE(hdl)->init_phase) {
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
708 case hcgi_phase_build_headers:
709 TRACE (ENTRIES, "Init %s\n", "begins");
710
711 /* Prepare Post
712 */
713 if (! cherokee_post_is_empty (&conn->post)) {
714 cherokee_post_walk_reset (&conn->post);
715 cherokee_post_get_len (&conn->post, &hdl->post_len);
716 }
717
718 /* Extracts PATH_INFO and filename from request uri
719 */
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
720 ret = cherokee_handler_cgi_base_extract_path (HDL_CGI_BASE(hdl), false);
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
721 if (unlikely (ret < ret_ok)) return ret;
722
723 /* Build the headers
724 */
725 ret = build_header (hdl, &hdl->write_buffer);
726 if (unlikely (ret != ret_ok)) return ret;
727
728 /* Connect
729 */
730 ret = connect_to_server (hdl);
731 if (unlikely (ret != ret_ok)) {
2e0ea0e @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@430 5dc97367-97…
alobbs authored
732 conn->error_code = http_service_unavailable;
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
733 return ret;
734 }
735
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
736 HDL_CGI_BASE(hdl)->init_phase = hcgi_phase_send_headers;
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
737
738 case hcgi_phase_send_headers:
739 TRACE (ENTRIES, "Init %s\n", "send_headers");
740
741 /* Send the header
742 */
743 ret = do_send (hdl, &hdl->write_buffer);
744 if (ret != ret_ok) return ret;
745
3509796 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@282 5dc97367-97…
alobbs authored
746 HDL_CGI_BASE(hdl)->init_phase = hcgi_phase_send_post;
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
747
748 case hcgi_phase_send_post:
749 /* Send the Post
750 */
751 if (hdl->post_len > 0) {
752 return send_post (hdl, &hdl->write_buffer);
f11857f @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@600 5dc97367-97…
alobbs authored
753 } else {
754 ret = send_no_post (hdl, &hdl->write_buffer);
755 if (ret != ret_ok) return ret;
ae9d971 @alobbs git-svn-id: svn://cherokee-project.com/cherokee/trunk@243 5dc97367-97…
alobbs authored
756 }
757 break;
758 }
759
760 TRACE (ENTRIES, "Init %s\n", "finishes");
761
762 cherokee_buffer_clean (&hdl->write_buffer);
763 return ret_ok;
764 }
765
Something went wrong with that request. Please try again.