~ubuntu-branches/ubuntu/natty/lighttpd/natty

« back to all changes in this revision

Viewing changes to src/mod_fastcgi.c

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Marek
  • Date: 2005-11-26 11:48:51 UTC
  • Revision ID: james.westby@ubuntu.com-20051126114851-76t9q0rrwbzjnt2t
Tags: upstream-1.4.8
ImportĀ upstreamĀ versionĀ 1.4.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <sys/types.h>
 
2
#include <unistd.h>
 
3
#include <errno.h>
 
4
#include <fcntl.h>
 
5
#include <string.h>
 
6
#include <stdlib.h>
 
7
#include <ctype.h>
 
8
#include <assert.h>
 
9
#include <signal.h>
 
10
 
 
11
#include "buffer.h"
 
12
#include "server.h"
 
13
#include "keyvalue.h"
 
14
#include "log.h"
 
15
 
 
16
#include "http_chunk.h"
 
17
#include "fdevent.h"
 
18
#include "connections.h"
 
19
#include "response.h"
 
20
#include "joblist.h"
 
21
 
 
22
#include "plugin.h"
 
23
 
 
24
#include "inet_ntop_cache.h"
 
25
#include "stat_cache.h"
 
26
 
 
27
#include <fastcgi.h>
 
28
#include <stdio.h>
 
29
 
 
30
#ifdef HAVE_SYS_FILIO_H
 
31
# include <sys/filio.h>
 
32
#endif
 
33
 
 
34
#include "sys-socket.h"
 
35
 
 
36
 
 
37
#ifndef UNIX_PATH_MAX
 
38
# define UNIX_PATH_MAX 108
 
39
#endif
 
40
 
 
41
#ifdef HAVE_SYS_UIO_H
 
42
#include <sys/uio.h>
 
43
#endif
 
44
#ifdef HAVE_SYS_WAIT_H
 
45
#include <sys/wait.h>
 
46
#endif
 
47
 
 
48
 
 
49
/*
 
50
 * 
 
51
 * TODO:
 
52
 * 
 
53
 * - add timeout for a connect to a non-fastcgi process
 
54
 *   (use state_timestamp + state)
 
55
 * 
 
56
 */
 
57
 
 
58
typedef struct fcgi_proc {
 
59
        size_t id; /* id will be between 1 and max_procs */
 
60
        buffer *socket; /* config.socket + "-" + id */
 
61
        unsigned port;  /* config.port + pno */
 
62
        
 
63
        pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
 
64
 
 
65
 
 
66
        size_t load; /* number of requests waiting on this process */
 
67
 
 
68
        time_t last_used; /* see idle_timeout */
 
69
        size_t requests;  /* see max_requests */
 
70
        struct fcgi_proc *prev, *next; /* see first */
 
71
        
 
72
        time_t disable_ts; /* replace by host->something */
 
73
        
 
74
        int is_local;
 
75
 
 
76
        enum { PROC_STATE_UNSET,            /* init-phase */
 
77
                        PROC_STATE_RUNNING, /* alive */
 
78
                        PROC_STATE_DIED_WAIT_FOR_PID,
 
79
                        PROC_STATE_KILLED,  /* was killed as we don't have the load anymore */
 
80
                        PROC_STATE_DIED,    /* marked as dead, should be restarted */
 
81
                        PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
 
82
        } state; 
 
83
} fcgi_proc;
 
84
 
 
85
typedef struct {
 
86
        /* list of processes handling this extension
 
87
         * sorted by lowest load
 
88
         *
 
89
         * whenever a job is done move it up in the list
 
90
         * until it is sorted, move it down as soon as the 
 
91
         * job is started
 
92
         */
 
93
        fcgi_proc *first; 
 
94
        fcgi_proc *unused_procs; 
 
95
 
 
96
        /* 
 
97
         * spawn at least min_procs, at max_procs.
 
98
         *
 
99
         * as soon as the load of the first entry 
 
100
         * is max_load_per_proc we spawn a new one
 
101
         * and add it to the first entry and give it 
 
102
         * the load
 
103
         * 
 
104
         */
 
105
 
 
106
        unsigned short min_procs;
 
107
        unsigned short max_procs;
 
108
        size_t num_procs;    /* how many procs are started */
 
109
        size_t active_procs; /* how many of them are really running */
 
110
 
 
111
        unsigned short max_load_per_proc;
 
112
 
 
113
        /*
 
114
         * kick the process from the list if it was not
 
115
         * used for idle_timeout until min_procs is 
 
116
         * reached. this helps to get the processlist
 
117
         * small again we had a small peak load.
 
118
         *
 
119
         */
 
120
        
 
121
        unsigned short idle_timeout;
 
122
        
 
123
        /*
 
124
         * time after a disabled remote connection is tried to be re-enabled
 
125
         * 
 
126
         * 
 
127
         */
 
128
        
 
129
        unsigned short disable_time;
 
130
 
 
131
        /*
 
132
         * same fastcgi processes get a little bit larger
 
133
         * than wanted. max_requests_per_proc kills a 
 
134
         * process after a number of handled requests.
 
135
         *
 
136
         */
 
137
        size_t max_requests_per_proc;
 
138
        
 
139
 
 
140
        /* config */
 
141
 
 
142
        /* 
 
143
         * host:port 
 
144
         *
 
145
         * if host is one of the local IP adresses the 
 
146
         * whole connection is local
 
147
         *
 
148
         * if tcp/ip should be used host AND port have
 
149
         * to be specified 
 
150
         * 
 
151
         */ 
 
152
        buffer *host; 
 
153
        unsigned short port;
 
154
 
 
155
        /*
 
156
         * Unix Domain Socket
 
157
         *
 
158
         * instead of TCP/IP we can use Unix Domain Sockets
 
159
         * - more secure (you have fileperms to play with)
 
160
         * - more control (on locally)
 
161
         * - more speed (no extra overhead)
 
162
         */
 
163
        buffer *unixsocket;
 
164
 
 
165
        /* if socket is local we can start the fastcgi 
 
166
         * process ourself
 
167
         *
 
168
         * bin-path is the path to the binary
 
169
         *
 
170
         * check min_procs and max_procs for the number
 
171
         * of process to start-up
 
172
         */
 
173
        buffer *bin_path; 
 
174
        
 
175
        /* bin-path is set bin-environment is taken to 
 
176
         * create the environement before starting the
 
177
         * FastCGI process
 
178
         * 
 
179
         */
 
180
        array *bin_env;
 
181
        
 
182
        array *bin_env_copy;
 
183
        
 
184
        /*
 
185
         * docroot-translation between URL->phys and the 
 
186
         * remote host
 
187
         *
 
188
         * reasons:
 
189
         * - different dir-layout if remote
 
190
         * - chroot if local
 
191
         *
 
192
         */
 
193
        buffer *docroot;
 
194
 
 
195
        /*
 
196
         * fastcgi-mode:
 
197
         * - responser
 
198
         * - authorizer
 
199
         *
 
200
         */
 
201
        unsigned short mode;
 
202
 
 
203
        /*
 
204
         * check_local tell you if the phys file is stat()ed 
 
205
         * or not. FastCGI doesn't care if the service is
 
206
         * remote. If the web-server side doesn't contain
 
207
         * the fastcgi-files we should not stat() for them
 
208
         * and say '404 not found'.
 
209
         */
 
210
        unsigned short check_local;
 
211
 
 
212
        /*
 
213
         * append PATH_INFO to SCRIPT_FILENAME
 
214
         * 
 
215
         * php needs this if cgi.fix_pathinfo is provied
 
216
         * 
 
217
         */
 
218
        
 
219
        unsigned short break_scriptfilename_for_php;
 
220
 
 
221
        /*
 
222
         * If the backend includes X-LIGHTTPD-send-file in the response
 
223
         * we use the value as filename and ignore the content.
 
224
         *
 
225
         */
 
226
        unsigned short allow_xsendfile;
 
227
                
 
228
        ssize_t load; /* replace by host->load */
 
229
 
 
230
        size_t max_id; /* corresponds most of the time to
 
231
        num_procs.
 
232
        
 
233
        only if a process is killed max_id waits for the process itself
 
234
        to die and decrements its afterwards */
 
235
 
 
236
        buffer *strip_request_uri;
 
237
} fcgi_extension_host;
 
238
 
 
239
/*
 
240
 * one extension can have multiple hosts assigned
 
241
 * one host can spawn additional processes on the same 
 
242
 *   socket (if we control it)
 
243
 *
 
244
 * ext -> host -> procs
 
245
 *    1:n     1:n
 
246
 *
 
247
 * if the fastcgi process is remote that whole goes down 
 
248
 * to
 
249
 *
 
250
 * ext -> host -> procs
 
251
 *    1:n     1:1 
 
252
 *
 
253
 * in case of PHP and FCGI_CHILDREN we have again a procs
 
254
 * but we don't control it directly.
 
255
 *
 
256
 */
 
257
 
 
258
typedef struct {
 
259
        buffer *key; /* like .php */
 
260
 
 
261
        fcgi_extension_host **hosts;
 
262
        
 
263
        size_t used;
 
264
        size_t size;
 
265
} fcgi_extension;
 
266
 
 
267
typedef struct {
 
268
        fcgi_extension **exts;
 
269
 
 
270
        size_t used;
 
271
        size_t size;
 
272
} fcgi_exts;
 
273
 
 
274
 
 
275
typedef struct {
 
276
        fcgi_exts *exts; 
 
277
        
 
278
        int debug;
 
279
} plugin_config;
 
280
 
 
281
typedef struct {
 
282
        size_t *ptr;
 
283
        size_t used;
 
284
        size_t size;
 
285
} buffer_uint;
 
286
 
 
287
typedef struct {
 
288
        char **ptr;
 
289
        
 
290
        size_t size;
 
291
        size_t used;
 
292
} char_array;
 
293
 
 
294
/* generic plugin data, shared between all connections */
 
295
typedef struct {
 
296
        PLUGIN_DATA;
 
297
        buffer_uint fcgi_request_id;
 
298
        
 
299
        buffer *fcgi_env;
 
300
        
 
301
        buffer *path;
 
302
        buffer *parse_response;
 
303
        
 
304
        plugin_config **config_storage;
 
305
        
 
306
        plugin_config conf; /* this is only used as long as no handler_ctx is setup */
 
307
} plugin_data;
 
308
 
 
309
/* connection specific data */
 
310
typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE, 
 
311
                FCGI_STATE_WRITE, FCGI_STATE_READ 
 
312
} fcgi_connection_state_t;
 
313
 
 
314
typedef struct {
 
315
        fcgi_proc *proc;
 
316
        fcgi_extension_host *host;
 
317
        
 
318
        fcgi_connection_state_t state;
 
319
        time_t   state_timestamp;
 
320
        
 
321
        int      reconnects; /* number of reconnect attempts */
 
322
        
 
323
        chunkqueue *rb; /* read queue */
 
324
        chunkqueue *wb; /* write queue */
 
325
        
 
326
        buffer   *response_header;
 
327
        
 
328
        int       delayed;   /* flag to mark that the connect() is delayed */
 
329
        
 
330
        size_t    request_id;
 
331
        int       fd;        /* fd to the fastcgi process */
 
332
        int       fde_ndx;   /* index into the fd-event buffer */
 
333
 
 
334
        pid_t     pid;
 
335
        int       got_proc;
 
336
 
 
337
        int       send_content_body;
 
338
        
 
339
        plugin_config conf;
 
340
        
 
341
        connection *remote_conn;  /* dumb pointer */
 
342
        plugin_data *plugin_data; /* dumb pointer */
 
343
} handler_ctx;
 
344
 
 
345
 
 
346
/* ok, we need a prototype */
 
347
static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
 
348
 
 
349
int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc);
 
350
 
 
351
 
 
352
 
 
353
static handler_ctx * handler_ctx_init() {
 
354
        handler_ctx * hctx;
 
355
        
 
356
        hctx = calloc(1, sizeof(*hctx));
 
357
        assert(hctx);
 
358
        
 
359
        hctx->fde_ndx = -1;
 
360
        
 
361
        hctx->response_header = buffer_init();
 
362
        
 
363
        hctx->request_id = 0;
 
364
        hctx->state = FCGI_STATE_INIT;
 
365
        hctx->proc = NULL;
 
366
        
 
367
        hctx->fd = -1;
 
368
        
 
369
        hctx->delayed = 0;
 
370
 
 
371
        hctx->reconnects = 0;
 
372
        hctx->send_content_body = 1;
 
373
 
 
374
        hctx->rb = chunkqueue_init();
 
375
        hctx->wb = chunkqueue_init();
 
376
        
 
377
        return hctx;
 
378
}
 
379
 
 
380
static void handler_ctx_free(handler_ctx *hctx) {
 
381
        buffer_free(hctx->response_header);
 
382
 
 
383
        chunkqueue_free(hctx->rb);
 
384
        chunkqueue_free(hctx->wb);
 
385
 
 
386
        free(hctx);
 
387
}
 
388
 
 
389
fcgi_proc *fastcgi_process_init() {
 
390
        fcgi_proc *f;
 
391
 
 
392
        f = calloc(1, sizeof(*f));
 
393
        f->socket = buffer_init();
 
394
        
 
395
        f->prev = NULL;
 
396
        f->next = NULL;
 
397
        
 
398
        return f;
 
399
}
 
400
 
 
401
void fastcgi_process_free(fcgi_proc *f) {
 
402
        if (!f) return;
 
403
        
 
404
        fastcgi_process_free(f->next);
 
405
        
 
406
        buffer_free(f->socket);
 
407
        
 
408
        free(f);
 
409
}
 
410
 
 
411
fcgi_extension_host *fastcgi_host_init() {
 
412
        fcgi_extension_host *f;
 
413
 
 
414
        f = calloc(1, sizeof(*f));
 
415
 
 
416
        f->host = buffer_init();
 
417
        f->unixsocket = buffer_init();
 
418
        f->docroot = buffer_init();
 
419
        f->bin_path = buffer_init();
 
420
        f->bin_env = array_init();
 
421
        f->bin_env_copy = array_init();
 
422
        f->strip_request_uri = buffer_init();
 
423
        
 
424
        return f;
 
425
}
 
426
 
 
427
void fastcgi_host_free(fcgi_extension_host *h) {
 
428
        if (!h) return;
 
429
        
 
430
        buffer_free(h->host);
 
431
        buffer_free(h->unixsocket);
 
432
        buffer_free(h->docroot);
 
433
        buffer_free(h->bin_path);
 
434
        buffer_free(h->strip_request_uri);
 
435
        array_free(h->bin_env);
 
436
        array_free(h->bin_env_copy);
 
437
        
 
438
        fastcgi_process_free(h->first);
 
439
        fastcgi_process_free(h->unused_procs);
 
440
        
 
441
        free(h);
 
442
        
 
443
}
 
444
 
 
445
fcgi_exts *fastcgi_extensions_init() {
 
446
        fcgi_exts *f;
 
447
 
 
448
        f = calloc(1, sizeof(*f));
 
449
        
 
450
        return f;
 
451
}
 
452
 
 
453
void fastcgi_extensions_free(fcgi_exts *f) {
 
454
        size_t i;
 
455
        
 
456
        if (!f) return;
 
457
        
 
458
        for (i = 0; i < f->used; i++) {
 
459
                fcgi_extension *fe;
 
460
                size_t j;
 
461
                
 
462
                fe = f->exts[i];
 
463
                
 
464
                for (j = 0; j < fe->used; j++) {
 
465
                        fcgi_extension_host *h;
 
466
                        
 
467
                        h = fe->hosts[j];
 
468
                        
 
469
                        fastcgi_host_free(h);
 
470
                }
 
471
                
 
472
                buffer_free(fe->key);
 
473
                free(fe->hosts);
 
474
                
 
475
                free(fe);
 
476
        }
 
477
        
 
478
        free(f->exts);
 
479
        
 
480
        free(f);
 
481
}
 
482
 
 
483
int fastcgi_extension_insert(fcgi_exts *ext, buffer *key, fcgi_extension_host *fh) {
 
484
        fcgi_extension *fe;
 
485
        size_t i;
 
486
 
 
487
        /* there is something */
 
488
 
 
489
        for (i = 0; i < ext->used; i++) {
 
490
                if (buffer_is_equal(key, ext->exts[i]->key)) {
 
491
                        break;
 
492
                }
 
493
        }
 
494
 
 
495
        if (i == ext->used) {
 
496
                /* filextension is new */
 
497
                fe = calloc(1, sizeof(*fe));
 
498
                assert(fe);
 
499
                fe->key = buffer_init();
 
500
                buffer_copy_string_buffer(fe->key, key);
 
501
 
 
502
                /* */
 
503
 
 
504
                if (ext->size == 0) {
 
505
                        ext->size = 8;
 
506
                        ext->exts = malloc(ext->size * sizeof(*(ext->exts)));
 
507
                        assert(ext->exts);
 
508
                } else if (ext->used == ext->size) {
 
509
                        ext->size += 8;
 
510
                        ext->exts = realloc(ext->exts, ext->size * sizeof(*(ext->exts)));
 
511
                        assert(ext->exts);
 
512
                }
 
513
                ext->exts[ext->used++] = fe;
 
514
        } else {
 
515
                fe = ext->exts[i];
 
516
        }
 
517
 
 
518
        if (fe->size == 0) {
 
519
                fe->size = 4;
 
520
                fe->hosts = malloc(fe->size * sizeof(*(fe->hosts)));
 
521
                assert(fe->hosts);
 
522
        } else if (fe->size == fe->used) {
 
523
                fe->size += 4;
 
524
                fe->hosts = realloc(fe->hosts, fe->size * sizeof(*(fe->hosts)));
 
525
                assert(fe->hosts);
 
526
        }
 
527
 
 
528
        fe->hosts[fe->used++] = fh; 
 
529
 
 
530
        return 0;
 
531
        
 
532
}
 
533
 
 
534
INIT_FUNC(mod_fastcgi_init) {
 
535
        plugin_data *p;
 
536
        
 
537
        p = calloc(1, sizeof(*p));
 
538
        
 
539
        p->fcgi_env = buffer_init();
 
540
        
 
541
        p->path = buffer_init();
 
542
        p->parse_response = buffer_init();
 
543
        
 
544
        return p;
 
545
}
 
546
 
 
547
 
 
548
FREE_FUNC(mod_fastcgi_free) {
 
549
        plugin_data *p = p_d;
 
550
        buffer_uint *r = &(p->fcgi_request_id);
 
551
        
 
552
        UNUSED(srv);
 
553
 
 
554
        if (r->ptr) free(r->ptr);
 
555
        
 
556
        buffer_free(p->fcgi_env);
 
557
        buffer_free(p->path);
 
558
        buffer_free(p->parse_response);
 
559
        
 
560
        if (p->config_storage) {
 
561
                size_t i, j, n;
 
562
                for (i = 0; i < srv->config_context->used; i++) {
 
563
                        plugin_config *s = p->config_storage[i];
 
564
                        fcgi_exts *exts;
 
565
                        
 
566
                        if (!s) continue;
 
567
                        
 
568
                        exts = s->exts;
 
569
 
 
570
                        for (j = 0; j < exts->used; j++) {
 
571
                                fcgi_extension *ex;
 
572
                                
 
573
                                ex = exts->exts[j];
 
574
                                
 
575
                                for (n = 0; n < ex->used; n++) {
 
576
                                        fcgi_proc *proc;
 
577
                                        fcgi_extension_host *host;
 
578
                                        
 
579
                                        host = ex->hosts[n];
 
580
                                        
 
581
                                        for (proc = host->first; proc; proc = proc->next) {
 
582
                                                if (proc->pid != 0) kill(proc->pid, SIGTERM);
 
583
                                                
 
584
                                                if (proc->is_local && 
 
585
                                                    !buffer_is_empty(proc->socket)) {
 
586
                                                        unlink(proc->socket->ptr);
 
587
                                                }
 
588
                                        }
 
589
                                        
 
590
                                        for (proc = host->unused_procs; proc; proc = proc->next) {
 
591
                                                if (proc->pid != 0) kill(proc->pid, SIGTERM);
 
592
                                                
 
593
                                                if (proc->is_local && 
 
594
                                                    !buffer_is_empty(proc->socket)) {
 
595
                                                        unlink(proc->socket->ptr);
 
596
                                                }
 
597
                                        }
 
598
                                }
 
599
                        }
 
600
                        
 
601
                        fastcgi_extensions_free(s->exts);
 
602
                        
 
603
                        free(s);
 
604
                }
 
605
                free(p->config_storage);
 
606
        }
 
607
        
 
608
        free(p);
 
609
        
 
610
        return HANDLER_GO_ON;
 
611
}
 
612
 
 
613
static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
 
614
        char *dst;
 
615
        
 
616
        if (!key || !val) return -1;
 
617
        
 
618
        dst = malloc(key_len + val_len + 3);
 
619
        memcpy(dst, key, key_len);
 
620
        dst[key_len] = '=';
 
621
        /* add the \0 from the value */
 
622
        memcpy(dst + key_len + 1, val, val_len + 1);
 
623
        
 
624
        if (env->size == 0) {
 
625
                env->size = 16;
 
626
                env->ptr = malloc(env->size * sizeof(*env->ptr));
 
627
        } else if (env->size == env->used + 1) {
 
628
                env->size += 16;
 
629
                env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
 
630
        }
 
631
        
 
632
        env->ptr[env->used++] = dst;
 
633
        
 
634
        return 0;
 
635
}
 
636
 
 
637
static int parse_binpath(char_array *env, buffer *b) {
 
638
        char *start;
 
639
        size_t i;
 
640
        /* search for spaces */
 
641
 
 
642
        start = b->ptr;
 
643
        for (i = 0; i < b->used - 1; i++) {
 
644
                switch(b->ptr[i]) {
 
645
                case ' ':
 
646
                case '\t':
 
647
                        /* a WS, stop here and copy the argument */
 
648
 
 
649
                        if (env->size == 0) {
 
650
                                env->size = 16;
 
651
                                env->ptr = malloc(env->size * sizeof(*env->ptr));
 
652
                        } else if (env->size == env->used) { 
 
653
                                env->size += 16;
 
654
                                env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
 
655
                        }
 
656
                        
 
657
                        b->ptr[i] = '\0';
 
658
 
 
659
                        env->ptr[env->used++] = start;
 
660
                        
 
661
                        start = b->ptr + i + 1;
 
662
                        break;
 
663
                default:
 
664
                        break;
 
665
                }
 
666
        }
 
667
 
 
668
        if (env->size == 0) {
 
669
                env->size = 16;
 
670
                env->ptr = malloc(env->size * sizeof(*env->ptr));
 
671
        } else if (env->size == env->used) { /* we need one extra for the terminating NULL */
 
672
                env->size += 16;
 
673
                env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
 
674
        }
 
675
 
 
676
        /* the rest */
 
677
        env->ptr[env->used++] = start;
 
678
 
 
679
        if (env->size == 0) {
 
680
                env->size = 16;
 
681
                env->ptr = malloc(env->size * sizeof(*env->ptr));
 
682
        } else if (env->size == env->used) { /* we need one extra for the terminating NULL */
 
683
                env->size += 16;
 
684
                env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
 
685
        }
 
686
 
 
687
        /* terminate */
 
688
        env->ptr[env->used++] = NULL;
 
689
 
 
690
        return 0;
 
691
}
 
692
 
 
693
static int fcgi_spawn_connection(server *srv, 
 
694
                                 plugin_data *p,
 
695
                                 fcgi_extension_host *host,
 
696
                                 fcgi_proc *proc) {
 
697
        int fcgi_fd;
 
698
        int socket_type, status;
 
699
        struct timeval tv = { 0, 100 * 1000 };
 
700
#ifdef HAVE_SYS_UN_H
 
701
        struct sockaddr_un fcgi_addr_un;
 
702
#endif
 
703
        struct sockaddr_in fcgi_addr_in;
 
704
        struct sockaddr *fcgi_addr;
 
705
        
 
706
        socklen_t servlen;
 
707
        
 
708
#ifndef HAVE_FORK
 
709
        return -1;
 
710
#endif
 
711
        
 
712
        if (p->conf.debug) {
 
713
                log_error_write(srv, __FILE__, __LINE__, "sdb",
 
714
                                "new proc, socket:", proc->port, proc->socket);
 
715
        }
 
716
                
 
717
        if (!buffer_is_empty(proc->socket)) {
 
718
                memset(&fcgi_addr, 0, sizeof(fcgi_addr));
 
719
                
 
720
#ifdef HAVE_SYS_UN_H
 
721
                fcgi_addr_un.sun_family = AF_UNIX;
 
722
                strcpy(fcgi_addr_un.sun_path, proc->socket->ptr);
 
723
                
 
724
#ifdef SUN_LEN
 
725
                servlen = SUN_LEN(&fcgi_addr_un);
 
726
#else
 
727
                /* stevens says: */
 
728
                servlen = proc->socket->used - 1 + sizeof(fcgi_addr_un.sun_family);
 
729
#endif
 
730
                socket_type = AF_UNIX;
 
731
                fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
 
732
#else
 
733
                log_error_write(srv, __FILE__, __LINE__, "s",
 
734
                                "ERROR: Unix Domain sockets are not supported.");
 
735
                return -1;
 
736
#endif
 
737
        } else {
 
738
                fcgi_addr_in.sin_family = AF_INET;
 
739
                
 
740
                if (buffer_is_empty(host->host)) {
 
741
                        fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
 
742
                } else {
 
743
                        struct hostent *he;
 
744
                        
 
745
                        /* set a usefull default */
 
746
                        fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
 
747
                        
 
748
                        
 
749
                        if (NULL == (he = gethostbyname(host->host->ptr))) {
 
750
                                log_error_write(srv, __FILE__, __LINE__, 
 
751
                                                "sdb", "gethostbyname failed: ", 
 
752
                                                h_errno, host->host);
 
753
                                return -1;
 
754
                        }
 
755
                        
 
756
                        if (he->h_addrtype != AF_INET) {
 
757
                                log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
 
758
                                return -1;
 
759
                        }
 
760
                        
 
761
                        if (he->h_length != sizeof(struct in_addr)) {
 
762
                                log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
 
763
                                return -1;
 
764
                        }
 
765
                        
 
766
                        memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
 
767
                        
 
768
                }
 
769
                fcgi_addr_in.sin_port = htons(proc->port);
 
770
                servlen = sizeof(fcgi_addr_in);
 
771
                
 
772
                socket_type = AF_INET;
 
773
                fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
 
774
        }
 
775
        
 
776
        if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
 
777
                log_error_write(srv, __FILE__, __LINE__, "ss", 
 
778
                                "failed:", strerror(errno));
 
779
                return -1;
 
780
        }
 
781
        
 
782
        if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
 
783
                /* server is not up, spawn in  */
 
784
                pid_t child;
 
785
                int val;
 
786
                
 
787
                if (!buffer_is_empty(proc->socket)) {
 
788
                        unlink(proc->socket->ptr);
 
789
                }
 
790
                
 
791
                close(fcgi_fd);
 
792
                
 
793
                /* reopen socket */
 
794
                if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
 
795
                        log_error_write(srv, __FILE__, __LINE__, "ss", 
 
796
                                "socket failed:", strerror(errno));
 
797
                        return -1;
 
798
                }
 
799
                
 
800
                val = 1;
 
801
                if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
 
802
                        log_error_write(srv, __FILE__, __LINE__, "ss", 
 
803
                                        "socketsockopt failed:", strerror(errno));
 
804
                        return -1;
 
805
                }
 
806
                
 
807
                /* create socket */
 
808
                if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
 
809
                        log_error_write(srv, __FILE__, __LINE__, "sbds", 
 
810
                                "bind failed for:", 
 
811
                                proc->socket, 
 
812
                                proc->port, 
 
813
                                strerror(errno));
 
814
                        return -1;
 
815
                }
 
816
                
 
817
                if (-1 == listen(fcgi_fd, 1024)) {
 
818
                        log_error_write(srv, __FILE__, __LINE__, "ss", 
 
819
                                "listen failed:", strerror(errno));
 
820
                        return -1;
 
821
                }
 
822
                
 
823
#ifdef HAVE_FORK        
 
824
                switch ((child = fork())) {
 
825
                case 0: {
 
826
                        size_t i = 0;
 
827
                        char_array env;
 
828
                        char_array arg;
 
829
                        
 
830
                        /* create environment */
 
831
                        env.ptr = NULL;
 
832
                        env.size = 0;
 
833
                        env.used = 0;
 
834
                        
 
835
                        arg.ptr = NULL;
 
836
                        arg.size = 0;
 
837
                        arg.used = 0;
 
838
 
 
839
                        if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
 
840
                                close(FCGI_LISTENSOCK_FILENO);
 
841
                                dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
 
842
                                close(fcgi_fd);
 
843
                        }
 
844
                        
 
845
                        /* we don't need the client socket */
 
846
                        for (i = 3; i < 256; i++) {
 
847
                                close(i);
 
848
                        }
 
849
                        
 
850
                        /* build clean environment */
 
851
                        if (host->bin_env_copy->used) {
 
852
                                for (i = 0; i < host->bin_env_copy->used; i++) {
 
853
                                        data_string *ds = (data_string *)host->bin_env_copy->data[i];
 
854
                                        char *ge;
 
855
                                        
 
856
                                        if (NULL != (ge = getenv(ds->value->ptr))) {
 
857
                                                env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
 
858
                                        }
 
859
                                }
 
860
                        } else {
 
861
                                for (i = 0; environ[i]; i++) {
 
862
                                        char *eq;
 
863
                                        
 
864
                                        if (NULL != (eq = strchr(environ[i], '='))) {
 
865
                                                env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
 
866
                                        }
 
867
                                }
 
868
                        }
 
869
                        
 
870
                        /* create environment */
 
871
                        for (i = 0; i < host->bin_env->used; i++) {
 
872
                                data_string *ds = (data_string *)host->bin_env->data[i];
 
873
                                
 
874
                                env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
 
875
                        }
 
876
                        
 
877
                        for (i = 0; i < env.used; i++) {
 
878
                                /* search for PHP_FCGI_CHILDREN */
 
879
                                if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
 
880
                        }
 
881
                        
 
882
                        /* not found, add a default */
 
883
                        if (i == env.used) {
 
884
                                env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
 
885
                        }
 
886
                        
 
887
                        env.ptr[env.used] = NULL;
 
888
 
 
889
                        parse_binpath(&arg, host->bin_path);
 
890
                        
 
891
                        /* exec the cgi */
 
892
                        execve(arg.ptr[0], arg.ptr, env.ptr);
 
893
                        
 
894
                        log_error_write(srv, __FILE__, __LINE__, "sbs", 
 
895
                                        "execve failed for:", host->bin_path, strerror(errno));
 
896
                        
 
897
                        exit(errno);
 
898
                        
 
899
                        break;
 
900
                }
 
901
                case -1:
 
902
                        /* error */
 
903
                        break;
 
904
                default:
 
905
                        /* father */
 
906
                        
 
907
                        /* wait */
 
908
                        select(0, NULL, NULL, NULL, &tv);
 
909
                        
 
910
                        switch (waitpid(child, &status, WNOHANG)) {
 
911
                        case 0:
 
912
                                /* child still running after timeout, good */
 
913
                                break;
 
914
                        case -1:
 
915
                                /* no PID found ? should never happen */
 
916
                                log_error_write(srv, __FILE__, __LINE__, "ss", 
 
917
                                                "pid not found:", strerror(errno));
 
918
                                return -1;
 
919
                        default:
 
920
                                log_error_write(srv, __FILE__, __LINE__, "sbs",
 
921
                                                "the fastcgi-backend", host->bin_path, "failed to start:");
 
922
                                /* the child should not terminate at all */
 
923
                                if (WIFEXITED(status)) {
 
924
                                        log_error_write(srv, __FILE__, __LINE__, "sdb", 
 
925
                                                        "child exited with status", 
 
926
                                                        WEXITSTATUS(status), host->bin_path);
 
927
                                        log_error_write(srv, __FILE__, __LINE__, "s", 
 
928
                                                        "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
 
929
                                                        "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
 
930
                                                        "in the output, NOT (cgi) NOR (cli)\n"
 
931
                                                        "For more information check http://www.lighttpd.net/documentation/fastcgi.html#preparing-php-as-a-fastcgi-program");
 
932
                                        log_error_write(srv, __FILE__, __LINE__, "s",
 
933
                                                        "If this is PHP on Gentoo add fastcgi to the USE flags");
 
934
                                } else if (WIFSIGNALED(status)) {
 
935
                                        log_error_write(srv, __FILE__, __LINE__, "sd", 
 
936
                                                        "terminated by signal:", 
 
937
                                                        WTERMSIG(status));
 
938
 
 
939
                                        if (WTERMSIG(status) == 11) {
 
940
                                                log_error_write(srv, __FILE__, __LINE__, "ss",
 
941
                                                                "to be exact: it seg-fault, crashed, died, ... you get the idea." );
 
942
                                                log_error_write(srv, __FILE__, __LINE__, "s",
 
943
                                                                "If this is PHP try to remove the byte-code caches for now and try again.");
 
944
                                        }
 
945
                                } else {
 
946
                                        log_error_write(srv, __FILE__, __LINE__, "sd", 
 
947
                                                        "child died somehow:", 
 
948
                                                        status);
 
949
                                }
 
950
                                return -1;
 
951
                        }
 
952
 
 
953
                        /* register process */
 
954
                        proc->pid = child;
 
955
                        proc->last_used = srv->cur_ts;
 
956
                        proc->is_local = 1;
 
957
                                                
 
958
                        break;
 
959
                }
 
960
#endif
 
961
        } else {
 
962
                proc->is_local = 0;
 
963
                proc->pid = 0;
 
964
                
 
965
                if (p->conf.debug) {
 
966
                        log_error_write(srv, __FILE__, __LINE__, "sb",
 
967
                                        "(debug) socket is already used, won't spawn:",
 
968
                                        proc->socket);
 
969
                }
 
970
        }
 
971
        
 
972
        proc->state = PROC_STATE_RUNNING;
 
973
        host->active_procs++;
 
974
        
 
975
        close(fcgi_fd);
 
976
        
 
977
        return 0;
 
978
}
 
979
 
 
980
 
 
981
SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
 
982
        plugin_data *p = p_d;
 
983
        data_unset *du;
 
984
        size_t i = 0;
 
985
        buffer *fcgi_mode = buffer_init();
 
986
        
 
987
        config_values_t cv[] = { 
 
988
                { "fastcgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
 
989
                { "fastcgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
 
990
                { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
 
991
        };
 
992
        
 
993
        p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
 
994
        
 
995
        for (i = 0; i < srv->config_context->used; i++) {
 
996
                plugin_config *s;
 
997
                array *ca;
 
998
                
 
999
                s = malloc(sizeof(plugin_config));
 
1000
                s->exts          = fastcgi_extensions_init();
 
1001
                s->debug         = 0;
 
1002
                
 
1003
                cv[0].destination = s->exts;
 
1004
                cv[1].destination = &(s->debug);
 
1005
                
 
1006
                p->config_storage[i] = s;
 
1007
                ca = ((data_config *)srv->config_context->data[i])->value;
 
1008
        
 
1009
                if (0 != config_insert_values_global(srv, ca, cv)) {
 
1010
                        return HANDLER_ERROR;
 
1011
                }
 
1012
                
 
1013
                /* 
 
1014
                 * <key> = ( ... )
 
1015
                 */
 
1016
                
 
1017
                if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
 
1018
                        size_t j;
 
1019
                        data_array *da = (data_array *)du;
 
1020
                        
 
1021
                        if (du->type != TYPE_ARRAY) {
 
1022
                                log_error_write(srv, __FILE__, __LINE__, "sss", 
 
1023
                                                "unexpected type for key: ", "fastcgi.server", "array of strings");
 
1024
                                
 
1025
                                return HANDLER_ERROR;
 
1026
                        }
 
1027
                        
 
1028
                        
 
1029
                        /* 
 
1030
                         * fastcgi.server = ( "<ext>" => ( ... ), 
 
1031
                         *                    "<ext>" => ( ... ) )
 
1032
                         */
 
1033
                        
 
1034
                        for (j = 0; j < da->value->used; j++) {
 
1035
                                size_t n;
 
1036
                                data_array *da_ext = (data_array *)da->value->data[j];
 
1037
                                
 
1038
                                if (da->value->data[j]->type != TYPE_ARRAY) {
 
1039
                                        log_error_write(srv, __FILE__, __LINE__, "sssbs", 
 
1040
                                                        "unexpected type for key: ", "fastcgi.server", 
 
1041
                                                        "[", da->value->data[j]->key, "](string)");
 
1042
                                        
 
1043
                                        return HANDLER_ERROR;
 
1044
                                }
 
1045
                                
 
1046
                                /* 
 
1047
                                 * da_ext->key == name of the extension 
 
1048
                                 */
 
1049
                                
 
1050
                                /* 
 
1051
                                 * fastcgi.server = ( "<ext>" => 
 
1052
                                 *                     ( "<host>" => ( ... ), 
 
1053
                                 *                       "<host>" => ( ... )
 
1054
                                 *                     ), 
 
1055
                                 *                    "<ext>" => ... )
 
1056
                                 */
 
1057
                                        
 
1058
                                for (n = 0; n < da_ext->value->used; n++) {
 
1059
                                        data_array *da_host = (data_array *)da_ext->value->data[n];
 
1060
                                        
 
1061
                                        fcgi_extension_host *df;
 
1062
                                        
 
1063
                                        config_values_t fcv[] = { 
 
1064
                                                { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
 
1065
                                                { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
 
1066
                                                { "mode",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
 
1067
                                                { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
 
1068
                                                { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 4 */
 
1069
                                                
 
1070
                                                { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 5 */
 
1071
                                                { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 6 */
 
1072
                                                { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
 
1073
                                                { "max-procs",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 8 */
 
1074
                                                { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
 
1075
                                                { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
 
1076
                                                { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
 
1077
                                                
 
1078
                                                { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 12 */
 
1079
                                                { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 13 */
 
1080
                                                
 
1081
                                                { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 14 */
 
1082
                                                { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 15 */
 
1083
                                                { "strip-request-uri",  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 16 */
 
1084
                                                
 
1085
                                                { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
 
1086
                                        };
 
1087
                                        
 
1088
                                        if (da_host->type != TYPE_ARRAY) {
 
1089
                                                log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
 
1090
                                                                "unexpected type for key:", 
 
1091
                                                                "fastcgi.server", 
 
1092
                                                                "[", da_host->key, "](string)");
 
1093
                                                
 
1094
                                                return HANDLER_ERROR;
 
1095
                                        }
 
1096
                                        
 
1097
                                        df = fastcgi_host_init();
 
1098
                                        
 
1099
                                        df->check_local  = 1;
 
1100
                                        df->min_procs    = 4;
 
1101
                                        df->max_procs    = 4;
 
1102
                                        df->max_load_per_proc = 1;
 
1103
                                        df->idle_timeout = 60;
 
1104
                                        df->mode = FCGI_RESPONDER;
 
1105
                                        df->disable_time = 60;
 
1106
                                        df->break_scriptfilename_for_php = 0;
 
1107
                                        df->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
 
1108
                                        
 
1109
                                        fcv[0].destination = df->host;
 
1110
                                        fcv[1].destination = df->docroot;
 
1111
                                        fcv[2].destination = fcgi_mode;
 
1112
                                        fcv[3].destination = df->unixsocket;
 
1113
                                        fcv[4].destination = df->bin_path;
 
1114
                                        
 
1115
                                        fcv[5].destination = &(df->check_local);
 
1116
                                        fcv[6].destination = &(df->port);
 
1117
                                        fcv[7].destination = &(df->min_procs);
 
1118
                                        fcv[8].destination = &(df->max_procs);
 
1119
                                        fcv[9].destination = &(df->max_load_per_proc);
 
1120
                                        fcv[10].destination = &(df->idle_timeout);
 
1121
                                        fcv[11].destination = &(df->disable_time);
 
1122
                                        
 
1123
                                        fcv[12].destination = df->bin_env;
 
1124
                                        fcv[13].destination = df->bin_env_copy;
 
1125
                                        fcv[14].destination = &(df->break_scriptfilename_for_php);
 
1126
                                        fcv[15].destination = &(df->allow_xsendfile);
 
1127
                                        fcv[16].destination = df->strip_request_uri;
 
1128
                                        
 
1129
                                        if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
 
1130
                                                return HANDLER_ERROR;
 
1131
                                        }
 
1132
                                                        
 
1133
                                        if ((!buffer_is_empty(df->host) || df->port) && 
 
1134
                                            !buffer_is_empty(df->unixsocket)) {
 
1135
                                                log_error_write(srv, __FILE__, __LINE__, "s", 
 
1136
                                                                "either host+port or socket");
 
1137
                                                
 
1138
                                                return HANDLER_ERROR;
 
1139
                                        }
 
1140
                                        
 
1141
                                        if (!buffer_is_empty(df->unixsocket)) {
 
1142
                                                /* unix domain socket */
 
1143
                                                
 
1144
                                                if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
 
1145
                                                        log_error_write(srv, __FILE__, __LINE__, "s", 
 
1146
                                                                        "path of the unixdomain socket is too large");
 
1147
                                                        return HANDLER_ERROR;
 
1148
                                                }
 
1149
                                        } else {
 
1150
                                                /* tcp/ip */
 
1151
                                                
 
1152
                                                if (buffer_is_empty(df->host) && 
 
1153
                                                    buffer_is_empty(df->bin_path)) {
 
1154
                                                        log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
 
1155
                                                                        "missing key (string):", 
 
1156
                                                                        da->key,
 
1157
                                                                        da_ext->key,
 
1158
                                                                        da_host->key,
 
1159
                                                                        "host");
 
1160
                                                        
 
1161
                                                        return HANDLER_ERROR;
 
1162
                                                } else if (df->port == 0) {
 
1163
                                                        log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
 
1164
                                                                        "missing key (short):", 
 
1165
                                                                        da->key,
 
1166
                                                                        da_ext->key,
 
1167
                                                                        da_host->key,
 
1168
                                                                        "port");
 
1169
                                                        return HANDLER_ERROR;
 
1170
                                                }
 
1171
                                        }
 
1172
                                                
 
1173
                                        if (!buffer_is_empty(df->bin_path)) { 
 
1174
                                                /* a local socket + self spawning */
 
1175
                                                size_t pno;
 
1176
 
 
1177
                                                /* HACK:  just to make sure the adaptive spawing is disabled */
 
1178
                                                df->min_procs = df->max_procs;
 
1179
                                                
 
1180
                                                if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
 
1181
                                                if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
 
1182
                                                
 
1183
                                                if (s->debug) {
 
1184
                                                        log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
 
1185
                                                                        "--- fastcgi spawning local",
 
1186
                                                                        "\n\tproc:", df->bin_path,
 
1187
                                                                        "\n\tport:", df->port,
 
1188
                                                                        "\n\tsocket", df->unixsocket,
 
1189
                                                                        "\n\tmin-procs:", df->min_procs,
 
1190
                                                                        "\n\tmax-procs:", df->max_procs);
 
1191
                                                }
 
1192
                                                
 
1193
                                                for (pno = 0; pno < df->min_procs; pno++) {
 
1194
                                                        fcgi_proc *proc;
 
1195
 
 
1196
                                                        proc = fastcgi_process_init();
 
1197
                                                        proc->id = df->num_procs++;
 
1198
                                                        df->max_id++;
 
1199
 
 
1200
                                                        if (buffer_is_empty(df->unixsocket)) {
 
1201
                                                                proc->port = df->port + pno;
 
1202
                                                        } else {
 
1203
                                                                buffer_copy_string_buffer(proc->socket, df->unixsocket);
 
1204
                                                                buffer_append_string(proc->socket, "-");
 
1205
                                                                buffer_append_long(proc->socket, pno);
 
1206
                                                        }
 
1207
                                                        
 
1208
                                                        if (s->debug) {
 
1209
                                                                log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
 
1210
                                                                                "--- fastcgi spawning",
 
1211
                                                                                "\n\tport:", df->port,
 
1212
                                                                                "\n\tsocket", df->unixsocket,
 
1213
                                                                                "\n\tcurrent:", pno, "/", df->min_procs);
 
1214
                                                        }
 
1215
                                                        
 
1216
                                                        if (fcgi_spawn_connection(srv, p, df, proc)) {
 
1217
                                                                log_error_write(srv, __FILE__, __LINE__, "s",
 
1218
                                                                                "[ERROR]: spawning fcgi failed.");
 
1219
                                                                return HANDLER_ERROR;
 
1220
                                                        }
 
1221
                                                        
 
1222
                                                        proc->next = df->first;
 
1223
                                                        if (df->first)  df->first->prev = proc;
 
1224
                                                        
 
1225
                                                        df->first = proc;
 
1226
                                                }
 
1227
                                        } else {
 
1228
                                                fcgi_proc *fp;
 
1229
                                                
 
1230
                                                fp = fastcgi_process_init();
 
1231
                                                fp->id = df->num_procs++;
 
1232
                                                df->max_id++;
 
1233
                                                df->active_procs++;
 
1234
                                                fp->state = PROC_STATE_RUNNING;
 
1235
                                                
 
1236
                                                if (buffer_is_empty(df->unixsocket)) {
 
1237
                                                        fp->port = df->port;
 
1238
                                                } else {
 
1239
                                                        buffer_copy_string_buffer(fp->socket, df->unixsocket);
 
1240
                                                }
 
1241
                                                
 
1242
                                                df->first = fp;
 
1243
                                                
 
1244
                                                df->min_procs = 1;
 
1245
                                                df->max_procs = 1;
 
1246
                                        }
 
1247
                                        
 
1248
                                        if (!buffer_is_empty(fcgi_mode)) {
 
1249
                                                if (strcmp(fcgi_mode->ptr, "responder") == 0) {
 
1250
                                                        df->mode = FCGI_RESPONDER;
 
1251
                                                } else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) {
 
1252
                                                        df->mode = FCGI_AUTHORIZER;
 
1253
                                                        if (buffer_is_empty(df->docroot)) {
 
1254
                                                                log_error_write(srv, __FILE__, __LINE__, "s",
 
1255
                                                                                "ERROR: docroot is required for authorizer mode.");
 
1256
                                                                return HANDLER_ERROR;
 
1257
                                                        }
 
1258
                                                } else {
 
1259
                                                        log_error_write(srv, __FILE__, __LINE__, "sbs",
 
1260
                                                                        "WARNING: unknown fastcgi mode:",
 
1261
                                                                        fcgi_mode, "(ignored, mode set to responder)");
 
1262
                                                }
 
1263
                                        }
 
1264
                                        
 
1265
                                        /* if extension already exists, take it */
 
1266
                                        fastcgi_extension_insert(s->exts, da_ext->key, df);
 
1267
                                }
 
1268
                        }
 
1269
                }
 
1270
        }
 
1271
        
 
1272
        buffer_free(fcgi_mode);
 
1273
        
 
1274
        return HANDLER_GO_ON;
 
1275
}
 
1276
 
 
1277
static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
 
1278
        hctx->state = state;
 
1279
        hctx->state_timestamp = srv->cur_ts;
 
1280
        
 
1281
        return 0;
 
1282
}
 
1283
 
 
1284
 
 
1285
static size_t fcgi_requestid_new(server *srv, plugin_data *p) {
 
1286
        size_t m = 0;
 
1287
        size_t i;
 
1288
        buffer_uint *r = &(p->fcgi_request_id);
 
1289
        
 
1290
        UNUSED(srv);
 
1291
 
 
1292
        for (i = 0; i < r->used; i++) {
 
1293
                if (r->ptr[i] > m) m = r->ptr[i];
 
1294
        }
 
1295
        
 
1296
        if (r->size == 0) {
 
1297
                r->size = 16;
 
1298
                r->ptr = malloc(sizeof(*r->ptr) * r->size);
 
1299
        } else if (r->used == r->size) {
 
1300
                r->size += 16;
 
1301
                r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
 
1302
        }
 
1303
        
 
1304
        r->ptr[r->used++] = ++m;
 
1305
        
 
1306
        return m;
 
1307
}
 
1308
 
 
1309
static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
 
1310
        size_t i;
 
1311
        buffer_uint *r = &(p->fcgi_request_id);
 
1312
        
 
1313
        UNUSED(srv);
 
1314
 
 
1315
        for (i = 0; i < r->used; i++) {
 
1316
                if (r->ptr[i] == request_id) break;
 
1317
        }
 
1318
        
 
1319
        if (i != r->used) {
 
1320
                /* found */
 
1321
                
 
1322
                if (i != r->used - 1) {
 
1323
                        r->ptr[i] = r->ptr[r->used - 1];
 
1324
                }
 
1325
                r->used--;
 
1326
        }
 
1327
        
 
1328
        return 0;
 
1329
}
 
1330
 
 
1331
void fcgi_connection_close(server *srv, handler_ctx *hctx) {
 
1332
        plugin_data *p;
 
1333
        connection  *con;
 
1334
        
 
1335
        if (NULL == hctx) return;
 
1336
        
 
1337
        p    = hctx->plugin_data;
 
1338
        con  = hctx->remote_conn;
 
1339
        
 
1340
        if (con->mode != p->id) {
 
1341
                WP();
 
1342
                return;
 
1343
        }
 
1344
        
 
1345
        if (hctx->fd != -1) {
 
1346
                fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
 
1347
                fdevent_unregister(srv->ev, hctx->fd);
 
1348
                close(hctx->fd);
 
1349
                srv->cur_fds--;
 
1350
        }
 
1351
        
 
1352
        if (hctx->request_id != 0) {
 
1353
                fcgi_requestid_del(srv, p, hctx->request_id);
 
1354
        }
 
1355
 
 
1356
        if (hctx->host && hctx->proc) {
 
1357
                hctx->host->load--;
 
1358
                
 
1359
                if (hctx->got_proc) {
 
1360
                        /* after the connect the process gets a load */
 
1361
                        hctx->proc->load--;
 
1362
                        
 
1363
                        if (p->conf.debug) {
 
1364
                                log_error_write(srv, __FILE__, __LINE__, "sddb",
 
1365
                                                "release proc:", 
 
1366
                                                hctx->fd,
 
1367
                                                hctx->proc->pid, hctx->proc->socket);
 
1368
                        }
 
1369
                }
 
1370
 
 
1371
                fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
 
1372
        }
 
1373
 
 
1374
        
 
1375
        handler_ctx_free(hctx);
 
1376
        con->plugin_ctx[p->id] = NULL;  
 
1377
}
 
1378
 
 
1379
static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
 
1380
        plugin_data *p    = hctx->plugin_data;
 
1381
        
 
1382
        /* child died 
 
1383
         * 
 
1384
         * 1. 
 
1385
         * 
 
1386
         * connect was ok, connection was accepted
 
1387
         * but the php accept loop checks after the accept if it should die or not.
 
1388
         * 
 
1389
         * if yes we can only detect it at a write() 
 
1390
         * 
 
1391
         * next step is resetting this attemp and setup a connection again
 
1392
         * 
 
1393
         * if we have more then 5 reconnects for the same request, die
 
1394
         * 
 
1395
         * 2. 
 
1396
         * 
 
1397
         * we have a connection but the child died by some other reason
 
1398
         * 
 
1399
         */
 
1400
        
 
1401
        fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
 
1402
        fdevent_unregister(srv->ev, hctx->fd);
 
1403
        close(hctx->fd);
 
1404
        srv->cur_fds--;
 
1405
        
 
1406
        fcgi_requestid_del(srv, p, hctx->request_id);
 
1407
        
 
1408
        fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
 
1409
        
 
1410
        hctx->request_id = 0;
 
1411
        hctx->reconnects++;
 
1412
        
 
1413
        if (p->conf.debug) {
 
1414
                log_error_write(srv, __FILE__, __LINE__, "sddb",
 
1415
                                "release proc:", 
 
1416
                                hctx->fd,
 
1417
                                hctx->proc->pid, hctx->proc->socket);
 
1418
        }
 
1419
        
 
1420
        hctx->proc->load--;
 
1421
        fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
 
1422
        
 
1423
        return 0;
 
1424
}
 
1425
 
 
1426
 
 
1427
static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
 
1428
        plugin_data *p = p_d;
 
1429
        
 
1430
        fcgi_connection_close(srv, con->plugin_ctx[p->id]);
 
1431
        
 
1432
        return HANDLER_GO_ON;
 
1433
}
 
1434
 
 
1435
 
 
1436
static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
 
1437
        size_t len;
 
1438
        
 
1439
        if (!key || !val) return -1;
 
1440
        
 
1441
        len = key_len + val_len;
 
1442
        
 
1443
        len += key_len > 127 ? 4 : 1;
 
1444
        len += val_len > 127 ? 4 : 1;
 
1445
        
 
1446
        buffer_prepare_append(env, len);
 
1447
        
 
1448
        if (key_len > 127) {
 
1449
                env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
 
1450
                env->ptr[env->used++] = (key_len >> 16) & 0xff;
 
1451
                env->ptr[env->used++] = (key_len >> 8) & 0xff;
 
1452
                env->ptr[env->used++] = (key_len >> 0) & 0xff;
 
1453
        } else {
 
1454
                env->ptr[env->used++] = (key_len >> 0) & 0xff;
 
1455
        }
 
1456
        
 
1457
        if (val_len > 127) {
 
1458
                env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
 
1459
                env->ptr[env->used++] = (val_len >> 16) & 0xff;
 
1460
                env->ptr[env->used++] = (val_len >> 8) & 0xff;
 
1461
                env->ptr[env->used++] = (val_len >> 0) & 0xff;
 
1462
        } else {
 
1463
                env->ptr[env->used++] = (val_len >> 0) & 0xff;
 
1464
        }
 
1465
        
 
1466
        memcpy(env->ptr + env->used, key, key_len);
 
1467
        env->used += key_len;
 
1468
        memcpy(env->ptr + env->used, val, val_len);
 
1469
        env->used += val_len;
 
1470
        
 
1471
        return 0;
 
1472
}
 
1473
 
 
1474
static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_id, int contentLength, unsigned char paddingLength) {
 
1475
        header->version = FCGI_VERSION_1;
 
1476
        header->type = type;
 
1477
        header->requestIdB0 = request_id & 0xff;
 
1478
        header->requestIdB1 = (request_id >> 8) & 0xff;
 
1479
        header->contentLengthB0 = contentLength & 0xff;
 
1480
        header->contentLengthB1 = (contentLength >> 8) & 0xff;
 
1481
        header->paddingLength = paddingLength;
 
1482
        header->reserved = 0;
 
1483
        
 
1484
        return 0;
 
1485
}
 
1486
/**
 
1487
 * 
 
1488
 * returns
 
1489
 *   -1 error
 
1490
 *    0 connected
 
1491
 *    1 not connected yet
 
1492
 */
 
1493
 
 
1494
static int fcgi_establish_connection(server *srv, handler_ctx *hctx) {
 
1495
        struct sockaddr *fcgi_addr;
 
1496
        struct sockaddr_in fcgi_addr_in;
 
1497
#ifdef HAVE_SYS_UN_H
 
1498
        struct sockaddr_un fcgi_addr_un;
 
1499
#endif
 
1500
        socklen_t servlen;
 
1501
        
 
1502
        fcgi_extension_host *host = hctx->host;
 
1503
        fcgi_proc *proc   = hctx->proc;
 
1504
        int fcgi_fd       = hctx->fd;
 
1505
        
 
1506
        memset(&fcgi_addr, 0, sizeof(fcgi_addr));
 
1507
        
 
1508
        if (!buffer_is_empty(proc->socket)) {
 
1509
#ifdef HAVE_SYS_UN_H
 
1510
                /* use the unix domain socket */
 
1511
                fcgi_addr_un.sun_family = AF_UNIX;
 
1512
                strcpy(fcgi_addr_un.sun_path, proc->socket->ptr);
 
1513
#ifdef SUN_LEN
 
1514
                servlen = SUN_LEN(&fcgi_addr_un);
 
1515
#else
 
1516
                /* stevens says: */
 
1517
                servlen = proc->socket->used - 1 + sizeof(fcgi_addr_un.sun_family);
 
1518
#endif
 
1519
                fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
 
1520
#else
 
1521
                return -1;
 
1522
#endif
 
1523
        } else {
 
1524
                fcgi_addr_in.sin_family = AF_INET;
 
1525
                if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
 
1526
                        log_error_write(srv, __FILE__, __LINE__, "sbs", 
 
1527
                                        "converting IP-adress failed for", host->host, 
 
1528
                                        "\nBe sure to specify an IP address here");
 
1529
                        
 
1530
                        return -1;
 
1531
                }
 
1532
                fcgi_addr_in.sin_port = htons(proc->port);
 
1533
                servlen = sizeof(fcgi_addr_in);
 
1534
                
 
1535
                fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
 
1536
        }
 
1537
        
 
1538
        if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
 
1539
                if (errno == EINPROGRESS || 
 
1540
                    errno == EALREADY ||
 
1541
                    errno == EINTR) {
 
1542
                        if (hctx->conf.debug) {
 
1543
                                log_error_write(srv, __FILE__, __LINE__, "sd", 
 
1544
                                                "connect delayed, will continue later:", fcgi_fd);
 
1545
                        }
 
1546
                        
 
1547
                        return 1;
 
1548
                } else if (errno == EAGAIN) {
 
1549
#if 0
 
1550
                        if(hctx->delayed == 0) {
 
1551
                                log_error_write(srv, __FILE__, __LINE__, "sdsdsdb", 
 
1552
                                                "need reconnect, will continue later:", fcgi_fd,
 
1553
                                                "reconnects:", hctx->reconnects,
 
1554
                                                "load:", host->load,
 
1555
                                                host->unixsocket);
 
1556
                        }
 
1557
#endif
 
1558
                        hctx->reconnects++;
 
1559
                        return -1;
 
1560
                } else {
 
1561
                        log_error_write(srv, __FILE__, __LINE__, "sdsddb", 
 
1562
                                        "connect failed:", fcgi_fd, 
 
1563
                                        strerror(errno), errno,
 
1564
                                        proc->port, proc->socket);
 
1565
 
 
1566
#if 0
 
1567
                        if (errno == EAGAIN) {
 
1568
                                log_error_write(srv, __FILE__, __LINE__, "sd", 
 
1569
                                                "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
 
1570
                                                "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
 
1571
                                                "The load for this fastcgi backend is:", proc->load);
 
1572
                        } 
 
1573
#endif
 
1574
                        
 
1575
                        return -1;
 
1576
                }
 
1577
        }
 
1578
#if 0
 
1579
        if(hctx->delayed == 1) {
 
1580
                log_error_write(srv, __FILE__, __LINE__, "sdsdsdb", 
 
1581
                                "reconnected:", fcgi_fd,
 
1582
                                "reconnects:", hctx->reconnects,
 
1583
                                "load:", host->load,
 
1584
                                host->unixsocket);
 
1585
        }
 
1586
#endif
 
1587
        hctx->reconnects = 0;
 
1588
        if (hctx->conf.debug > 1) {
 
1589
                log_error_write(srv, __FILE__, __LINE__, "sd", 
 
1590
                                "connect succeeded: ", fcgi_fd);
 
1591
        }
 
1592
 
 
1593
        return 0;
 
1594
}
 
1595
 
 
1596
static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
 
1597
        size_t i;
 
1598
        
 
1599
        for (i = 0; i < con->request.headers->used; i++) {
 
1600
                data_string *ds;
 
1601
                
 
1602
                ds = (data_string *)con->request.headers->data[i];
 
1603
                
 
1604
                if (ds->value->used && ds->key->used) {
 
1605
                        size_t j;
 
1606
                        buffer_reset(srv->tmp_buf);
 
1607
                        
 
1608
                        if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
 
1609
                                BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
 
1610
                                srv->tmp_buf->used--;
 
1611
                        }
 
1612
                        
 
1613
                        buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
 
1614
                        for (j = 0; j < ds->key->used - 1; j++) {
 
1615
                                char c = '_';
 
1616
                                if (light_isalpha(ds->key->ptr[j])) {
 
1617
                                        /* upper-case */
 
1618
                                        c = ds->key->ptr[j] & ~32;
 
1619
                                } else if (light_isdigit(ds->key->ptr[j])) {
 
1620
                                        /* copy */
 
1621
                                        c = ds->key->ptr[j];
 
1622
                                }
 
1623
                                srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
 
1624
                        }
 
1625
                        srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
 
1626
                        
 
1627
                        fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
 
1628
                }
 
1629
        }
 
1630
        
 
1631
        for (i = 0; i < con->environment->used; i++) {
 
1632
                data_string *ds;
 
1633
                
 
1634
                ds = (data_string *)con->environment->data[i];
 
1635
                
 
1636
                if (ds->value->used && ds->key->used) {
 
1637
                        size_t j;
 
1638
                        buffer_reset(srv->tmp_buf);
 
1639
                        
 
1640
                        buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
 
1641
                        for (j = 0; j < ds->key->used - 1; j++) {
 
1642
                                srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
 
1643
                                        isalpha((unsigned char)ds->key->ptr[j]) ? 
 
1644
                                        toupper((unsigned char)ds->key->ptr[j]) : '_';
 
1645
                        }
 
1646
                        srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
 
1647
                        
 
1648
                        fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
 
1649
                }
 
1650
        }
 
1651
        
 
1652
        return 0;
 
1653
}
 
1654
 
 
1655
 
 
1656
static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
 
1657
        FCGI_BeginRequestRecord beginRecord;
 
1658
        FCGI_Header header;
 
1659
        buffer *b;
 
1660
        
 
1661
        char buf[32];
 
1662
        const char *s;
 
1663
#ifdef HAVE_IPV6
 
1664
        char b2[INET6_ADDRSTRLEN + 1];
 
1665
#endif
 
1666
        
 
1667
        plugin_data *p    = hctx->plugin_data;
 
1668
        fcgi_extension_host *host= hctx->host;
 
1669
 
 
1670
        connection *con   = hctx->remote_conn;
 
1671
        server_socket *srv_sock = con->srv_socket;
 
1672
        
 
1673
        sock_addr our_addr;
 
1674
        socklen_t our_addr_len;
 
1675
        
 
1676
        /* send FCGI_BEGIN_REQUEST */
 
1677
        
 
1678
        fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
 
1679
        beginRecord.body.roleB0 = host->mode;
 
1680
        beginRecord.body.roleB1 = 0;
 
1681
        beginRecord.body.flags = 0;
 
1682
        memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
 
1683
 
 
1684
        b = chunkqueue_get_append_buffer(hctx->wb);
 
1685
        
 
1686
        buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
 
1687
        
 
1688
        /* send FCGI_PARAMS */
 
1689
        buffer_prepare_copy(p->fcgi_env, 1024);
 
1690
 
 
1691
 
 
1692
        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
 
1693
        
 
1694
        if (con->server_name->used) {
 
1695
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
 
1696
        } else {
 
1697
#ifdef HAVE_IPV6
 
1698
                s = inet_ntop(srv_sock->addr.plain.sa_family, 
 
1699
                              srv_sock->addr.plain.sa_family == AF_INET6 ? 
 
1700
                              (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
 
1701
                              (const void *) &(srv_sock->addr.ipv4.sin_addr),
 
1702
                              b2, sizeof(b2)-1);
 
1703
#else
 
1704
                s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
 
1705
#endif
 
1706
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
 
1707
        }
 
1708
        
 
1709
        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
 
1710
        
 
1711
        ltostr(buf, 
 
1712
#ifdef HAVE_IPV6
 
1713
               ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
 
1714
#else
 
1715
               ntohs(srv_sock->addr.ipv4.sin_port)
 
1716
#endif
 
1717
               );
 
1718
        
 
1719
        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
 
1720
        
 
1721
        /* get the server-side of the connection to the client */
 
1722
        our_addr_len = sizeof(our_addr);
 
1723
        
 
1724
        if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
 
1725
                s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
 
1726
        } else {
 
1727
                s = inet_ntop_cache_get_ip(srv, &(our_addr));
 
1728
        }
 
1729
        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
 
1730
        
 
1731
        ltostr(buf, 
 
1732
#ifdef HAVE_IPV6
 
1733
               ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
 
1734
#else
 
1735
               ntohs(con->dst_addr.ipv4.sin_port)
 
1736
#endif
 
1737
               );
 
1738
        
 
1739
        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
 
1740
        
 
1741
        s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
 
1742
        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
 
1743
        
 
1744
        if (!buffer_is_empty(con->authed_user)) {
 
1745
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
 
1746
                             CONST_BUF_LEN(con->authed_user));
 
1747
        }
 
1748
        
 
1749
        if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
 
1750
                /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
 
1751
                
 
1752
                /* request.content_length < SSIZE_MAX, see request.c */
 
1753
                ltostr(buf, con->request.content_length);
 
1754
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
 
1755
        }
 
1756
 
 
1757
        if (host->mode != FCGI_AUTHORIZER) {
 
1758
                /*
 
1759
                 * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
 
1760
                 * http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
 
1761
                 * (6.1.14, 6.1.6, 6.1.7)
 
1762
                 * For AUTHORIZER mode these headers should be omitted.
 
1763
                 */
 
1764
 
 
1765
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
 
1766
                
 
1767
                if (!buffer_is_empty(con->request.pathinfo)) {
 
1768
                        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
 
1769
                        
 
1770
                        /* PATH_TRANSLATED is only defined if PATH_INFO is set */
 
1771
                        
 
1772
                        if (!buffer_is_empty(host->docroot)) {
 
1773
                                buffer_copy_string_buffer(p->path, host->docroot);
 
1774
                        } else {
 
1775
                                buffer_copy_string_buffer(p->path, con->physical.doc_root);
 
1776
                        }
 
1777
                        buffer_append_string_buffer(p->path, con->request.pathinfo);
 
1778
                        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path));
 
1779
                } else {
 
1780
                        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN(""));
 
1781
                }
 
1782
        }
 
1783
 
 
1784
        /*
 
1785
         * SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual
 
1786
         * http://www.php.net/manual/en/reserved.variables.php
 
1787
         * treatment of PATH_TRANSLATED is different from the one of CGI specs.
 
1788
         * TODO: this code should be checked against cgi.fix_pathinfo php
 
1789
         * parameter.
 
1790
         */
 
1791
 
 
1792
        if (!buffer_is_empty(host->docroot)) {
 
1793
                /* 
 
1794
                 * rewrite SCRIPT_FILENAME 
 
1795
                 * 
 
1796
                 */
 
1797
                
 
1798
                buffer_copy_string_buffer(p->path, host->docroot);
 
1799
                buffer_append_string_buffer(p->path, con->uri.path);
 
1800
                
 
1801
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
 
1802
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
 
1803
        } else {
 
1804
                buffer_copy_string_buffer(p->path, con->physical.path);
 
1805
                
 
1806
                /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself 
 
1807
                 * 
 
1808
                 * see src/sapi/cgi_main.c, init_request_info()
 
1809
                 */
 
1810
                if (host->break_scriptfilename_for_php) {
 
1811
                        buffer_append_string_buffer(p->path, con->request.pathinfo);
 
1812
                }
 
1813
                
 
1814
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
 
1815
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
 
1816
        }
 
1817
 
 
1818
        if (host->strip_request_uri->used > 1) {
 
1819
                /* we need at least one char to strip off */
 
1820
                /**
 
1821
                 * /app1/index/list
 
1822
                 *
 
1823
                 * stripping /app1 or /app1/ should lead to 
 
1824
                 *
 
1825
                 * /index/list
 
1826
                 *
 
1827
                 */
 
1828
                if ('/' != host->strip_request_uri->ptr[host->strip_request_uri->used - 2]) {
 
1829
                        /* fix the user-input to have / as last char */
 
1830
                        buffer_append_string(host->strip_request_uri, "/");
 
1831
                }
 
1832
 
 
1833
                if (con->request.orig_uri->used >= host->strip_request_uri->used &&
 
1834
                    0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
 
1835
                        /* the left is the same */
 
1836
 
 
1837
                        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), 
 
1838
                                        con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
 
1839
                                        con->request.orig_uri->used - (host->strip_request_uri->used - 2));
 
1840
                } else {
 
1841
                        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
 
1842
                }
 
1843
        } else {
 
1844
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
 
1845
        }
 
1846
        if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
 
1847
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));
 
1848
        }
 
1849
        if (!buffer_is_empty(con->uri.query)) {
 
1850
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
 
1851
        } else {
 
1852
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
 
1853
        }
 
1854
        
 
1855
        s = get_http_method_name(con->request.http_method);
 
1856
        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
 
1857
        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
 
1858
        s = get_http_version_name(con->request.http_version);
 
1859
        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
 
1860
        
 
1861
#ifdef USE_OPENSSL
 
1862
        if (srv_sock->is_ssl) {
 
1863
                fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
 
1864
        }
 
1865
#endif
 
1866
        
 
1867
        
 
1868
        fcgi_env_add_request_headers(srv, con, p);
 
1869
        
 
1870
        fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
 
1871
        buffer_append_memory(b, (const char *)&header, sizeof(header));
 
1872
        buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
 
1873
        
 
1874
        fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
 
1875
        buffer_append_memory(b, (const char *)&header, sizeof(header));
 
1876
 
 
1877
        b->used++; /* add virtual \0 */
 
1878
        hctx->wb->bytes_in += b->used - 1;
 
1879
 
 
1880
        if (con->request.content_length) {
 
1881
                chunkqueue *req_cq = con->request_content_queue;
 
1882
                chunk *req_c;
 
1883
                off_t offset;
 
1884
 
 
1885
                /* something to send ? */
 
1886
                for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; ) {
 
1887
                        off_t weWant = req_cq->bytes_in - offset > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : req_cq->bytes_in - offset;
 
1888
                        off_t written = 0;
 
1889
                        off_t weHave = 0;
 
1890
 
 
1891
                        /* we announce toWrite octects
 
1892
                         * now take all the request_content chunk that we need to fill this request
 
1893
                         * */   
 
1894
 
 
1895
                        b = chunkqueue_get_append_buffer(hctx->wb);
 
1896
                        fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
 
1897
                        buffer_copy_memory(b, (const char *)&header, sizeof(header));
 
1898
                        hctx->wb->bytes_in += sizeof(header);
 
1899
 
 
1900
                        if (p->conf.debug > 10) {
 
1901
                                fprintf(stderr, "%s.%d: tosend: %lld / %lld\n", __FILE__, __LINE__, offset, req_cq->bytes_in);
 
1902
                        }
 
1903
 
 
1904
                        for (written = 0; written != weWant; ) {
 
1905
                                if (p->conf.debug > 10) {
 
1906
                                        fprintf(stderr, "%s.%d: chunk: %lld / %lld\n", __FILE__, __LINE__, written, weWant);
 
1907
                                }
 
1908
 
 
1909
                                switch (req_c->type) {
 
1910
                                case FILE_CHUNK:
 
1911
                                        weHave = req_c->file.length - req_c->offset;
 
1912
 
 
1913
                                        if (weHave > weWant - written) weHave = weWant - written;
 
1914
 
 
1915
                                        if (p->conf.debug > 10) {
 
1916
                                                fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n", 
 
1917
                                                                __FILE__, __LINE__, 
 
1918
                                                                weHave, 
 
1919
                                                                req_c->offset, 
 
1920
                                                                req_c->file.length, 
 
1921
                                                                req_c->file.name->ptr);
 
1922
                                        }
 
1923
 
 
1924
                                        assert(weHave != 0);
 
1925
                                        
 
1926
                                        chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
 
1927
 
 
1928
                                        req_c->offset += weHave;
 
1929
                                        req_cq->bytes_out += weHave;
 
1930
                                        written += weHave;
 
1931
 
 
1932
                                        hctx->wb->bytes_in += weHave;
 
1933
 
 
1934
                                        /* steal the tempfile
 
1935
                                         *
 
1936
                                         * This is tricky:
 
1937
                                         * - we reference the tempfile from the request-content-queue several times
 
1938
                                         *   if the req_c is larger than FCGI_MAX_LENGTH
 
1939
                                         * - we can't simply cleanup the request-content-queue as soon as possible
 
1940
                                         *   as it would remove the tempfiles 
 
1941
                                         * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
 
1942
                                         *   referencing chunk of the fastcgi-write-queue
 
1943
                                         *
 
1944
                                         *  */
 
1945
 
 
1946
                                        if (req_c->offset == req_c->file.length) {
 
1947
                                                chunk *c;
 
1948
 
 
1949
                                                if (p->conf.debug > 10) {
 
1950
                                                        fprintf(stderr, "%s.%d: next chunk\n", __FILE__, __LINE__);
 
1951
                                                }
 
1952
                                                c = hctx->wb->last;
 
1953
 
 
1954
                                                assert(c->type == FILE_CHUNK);
 
1955
                                                assert(req_c->file.is_temp == 1);
 
1956
 
 
1957
                                                c->file.is_temp = 1;
 
1958
                                                req_c->file.is_temp = 0;
 
1959
 
 
1960
                                                chunkqueue_remove_finished_chunks(req_cq);
 
1961
 
 
1962
                                                req_c = req_cq->first;
 
1963
                                        }
 
1964
 
 
1965
                                        break;
 
1966
                                case MEM_CHUNK:
 
1967
                                        /* append to the buffer */
 
1968
                                        weHave = req_c->mem->used - 1 - req_c->offset;
 
1969
 
 
1970
                                        if (weHave > weWant - written) weHave = weWant - written;
 
1971
 
 
1972
                                        buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave);
 
1973
 
 
1974
                                        req_c->offset += weHave;
 
1975
                                        req_cq->bytes_out += weHave;
 
1976
                                        written += weHave;
 
1977
                                        
 
1978
                                        hctx->wb->bytes_in += weHave;
 
1979
 
 
1980
                                        if (req_c->offset == req_c->mem->used - 1) {
 
1981
                                                chunkqueue_remove_finished_chunks(req_cq);
 
1982
 
 
1983
                                                req_c = req_cq->first;
 
1984
                                        }
 
1985
 
 
1986
                                        break;
 
1987
                                default:
 
1988
                                        break;
 
1989
                                }
 
1990
                        }
 
1991
                        
 
1992
                        b->used++; /* add virtual \0 */
 
1993
                        offset += weWant;
 
1994
                }
 
1995
        }
 
1996
        
 
1997
        b = chunkqueue_get_append_buffer(hctx->wb);
 
1998
        /* terminate STDIN */
 
1999
        fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
 
2000
        buffer_copy_memory(b, (const char *)&header, sizeof(header));
 
2001
        b->used++; /* add virtual \0 */
 
2002
 
 
2003
        hctx->wb->bytes_in += sizeof(header);
 
2004
 
 
2005
#if 0
 
2006
        for (i = 0; i < hctx->write_buffer->used; i++) {
 
2007
                fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
 
2008
                if ((i+1) % 16 == 0) {
 
2009
                        size_t j;
 
2010
                        for (j = i-15; j <= i; j++) {
 
2011
                                fprintf(stderr, "%c", 
 
2012
                                        isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
 
2013
                        }
 
2014
                        fprintf(stderr, "\n");
 
2015
                }
 
2016
        }
 
2017
#endif
 
2018
        
 
2019
        return 0;
 
2020
}
 
2021
 
 
2022
static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
 
2023
        char *s, *ns;
 
2024
        
 
2025
        handler_ctx *hctx = con->plugin_ctx[p->id];
 
2026
        fcgi_extension_host *host= hctx->host;
 
2027
        
 
2028
        UNUSED(srv);
 
2029
 
 
2030
        buffer_copy_string_buffer(p->parse_response, in);
 
2031
        
 
2032
        /* search for \n */
 
2033
        for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
 
2034
                char *key, *value;
 
2035
                int key_len;
 
2036
                data_string *ds;
 
2037
                
 
2038
                /* a good day. Someone has read the specs and is sending a \r\n to us */
 
2039
                
 
2040
                if (ns > p->parse_response->ptr &&
 
2041
                    *(ns-1) == '\r') {
 
2042
                        *(ns-1) = '\0';
 
2043
                }
 
2044
                
 
2045
                ns[0] = '\0';
 
2046
                
 
2047
                key = s;
 
2048
                if (NULL == (value = strchr(s, ':'))) {
 
2049
                        /* we expect: "<key>: <value>\n" */
 
2050
                        continue;
 
2051
                }
 
2052
                
 
2053
                key_len = value - key;
 
2054
                
 
2055
                value++;
 
2056
                /* strip WS */
 
2057
                while (*value == ' ' || *value == '\t') value++;
 
2058
                
 
2059
                if (host->mode != FCGI_AUTHORIZER ||
 
2060
                    !(con->http_status == 0 ||
 
2061
                      con->http_status == 200)) {
 
2062
                        /* authorizers shouldn't affect the response headers sent back to the client */
 
2063
                        
 
2064
                        /* don't forward Status: */
 
2065
                        if (0 != strncasecmp(key, "Status", key_len)) {
 
2066
                                if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
 
2067
                                        ds = data_response_init();
 
2068
                                }
 
2069
                                buffer_copy_string_len(ds->key, key, key_len);
 
2070
                                buffer_copy_string(ds->value, value);
 
2071
                                
 
2072
                                array_insert_unique(con->response.headers, (data_unset *)ds);
 
2073
                        }
 
2074
                }
 
2075
                
 
2076
                switch(key_len) {
 
2077
                case 4:
 
2078
                        if (0 == strncasecmp(key, "Date", key_len)) {
 
2079
                                con->parsed_response |= HTTP_DATE;
 
2080
                        }
 
2081
                        break;
 
2082
                case 6:
 
2083
                        if (0 == strncasecmp(key, "Status", key_len)) {
 
2084
                                con->http_status = strtol(value, NULL, 10);
 
2085
                                con->parsed_response |= HTTP_STATUS;
 
2086
                        }
 
2087
                        break;
 
2088
                case 8:
 
2089
                        if (0 == strncasecmp(key, "Location", key_len)) {
 
2090
                                con->parsed_response |= HTTP_LOCATION;
 
2091
                        }
 
2092
                        break;
 
2093
                case 10:
 
2094
                        if (0 == strncasecmp(key, "Connection", key_len)) {
 
2095
                                con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
 
2096
                                con->parsed_response |= HTTP_CONNECTION;
 
2097
                        }
 
2098
                        break;
 
2099
                case 14:
 
2100
                        if (0 == strncasecmp(key, "Content-Length", key_len)) {
 
2101
                                con->response.content_length = strtol(value, NULL, 10);
 
2102
                                con->parsed_response |= HTTP_CONTENT_LENGTH;
 
2103
                                
 
2104
                                if (con->response.content_length < 0) con->response.content_length = 0;
 
2105
                        }
 
2106
                        break;
 
2107
                default:
 
2108
                        break;
 
2109
                }
 
2110
        }
 
2111
        
 
2112
        /* CGI/1.1 rev 03 - 7.2.1.2 */
 
2113
        if ((con->parsed_response & HTTP_LOCATION) &&
 
2114
            !(con->parsed_response & HTTP_STATUS)) {
 
2115
                con->http_status = 302;
 
2116
        }
 
2117
        
 
2118
        return 0;
 
2119
}
 
2120
 
 
2121
typedef struct {
 
2122
        buffer  *b; 
 
2123
        size_t   len;
 
2124
        int      type;
 
2125
        int      padding;
 
2126
        size_t   request_id;
 
2127
} fastcgi_response_packet;
 
2128
 
 
2129
static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_packet *packet) {
 
2130
        chunk * c;
 
2131
        size_t offset = 0;
 
2132
        size_t toread = 0;
 
2133
        FCGI_Header *header;
 
2134
 
 
2135
        if (!hctx->rb->first) return -1;
 
2136
 
 
2137
        packet->b = buffer_init();
 
2138
        packet->len = 0;
 
2139
        packet->type = 0;
 
2140
        packet->padding = 0;
 
2141
        packet->request_id = 0;
 
2142
 
 
2143
        /* get at least the FastCGI header */
 
2144
        for (c = hctx->rb->first; c; c = c->next) {
 
2145
                if (packet->b->used == 0) {
 
2146
                        buffer_copy_string_len(packet->b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
 
2147
                } else {
 
2148
                        buffer_append_string_len(packet->b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
 
2149
                }
 
2150
 
 
2151
                if (packet->b->used >= sizeof(*header) + 1) break;
 
2152
        }
 
2153
 
 
2154
        if ((packet->b->used == 0) ||
 
2155
            (packet->b->used - 1 < sizeof(FCGI_Header))) {
 
2156
                /* no header */
 
2157
                buffer_free(packet->b);
 
2158
 
 
2159
                log_error_write(srv, __FILE__, __LINE__, "s", "FastCGI: header to small");
 
2160
                return -1;
 
2161
        }
 
2162
 
 
2163
        /* we have at least a header, now check how much me have to fetch */ 
 
2164
        header = (FCGI_Header *)(packet->b->ptr);
 
2165
                        
 
2166
        packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
 
2167
        packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
 
2168
        packet->type = header->type;
 
2169
        packet->padding = header->paddingLength;
 
2170
 
 
2171
        /* the first bytes in packet->b are the header */
 
2172
        offset = sizeof(*header);
 
2173
 
 
2174
        /* ->b should only be the content */
 
2175
        buffer_copy_string(packet->b, ""); /* used == 1 */
 
2176
 
 
2177
        if (packet->len) {
 
2178
                /* copy the content */
 
2179
                for (; c && (packet->b->used < packet->len + 1); c = c->next) {
 
2180
                        size_t weWant = packet->len - (packet->b->used - 1);
 
2181
                        size_t weHave = c->mem->used - c->offset - offset - 1;
 
2182
 
 
2183
                        if (weHave > weWant) weHave = weWant;
 
2184
                                                
 
2185
                        buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
 
2186
 
 
2187
                        /* we only skipped the first 8 bytes as they are the fcgi header */
 
2188
                        offset = 0;
 
2189
                }
 
2190
 
 
2191
                if (packet->b->used < packet->len + 1) {
 
2192
                        /* we didn't got the full packet */
 
2193
 
 
2194
                        buffer_free(packet->b);
 
2195
                        return -1;
 
2196
                }
 
2197
 
 
2198
                packet->b->used -= packet->padding;
 
2199
                packet->b->ptr[packet->b->used - 1] = '\0';
 
2200
        }
 
2201
 
 
2202
        /* tag the chunks as read */
 
2203
        toread = packet->len + sizeof(FCGI_Header);
 
2204
        for (c = hctx->rb->first; c && toread; c = c->next) {
 
2205
                if (c->mem->used - c->offset - 1 <= toread) {
 
2206
                        /* we read this whole buffer, move it to unused */
 
2207
                        toread -= c->mem->used - c->offset - 1;
 
2208
                        c->offset = c->mem->used - 1; /* everthing has been written */
 
2209
                } else {
 
2210
                        c->offset += toread;
 
2211
                        toread = 0;
 
2212
                }
 
2213
        }
 
2214
 
 
2215
        chunkqueue_remove_finished_chunks(hctx->rb);
 
2216
        
 
2217
        return 0;
 
2218
}
 
2219
 
 
2220
static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
 
2221
        int fin = 0;
 
2222
        int toread;
 
2223
        ssize_t r;
 
2224
        
 
2225
        plugin_data *p    = hctx->plugin_data;
 
2226
        connection *con   = hctx->remote_conn;
 
2227
        int fcgi_fd       = hctx->fd;
 
2228
        fcgi_extension_host *host= hctx->host;
 
2229
        fcgi_proc *proc   = hctx->proc;
 
2230
        
 
2231
        /* 
 
2232
         * check how much we have to read 
 
2233
         */
 
2234
        if (ioctl(hctx->fd, FIONREAD, &toread)) {
 
2235
                log_error_write(srv, __FILE__, __LINE__, "sd", 
 
2236
                                "unexpected end-of-file (perhaps the fastcgi process died):",
 
2237
                                fcgi_fd);
 
2238
                return -1;
 
2239
        }
 
2240
        
 
2241
        /* init read-buffer */
 
2242
        
 
2243
        if (toread > 0) {
 
2244
                buffer *b;
 
2245
 
 
2246
                b = chunkqueue_get_append_buffer(hctx->rb);
 
2247
                buffer_prepare_copy(b, toread + 1);
 
2248
 
 
2249
                /* append to read-buffer */
 
2250
                if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
 
2251
                        log_error_write(srv, __FILE__, __LINE__, "sds", 
 
2252
                                        "unexpected end-of-file (perhaps the fastcgi process died):",
 
2253
                                        fcgi_fd, strerror(errno));
 
2254
                        return -1;
 
2255
                }
 
2256
                
 
2257
                /* this should be catched by the b > 0 above */
 
2258
                assert(r);
 
2259
 
 
2260
                b->used = r + 1; /* one extra for the fake \0 */
 
2261
                b->ptr[b->used - 1] = '\0';
 
2262
        } else {
 
2263
                log_error_write(srv, __FILE__, __LINE__, "ssdsdsd", 
 
2264
                                "unexpected end-of-file (perhaps the fastcgi process died):",
 
2265
                                "pid:", proc->pid,
 
2266
                                "fcgi-fd:", fcgi_fd, 
 
2267
                                "remote-fd:", con->fd);
 
2268
                
 
2269
                return -1;
 
2270
        }
 
2271
 
 
2272
        /*
 
2273
         * parse the fastcgi packets and forward the content to the write-queue
 
2274
         *
 
2275
         */     
 
2276
        while (fin == 0) {
 
2277
                fastcgi_response_packet packet;
 
2278
 
 
2279
                /* check if we have at least one packet */
 
2280
                if (0 != fastcgi_get_packet(srv, hctx, &packet)) {
 
2281
                        /* no full packet */
 
2282
 
 
2283
                        hctx->delayed = 1;
 
2284
 
 
2285
                        break;
 
2286
                }
 
2287
 
 
2288
                switch(packet.type) {
 
2289
                case FCGI_STDOUT:
 
2290
                        if (packet.len == 0) break;
 
2291
 
 
2292
                        /* is the header already finished */
 
2293
                        if (0 == con->file_started) {
 
2294
                                char *c;
 
2295
                                size_t blen;
 
2296
                                data_string *ds;
 
2297
                                        
 
2298
                                /* search for header terminator 
 
2299
                                 * 
 
2300
                                 * if we start with \r\n check if last packet terminated with \r\n
 
2301
                                 * if we start with \n check if last packet terminated with \n
 
2302
                                 * search for \r\n\r\n
 
2303
                                 * search for \n\n
 
2304
                                 */
 
2305
 
 
2306
                                if (hctx->response_header->used == 0) {
 
2307
                                        buffer_copy_string_buffer(hctx->response_header, packet.b);
 
2308
                                } else {
 
2309
                                        buffer_append_string_buffer(hctx->response_header, packet.b);
 
2310
                                }
 
2311
 
 
2312
                                if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
 
2313
                                        blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
 
2314
                                        hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
 
2315
                                        c += 4; /* point the the start of the response */
 
2316
                                } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
 
2317
                                        blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
 
2318
                                        hctx->response_header->used = c - hctx->response_header->ptr + 2;
 
2319
                                        c += 2; /* point the the start of the response */
 
2320
                                } else {
 
2321
                                        /* no luck, no header found */
 
2322
                                        break;
 
2323
                                }
 
2324
 
 
2325
                                /* parse the response header */
 
2326
                                fcgi_response_parse(srv, con, p, hctx->response_header);
 
2327
 
 
2328
                                con->file_started = 1;
 
2329
 
 
2330
                                if (host->mode == FCGI_AUTHORIZER &&
 
2331
                                    (con->http_status == 0 ||
 
2332
                                     con->http_status == 200)) {
 
2333
                                        /* a authorizer with approved the static request, ignore the content here */
 
2334
                                        hctx->send_content_body = 0;
 
2335
                                }
 
2336
 
 
2337
                                if (host->allow_xsendfile &&
 
2338
                                    NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
 
2339
                                        stat_cache_entry *sce;
 
2340
 
 
2341
                                        if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
 
2342
                                                /* found */
 
2343
 
 
2344
                                                http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
 
2345
                                                hctx->send_content_body = 0; /* ignore the content */
 
2346
                                                joblist_append(srv, con);
 
2347
                                        }
 
2348
                                }
 
2349
 
 
2350
                                                
 
2351
                                if (hctx->send_content_body && blen > 1) {                                              
 
2352
                                        /* enable chunked-transfer-encoding */
 
2353
                                        if (con->request.http_version == HTTP_VERSION_1_1 &&
 
2354
                                            !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
 
2355
                                                con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
 
2356
                                        }
 
2357
 
 
2358
                                        http_chunk_append_mem(srv, con, c, blen);
 
2359
                                        joblist_append(srv, con);
 
2360
                                }
 
2361
                        } else if (hctx->send_content_body && packet.b->used > 1) {
 
2362
                                if (con->request.http_version == HTTP_VERSION_1_1 &&
 
2363
                                    !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
 
2364
                                        /* enable chunked-transfer-encoding */
 
2365
                                        con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
 
2366
                                }
 
2367
 
 
2368
                                http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
 
2369
                                joblist_append(srv, con);
 
2370
                        }
 
2371
                        break;
 
2372
                case FCGI_STDERR:
 
2373
                        log_error_write(srv, __FILE__, __LINE__, "sb", 
 
2374
                                        "FastCGI-stderr:", packet.b);
 
2375
                        
 
2376
                        break;
 
2377
                case FCGI_END_REQUEST:
 
2378
                        con->file_finished = 1;
 
2379
                        
 
2380
                        if (host->mode != FCGI_AUTHORIZER ||
 
2381
                            !(con->http_status == 0 ||
 
2382
                              con->http_status == 200)) {
 
2383
                                /* send chunk-end if nesseary */
 
2384
                                http_chunk_append_mem(srv, con, NULL, 0);
 
2385
                                joblist_append(srv, con);
 
2386
                        }
 
2387
                        
 
2388
                        fin = 1;
 
2389
                        break;
 
2390
                default:
 
2391
                        log_error_write(srv, __FILE__, __LINE__, "sd", 
 
2392
                                        "FastCGI: header.type not handled: ", packet.type);
 
2393
                        break;
 
2394
                }
 
2395
                buffer_free(packet.b);
 
2396
        }
 
2397
        
 
2398
        return fin;
 
2399
}
 
2400
 
 
2401
int fcgi_proclist_sort_up(server *srv, fcgi_extension_host *host, fcgi_proc *proc) {
 
2402
        fcgi_proc *p;
 
2403
        
 
2404
        UNUSED(srv);
 
2405
        
 
2406
        /* we have been the smallest of the current list 
 
2407
         * and we want to insert the node sorted as soon 
 
2408
         * possible
 
2409
         *
 
2410
         * 1 0 0 0 1 1 1 
 
2411
         * |      ^ 
 
2412
         * |      |
 
2413
         * +------+
 
2414
         * 
 
2415
         */
 
2416
 
 
2417
        /* nothing to sort, only one element */
 
2418
        if (host->first == proc && proc->next == NULL) return 0;
 
2419
 
 
2420
        for (p = proc; p->next && p->next->load < proc->load; p = p->next);
 
2421
 
 
2422
        /* no need to move something 
 
2423
         *
 
2424
         * 1 2 2 2 3 3 3 
 
2425
         * ^
 
2426
         * |
 
2427
         * +
 
2428
         *
 
2429
         */
 
2430
        if (p == proc) return 0;
 
2431
 
 
2432
        if (host->first == proc) {
 
2433
                /* we have been the first elememt */
 
2434
 
 
2435
                host->first = proc->next;
 
2436
                host->first->prev = NULL;
 
2437
        }
 
2438
 
 
2439
        /* disconnect proc */
 
2440
 
 
2441
        if (proc->prev) proc->prev->next = proc->next;
 
2442
        if (proc->next) proc->next->prev = proc->prev;
 
2443
        
 
2444
        /* proc should be right of p */
 
2445
        
 
2446
        proc->next = p->next;
 
2447
        proc->prev = p;
 
2448
        if (p->next) p->next->prev = proc;
 
2449
        p->next = proc;
 
2450
#if 0
 
2451
        for(p = host->first; p; p = p->next) {
 
2452
                log_error_write(srv, __FILE__, __LINE__, "dd", 
 
2453
                                p->pid, p->load);
 
2454
        }
 
2455
#else
 
2456
        UNUSED(srv);
 
2457
#endif
 
2458
 
 
2459
        return 0;
 
2460
}
 
2461
 
 
2462
int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc) {
 
2463
        fcgi_proc *p;
 
2464
        
 
2465
        UNUSED(srv);
 
2466
        
 
2467
        /* we have been the smallest of the current list 
 
2468
         * and we want to insert the node sorted as soon 
 
2469
         * possible
 
2470
         *
 
2471
         *  0 0 0 0 1 0 1 
 
2472
         * ^          |
 
2473
         * |          |
 
2474
         * +----------+
 
2475
         *
 
2476
         *
 
2477
         * the basic is idea is:
 
2478
         * - the last active fastcgi process should be still 
 
2479
         *   in ram and is not swapped out yet
 
2480
         * - processes that are not reused will be killed
 
2481
         *   after some time by the trigger-handler
 
2482
         * - remember it as:
 
2483
         *   everything > 0 is hot
 
2484
         *   all unused procs are colder the more right they are
 
2485
         *   ice-cold processes are propably unused since more
 
2486
         *   than 'unused-timeout', are swaped out and won't be
 
2487
         *   reused in the next seconds anyway.
 
2488
         * 
 
2489
         */
 
2490
 
 
2491
        /* nothing to sort, only one element */
 
2492
        if (host->first == proc && proc->next == NULL) return 0;
 
2493
 
 
2494
        for (p = host->first; p != proc && p->load < proc->load; p = p->next);
 
2495
 
 
2496
 
 
2497
        /* no need to move something 
 
2498
         *
 
2499
         * 1 2 2 2 3 3 3 
 
2500
         * ^
 
2501
         * |
 
2502
         * +
 
2503
         *
 
2504
         */
 
2505
        if (p == proc) return 0;
 
2506
        
 
2507
        /* we have to move left. If we are already the first element
 
2508
         * we are done */
 
2509
        if (host->first == proc) return 0;
 
2510
 
 
2511
        /* release proc */
 
2512
        if (proc->prev) proc->prev->next = proc->next;
 
2513
        if (proc->next) proc->next->prev = proc->prev;
 
2514
 
 
2515
        /* proc should be left of p */
 
2516
        proc->next = p;
 
2517
        proc->prev = p->prev;
 
2518
        if (p->prev) p->prev->next = proc;
 
2519
        p->prev = proc;
 
2520
 
 
2521
        if (proc->prev == NULL) host->first = proc;
 
2522
#if 0   
 
2523
        for(p = host->first; p; p = p->next) {
 
2524
                log_error_write(srv, __FILE__, __LINE__, "dd", 
 
2525
                                p->pid, p->load);
 
2526
        }
 
2527
#else
 
2528
        UNUSED(srv);
 
2529
#endif
 
2530
 
 
2531
        return 0;
 
2532
}
 
2533
 
 
2534
static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
 
2535
        fcgi_proc *proc;
 
2536
        
 
2537
        for (proc = host->first; proc; proc = proc->next) {
 
2538
                if (p->conf.debug) {
 
2539
                        log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd", 
 
2540
                                        "proc:", 
 
2541
                                        host->host, proc->port, 
 
2542
                                        proc->socket,
 
2543
                                        proc->state,
 
2544
                                        proc->is_local,
 
2545
                                        proc->load,
 
2546
                                        proc->pid);
 
2547
                }
 
2548
                
 
2549
                if (0 == proc->is_local) {
 
2550
                        /* 
 
2551
                         * external servers might get disabled 
 
2552
                         * 
 
2553
                         * enable the server again, perhaps it is back again 
 
2554
                         */
 
2555
                        
 
2556
                        if ((proc->state == PROC_STATE_DISABLED) &&
 
2557
                            (srv->cur_ts - proc->disable_ts > host->disable_time)) {
 
2558
                                proc->state = PROC_STATE_RUNNING;
 
2559
                                host->active_procs++;
 
2560
                                
 
2561
                                log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
 
2562
                                                "fcgi-server re-enabled:", 
 
2563
                                                host->host, host->port, 
 
2564
                                                host->unixsocket);
 
2565
                        }
 
2566
                } else {
 
2567
                        /* the child should not terminate at all */
 
2568
                        int status;
 
2569
                        
 
2570
                        if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
 
2571
                                switch(waitpid(proc->pid, &status, WNOHANG)) {
 
2572
                                case 0:
 
2573
                                        /* child is still alive */
 
2574
                                        break;
 
2575
                                case -1:
 
2576
                                        break;
 
2577
                                default:
 
2578
                                        if (WIFEXITED(status)) {
 
2579
#if 0
 
2580
                                                log_error_write(srv, __FILE__, __LINE__, "sdsd", 
 
2581
                                                                "child exited, pid:", proc->pid,
 
2582
                                                                "status:", WEXITSTATUS(status));
 
2583
#endif
 
2584
                                        } else if (WIFSIGNALED(status)) {
 
2585
                                                log_error_write(srv, __FILE__, __LINE__, "sd", 
 
2586
                                                                "child signaled:", 
 
2587
                                                                WTERMSIG(status));
 
2588
                                        } else {
 
2589
                                                log_error_write(srv, __FILE__, __LINE__, "sd", 
 
2590
                                                                "child died somehow:", 
 
2591
                                                                status);
 
2592
                                        }
 
2593
                                        
 
2594
                                        proc->state = PROC_STATE_DIED;
 
2595
                                        break;
 
2596
                                }
 
2597
                        }
 
2598
                        
 
2599
                        /* 
 
2600
                         * local servers might died, but we restart them
 
2601
                         * 
 
2602
                         */
 
2603
                        if (proc->state == PROC_STATE_DIED &&
 
2604
                            proc->load == 0) {
 
2605
                                /* restart the child */
 
2606
                                
 
2607
                                if (p->conf.debug) {
 
2608
                                        log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
 
2609
                                                        "--- fastcgi spawning",
 
2610
                                                        "\n\tport:", host->port,
 
2611
                                                        "\n\tsocket", host->unixsocket,
 
2612
                                                        "\n\tcurrent:", 1, "/", host->min_procs);
 
2613
                                }
 
2614
                                
 
2615
                                if (fcgi_spawn_connection(srv, p, host, proc)) {
 
2616
                                        log_error_write(srv, __FILE__, __LINE__, "s",
 
2617
                                                        "ERROR: spawning fcgi failed.");
 
2618
                                        return HANDLER_ERROR;
 
2619
                                }
 
2620
                                
 
2621
                                fcgi_proclist_sort_down(srv, host, proc);
 
2622
                        }
 
2623
                }
 
2624
        }
 
2625
        
 
2626
        return 0;
 
2627
}
 
2628
 
 
2629
 
 
2630
static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
 
2631
        plugin_data *p    = hctx->plugin_data;
 
2632
        fcgi_extension_host *host= hctx->host;
 
2633
        connection *con   = hctx->remote_conn;
 
2634
        
 
2635
        int ret;
 
2636
 
 
2637
        /* sanity check */      
 
2638
        if (!host ||
 
2639
            ((!host->host->used || !host->port) && !host->unixsocket->used)) {
 
2640
                log_error_write(srv, __FILE__, __LINE__, "sxddd", 
 
2641
                                "write-req: error",
 
2642
                                host,
 
2643
                                host->host->used,
 
2644
                                host->port,
 
2645
                                host->unixsocket->used);
 
2646
                return HANDLER_ERROR;
 
2647
        }
 
2648
        
 
2649
 
 
2650
        switch(hctx->state) {
 
2651
        case FCGI_STATE_INIT:
 
2652
                ret = host->unixsocket->used ? AF_UNIX : AF_INET;
 
2653
                
 
2654
                if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
 
2655
                        if (errno == EMFILE ||
 
2656
                            errno == EINTR) {
 
2657
                                log_error_write(srv, __FILE__, __LINE__, "sd", 
 
2658
                                                "wait for fd at connection:", con->fd);
 
2659
                                
 
2660
                                return HANDLER_WAIT_FOR_FD;
 
2661
                        }
 
2662
                        
 
2663
                        log_error_write(srv, __FILE__, __LINE__, "ssdd", 
 
2664
                                        "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
 
2665
                        return HANDLER_ERROR;
 
2666
                }
 
2667
                hctx->fde_ndx = -1;
 
2668
                
 
2669
                srv->cur_fds++;
 
2670
                
 
2671
                fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
 
2672
                
 
2673
                if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
 
2674
                        log_error_write(srv, __FILE__, __LINE__, "ss", 
 
2675
                                        "fcntl failed: ", strerror(errno));
 
2676
                        
 
2677
                        return HANDLER_ERROR;
 
2678
                }
 
2679
                
 
2680
                /* fall through */
 
2681
        case FCGI_STATE_CONNECT:
 
2682
                if (hctx->state == FCGI_STATE_INIT || hctx->delayed == 1) {
 
2683
                        for (hctx->proc = hctx->host->first; 
 
2684
                             hctx->proc && hctx->proc->state != PROC_STATE_RUNNING; 
 
2685
                             hctx->proc = hctx->proc->next);
 
2686
                        
 
2687
                        /* all childs are dead */
 
2688
                        if (hctx->proc == NULL) {
 
2689
                                hctx->fde_ndx = -1;
 
2690
                                
 
2691
                                return HANDLER_ERROR;
 
2692
                        }
 
2693
                        
 
2694
                        if (hctx->proc->is_local) {
 
2695
                                hctx->pid = hctx->proc->pid;
 
2696
                        }
 
2697
                        
 
2698
                        switch (fcgi_establish_connection(srv, hctx)) {
 
2699
                        case 1:
 
2700
                                fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
 
2701
                                
 
2702
                                /* connection is in progress, wait for an event and call getsockopt() below */
 
2703
                                
 
2704
                                fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
 
2705
                                
 
2706
                                hctx->delayed = 0;
 
2707
                                return HANDLER_WAIT_FOR_EVENT;
 
2708
                        case -1:
 
2709
                                /* if ECONNREFUSED/EAGAIN re-try connect() */
 
2710
                                
 
2711
                                fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
 
2712
                                hctx->delayed = 1;
 
2713
                                return HANDLER_WAIT_FOR_EVENT;
 
2714
                        default:
 
2715
                                /* everything is ok, go on */
 
2716
                                break;
 
2717
                        }
 
2718
 
 
2719
                } else {
 
2720
                        int socket_error;
 
2721
                        socklen_t socket_error_len = sizeof(socket_error);
 
2722
                        
 
2723
                        /* try to finish the connect() */
 
2724
                        if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
 
2725
                                log_error_write(srv, __FILE__, __LINE__, "ss", 
 
2726
                                                "getsockopt failed:", strerror(errno));
 
2727
                                
 
2728
                                return HANDLER_ERROR;
 
2729
                        }
 
2730
                        if (socket_error != 0) {
 
2731
                                if (!hctx->proc->is_local || p->conf.debug) {
 
2732
                                        /* local procs get restarted */
 
2733
                                        
 
2734
                                        log_error_write(srv, __FILE__, __LINE__, "ss",
 
2735
                                                        "establishing connection failed:", strerror(socket_error), 
 
2736
                                                        "port:", hctx->proc->port);
 
2737
                                }
 
2738
                                
 
2739
                                return HANDLER_ERROR;
 
2740
                        }
 
2741
                }
 
2742
                
 
2743
                /* ok, we have the connection */
 
2744
                
 
2745
                hctx->proc->load++;
 
2746
                hctx->proc->last_used = srv->cur_ts;
 
2747
                hctx->got_proc = 1;
 
2748
                
 
2749
                if (p->conf.debug) {
 
2750
                        log_error_write(srv, __FILE__, __LINE__, "sddbdd",
 
2751
                                        "got proc:", 
 
2752
                                        hctx->fd,
 
2753
                                        hctx->proc->pid, 
 
2754
                                        hctx->proc->socket, 
 
2755
                                        hctx->proc->port,
 
2756
                                        hctx->proc->load);
 
2757
                }
 
2758
 
 
2759
                /* move the proc-list entry down the list */
 
2760
                fcgi_proclist_sort_up(srv, hctx->host, hctx->proc);
 
2761
                
 
2762
                if (hctx->request_id == 0) {
 
2763
                        hctx->request_id = fcgi_requestid_new(srv, p);
 
2764
                } else {
 
2765
                        log_error_write(srv, __FILE__, __LINE__, "sd", 
 
2766
                                        "fcgi-request is already in use:", hctx->request_id);
 
2767
                }
 
2768
                
 
2769
                fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
 
2770
                /* fall through */
 
2771
        case FCGI_STATE_PREPARE_WRITE:
 
2772
                fcgi_create_env(srv, hctx, hctx->request_id);
 
2773
                
 
2774
                fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
 
2775
                
 
2776
                /* fall through */
 
2777
        case FCGI_STATE_WRITE:
 
2778
                ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
 
2779
 
 
2780
                chunkqueue_remove_finished_chunks(hctx->wb);
 
2781
                
 
2782
                if (ret < 0) {
 
2783
                        switch(errno) {
 
2784
                        case ENOTCONN:
 
2785
                                /* the connection got dropped after accept() 
 
2786
                                 * 
 
2787
                                 * this is most of the time a PHP which dies 
 
2788
                                 * after PHP_FCGI_MAX_REQUESTS
 
2789
                                 * 
 
2790
                                 */ 
 
2791
                                if (hctx->wb->bytes_out == 0 &&
 
2792
                                    hctx->reconnects < 5) {
 
2793
                                        usleep(10000); /* take away the load of the webserver 
 
2794
                                                        * to let the php a chance to restart 
 
2795
                                                        */
 
2796
                                        
 
2797
                                        fcgi_reconnect(srv, hctx);
 
2798
                                
 
2799
                                        return HANDLER_WAIT_FOR_FD;
 
2800
                                }
 
2801
                                
 
2802
                                /* not reconnected ... why
 
2803
                                 * 
 
2804
                                 * far@#lighttpd report this for FreeBSD
 
2805
                                 * 
 
2806
                                 */
 
2807
                                
 
2808
                                log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
 
2809
                                                "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
 
2810
                                                "write-offset:", hctx->wb->bytes_out,
 
2811
                                                "reconnect attempts:", hctx->reconnects);
 
2812
                                
 
2813
                                return HANDLER_ERROR;
 
2814
                        case EAGAIN:
 
2815
                        case EINTR:
 
2816
                                fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
 
2817
                                
 
2818
                                return HANDLER_WAIT_FOR_EVENT;
 
2819
                        default:
 
2820
                                log_error_write(srv, __FILE__, __LINE__, "ssd", 
 
2821
                                                "write failed:", strerror(errno), errno);
 
2822
                                
 
2823
                                return HANDLER_ERROR;
 
2824
                        }
 
2825
                }
 
2826
 
 
2827
                if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
 
2828
                        /* we don't need the out event anymore */
 
2829
                        fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
 
2830
                        fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
 
2831
                        fcgi_set_state(srv, hctx, FCGI_STATE_READ);
 
2832
                } else {
 
2833
                        fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
 
2834
                                
 
2835
                        return HANDLER_WAIT_FOR_EVENT;
 
2836
                }
 
2837
 
 
2838
                break;
 
2839
        case FCGI_STATE_READ:
 
2840
                /* waiting for a response */
 
2841
                break;
 
2842
        default:
 
2843
                log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
 
2844
                return HANDLER_ERROR;
 
2845
        }
 
2846
        
 
2847
        return HANDLER_WAIT_FOR_EVENT;
 
2848
}
 
2849
 
 
2850
SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
 
2851
        plugin_data *p = p_d;
 
2852
        
 
2853
        handler_ctx *hctx = con->plugin_ctx[p->id];
 
2854
        fcgi_proc *proc;
 
2855
        fcgi_extension_host *host;
 
2856
        
 
2857
        if (NULL == hctx) return HANDLER_GO_ON;
 
2858
        
 
2859
        /* not my job */
 
2860
        if (con->mode != p->id) return HANDLER_GO_ON;
 
2861
        
 
2862
        /* ok, create the request */
 
2863
        switch(fcgi_write_request(srv, hctx)) {
 
2864
        case HANDLER_ERROR:
 
2865
                proc = hctx->proc;
 
2866
                host = hctx->host;
 
2867
                
 
2868
#if 0
 
2869
                if (proc && 
 
2870
                    0 == proc->is_local &&
 
2871
                    proc->state != PROC_STATE_DISABLED) {
 
2872
                        /* only disable remote servers as we don't manage them*/
 
2873
                        
 
2874
                        log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:", 
 
2875
                                        host->host,
 
2876
                                        proc->port,
 
2877
                                        proc->socket);
 
2878
                        
 
2879
                        /* disable this server */
 
2880
                        proc->disable_ts = srv->cur_ts;
 
2881
                        proc->state = PROC_STATE_DISABLED;
 
2882
                        host->active_procs--;
 
2883
                }
 
2884
#endif
 
2885
                
 
2886
                if (hctx->state == FCGI_STATE_INIT ||
 
2887
                    hctx->state == FCGI_STATE_CONNECT) {
 
2888
                        /* connect() or getsockopt() failed, 
 
2889
                         * restart the request-handling 
 
2890
                         */
 
2891
                        if (proc && proc->is_local) {
 
2892
 
 
2893
                                if (p->conf.debug) {
 
2894
                                        log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to fastcgi failed, restarting the request-handling:", 
 
2895
                                                        host->host,
 
2896
                                                        proc->port,
 
2897
                                                        proc->socket);
 
2898
                                }
 
2899
 
 
2900
                                /* 
 
2901
                                 * several hctx might reference the same proc
 
2902
                                 * 
 
2903
                                 * Only one of them should mark the proc as dead all the other
 
2904
                                 * ones should just take a new one.
 
2905
                                 * 
 
2906
                                 * If a new proc was started with the old struct this might lead
 
2907
                                 * the mark a perfect proc as dead otherwise
 
2908
                                 * 
 
2909
                                 */
 
2910
                                if (proc->state == PROC_STATE_RUNNING &&
 
2911
                                    hctx->pid == proc->pid) {
 
2912
                                        proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
 
2913
                                }
 
2914
                        }
 
2915
                        fcgi_restart_dead_procs(srv, p, host);
 
2916
                        
 
2917
                        fcgi_connection_close(srv, hctx);
 
2918
                        
 
2919
                        buffer_reset(con->physical.path);
 
2920
                        con->mode = DIRECT;
 
2921
                        joblist_append(srv, con); /* really ? */
 
2922
 
 
2923
                        /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
 
2924
                         * and hope that the childs will be restarted 
 
2925
                         * 
 
2926
                         */
 
2927
                        
 
2928
                        /* we might get into a LOOP here
 
2929
                         * 
 
2930
                         * but how to handle this ?
 
2931
                         * 
 
2932
                         * if we enter a endless loop, we will burn the CPU
 
2933
                         * 
 
2934
                         * let this handle by the loop-detection
 
2935
                         */
 
2936
                        
 
2937
                        return HANDLER_WAIT_FOR_FD;
 
2938
                } else {
 
2939
                        fcgi_connection_close(srv, hctx);
 
2940
                        
 
2941
                        buffer_reset(con->physical.path);
 
2942
                        con->mode = DIRECT;
 
2943
                        con->http_status = 503;
 
2944
                        joblist_append(srv, con); /* really ? */
 
2945
                        
 
2946
                        return HANDLER_FINISHED;
 
2947
                }
 
2948
        case HANDLER_WAIT_FOR_EVENT:
 
2949
                if (con->file_started == 1) {
 
2950
                        return HANDLER_FINISHED;
 
2951
                } else {
 
2952
                        return HANDLER_WAIT_FOR_EVENT;
 
2953
                }
 
2954
        case HANDLER_WAIT_FOR_FD:
 
2955
                return HANDLER_WAIT_FOR_FD;
 
2956
        default:
 
2957
                log_error_write(srv, __FILE__, __LINE__, "s", "subrequest write-req default");
 
2958
                return HANDLER_ERROR;
 
2959
        }
 
2960
}
 
2961
 
 
2962
static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
 
2963
        server      *srv  = (server *)s;
 
2964
        handler_ctx *hctx = ctx;
 
2965
        connection  *con  = hctx->remote_conn;
 
2966
        plugin_data *p    = hctx->plugin_data;
 
2967
        
 
2968
        fcgi_proc *proc   = hctx->proc;
 
2969
        fcgi_extension_host *host= hctx->host;
 
2970
 
 
2971
        if ((revents & FDEVENT_IN) &&
 
2972
            hctx->state == FCGI_STATE_READ) {
 
2973
                switch (fcgi_demux_response(srv, hctx)) {
 
2974
                case 0:
 
2975
                        break;
 
2976
                case 1:
 
2977
                        
 
2978
                        if (host->mode == FCGI_AUTHORIZER && 
 
2979
                            (con->http_status == 200 ||
 
2980
                             con->http_status == 0)) {
 
2981
                                /*
 
2982
                                 * If we are here in AUTHORIZER mode then a request for autorizer
 
2983
                                 * was proceeded already, and status 200 has been returned. We need
 
2984
                                 * now to handle autorized request.
 
2985
                                 */
 
2986
 
 
2987
                                buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
 
2988
                                
 
2989
                                buffer_copy_string_buffer(con->physical.path, host->docroot);
 
2990
                                buffer_append_string_buffer(con->physical.path, con->uri.path);
 
2991
                                fcgi_connection_close(srv, hctx);
 
2992
                                
 
2993
                                con->mode = DIRECT;
 
2994
                                con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
 
2995
                        } else {
 
2996
                                /* we are done */
 
2997
                                fcgi_connection_close(srv, hctx);
 
2998
                        }
 
2999
                        
 
3000
                        joblist_append(srv, con);
 
3001
                        return HANDLER_FINISHED;
 
3002
                case -1:
 
3003
                        if (proc->pid && proc->state != PROC_STATE_DIED) {
 
3004
                                int status;
 
3005
                                
 
3006
                                /* only fetch the zombie if it is not already done */
 
3007
                                
 
3008
                                switch(waitpid(proc->pid, &status, WNOHANG)) {
 
3009
                                case 0:
 
3010
                                        /* child is still alive */
 
3011
                                        break;
 
3012
                                case -1:
 
3013
                                        break;
 
3014
                                default:
 
3015
                                        /* the child should not terminate at all */
 
3016
                                        if (WIFEXITED(status)) {
 
3017
                                                log_error_write(srv, __FILE__, __LINE__, "sdsd", 
 
3018
                                                                "child exited, pid:", proc->pid,
 
3019
                                                                "status:", WEXITSTATUS(status));
 
3020
                                        } else if (WIFSIGNALED(status)) {
 
3021
                                                log_error_write(srv, __FILE__, __LINE__, "sd", 
 
3022
                                                                "child signaled:", 
 
3023
                                                                WTERMSIG(status));
 
3024
                                        } else {
 
3025
                                                log_error_write(srv, __FILE__, __LINE__, "sd", 
 
3026
                                                                "child died somehow:", 
 
3027
                                                                status);
 
3028
                                        }
 
3029
                                        
 
3030
                                        if (p->conf.debug) {
 
3031
                                                log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
 
3032
                                                                "--- fastcgi spawning",
 
3033
                                                                "\n\tport:", host->port,
 
3034
                                                                "\n\tsocket", host->unixsocket,
 
3035
                                                                "\n\tcurrent:", 1, "/", host->min_procs);
 
3036
                                        }
 
3037
                                        
 
3038
                                        if (fcgi_spawn_connection(srv, p, host, proc)) {
 
3039
                                                /* child died */
 
3040
                                                proc->state = PROC_STATE_DIED;
 
3041
                                        } else {
 
3042
                                                fcgi_proclist_sort_down(srv, host, proc);
 
3043
                                        }
 
3044
                                        
 
3045
                                        break;
 
3046
                                }
 
3047
                        }
 
3048
 
 
3049
                        if (con->file_started == 0) {
 
3050
                                /* nothing has been send out yet, try to use another child */
 
3051
                                
 
3052
                                if (hctx->wb->bytes_out == 0 &&
 
3053
                                    hctx->reconnects < 5) {
 
3054
                                        fcgi_reconnect(srv, hctx);
 
3055
                                        
 
3056
                                        log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
 
3057
                                                "response not sent, request not sent, reconnection.",
 
3058
                                                "connection-fd:", con->fd,
 
3059
                                                "fcgi-fd:", hctx->fd);
 
3060
                                        
 
3061
                                        return HANDLER_WAIT_FOR_FD;
 
3062
                                }
 
3063
                                
 
3064
                                log_error_write(srv, __FILE__, __LINE__, "sosdsd", 
 
3065
                                                "response not sent, request sent:", hctx->wb->bytes_out,
 
3066
                                                "connection-fd:", con->fd,
 
3067
                                                "fcgi-fd:", hctx->fd);
 
3068
                                
 
3069
                                fcgi_connection_close(srv, hctx);
 
3070
                                
 
3071
                                connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
 
3072
                                buffer_reset(con->physical.path);
 
3073
                                con->http_status = 500;
 
3074
                                con->mode = DIRECT;
 
3075
                        } else {
 
3076
                                /* response might have been already started, kill the connection */
 
3077
                                fcgi_connection_close(srv, hctx);
 
3078
                                
 
3079
                                log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
 
3080
                                                "response already sent out, termination connection",
 
3081
                                                "connection-fd:", con->fd,
 
3082
                                                "fcgi-fd:", hctx->fd);
 
3083
                                
 
3084
                                connection_set_state(srv, con, CON_STATE_ERROR);
 
3085
                        }
 
3086
 
 
3087
                        /* */
 
3088
                        
 
3089
                        
 
3090
                        joblist_append(srv, con);
 
3091
                        return HANDLER_FINISHED;
 
3092
                }
 
3093
        }
 
3094
        
 
3095
        if (revents & FDEVENT_OUT) {
 
3096
                if (hctx->state == FCGI_STATE_CONNECT ||
 
3097
                    hctx->state == FCGI_STATE_WRITE) {
 
3098
                        /* we are allowed to send something out
 
3099
                         * 
 
3100
                         * 1. in a unfinished connect() call
 
3101
                         * 2. in a unfinished write() call (long POST request)
 
3102
                         */
 
3103
                        return mod_fastcgi_handle_subrequest(srv, con, p);
 
3104
                } else {
 
3105
                        log_error_write(srv, __FILE__, __LINE__, "sd", 
 
3106
                                        "got a FDEVENT_OUT and didn't know why:", 
 
3107
                                        hctx->state);
 
3108
                }
 
3109
        }
 
3110
        
 
3111
        /* perhaps this issue is already handled */
 
3112
        if (revents & FDEVENT_HUP) {
 
3113
                if (hctx->state == FCGI_STATE_CONNECT) {
 
3114
                        /* getoptsock will catch this one (right ?)
 
3115
                         * 
 
3116
                         * if we are in connect we might get a EINPROGRESS 
 
3117
                         * in the first call and a FDEVENT_HUP in the 
 
3118
                         * second round
 
3119
                         * 
 
3120
                         * FIXME: as it is a bit ugly.
 
3121
                         * 
 
3122
                         */
 
3123
                        return mod_fastcgi_handle_subrequest(srv, con, p);
 
3124
                } else if (hctx->state == FCGI_STATE_READ &&
 
3125
                           hctx->proc->port == 0) {
 
3126
                        /* FIXME:
 
3127
                         * 
 
3128
                         * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
 
3129
                         * even if the FCGI_FIN packet is not received yet
 
3130
                         */
 
3131
                } else {
 
3132
                        log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
 
3133
                                        "error: unexpected close of fastcgi connection for", 
 
3134
                                        con->uri.path,
 
3135
                                        "(no fastcgi process on host: ", 
 
3136
                                        host->host,
 
3137
                                        ", port: ", 
 
3138
                                        host->port,
 
3139
                                        " ?)",
 
3140
                                        hctx->state);
 
3141
                        
 
3142
                        connection_set_state(srv, con, CON_STATE_ERROR);
 
3143
                        fcgi_connection_close(srv, hctx);
 
3144
                        joblist_append(srv, con);
 
3145
                }
 
3146
        } else if (revents & FDEVENT_ERR) {
 
3147
                log_error_write(srv, __FILE__, __LINE__, "s", 
 
3148
                                "fcgi: got a FDEVENT_ERR. Don't know why.");
 
3149
                /* kill all connections to the fastcgi process */
 
3150
 
 
3151
 
 
3152
                connection_set_state(srv, con, CON_STATE_ERROR);
 
3153
                fcgi_connection_close(srv, hctx);
 
3154
                joblist_append(srv, con);
 
3155
        }
 
3156
        
 
3157
        return HANDLER_FINISHED;
 
3158
}
 
3159
#define PATCH(x) \
 
3160
        p->conf.x = s->x;
 
3161
static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
 
3162
        size_t i, j;
 
3163
        plugin_config *s = p->config_storage[0];
 
3164
        
 
3165
        PATCH(exts);
 
3166
        PATCH(debug);
 
3167
        
 
3168
        /* skip the first, the global context */
 
3169
        for (i = 1; i < srv->config_context->used; i++) {
 
3170
                data_config *dc = (data_config *)srv->config_context->data[i];
 
3171
                s = p->config_storage[i];
 
3172
                
 
3173
                /* condition didn't match */
 
3174
                if (!config_check_cond(srv, con, dc)) continue;
 
3175
                
 
3176
                /* merge config */
 
3177
                for (j = 0; j < dc->value->used; j++) {
 
3178
                        data_unset *du = dc->value->data[j];
 
3179
                        
 
3180
                        if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
 
3181
                                PATCH(exts);
 
3182
                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
 
3183
                                PATCH(debug);
 
3184
                        }
 
3185
                }
 
3186
        }
 
3187
        
 
3188
        return 0;
 
3189
}
 
3190
#undef PATCH
 
3191
 
 
3192
 
 
3193
static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
 
3194
        plugin_data *p = p_d;
 
3195
        size_t s_len;
 
3196
        int used = -1;
 
3197
        int ndx;
 
3198
        size_t k;
 
3199
        buffer *fn;
 
3200
        fcgi_extension *extension = NULL;
 
3201
        
 
3202
        /* Possibly, we processed already this request */
 
3203
        if (con->file_started == 1) return HANDLER_GO_ON;
 
3204
        
 
3205
        fn = con->uri.path;
 
3206
 
 
3207
        if (fn->used == 0) {
 
3208
                return HANDLER_ERROR;
 
3209
        }
 
3210
        
 
3211
        s_len = fn->used - 1;
 
3212
        
 
3213
        fcgi_patch_connection(srv, con, p);
 
3214
        
 
3215
        /* check if extension matches */
 
3216
        for (k = 0; k < p->conf.exts->used; k++) {
 
3217
                size_t ct_len; /* length of the config entry */
 
3218
                
 
3219
                extension = p->conf.exts->exts[k];
 
3220
                
 
3221
                if (extension->key->used == 0) continue;
 
3222
                
 
3223
                ct_len = extension->key->used - 1;
 
3224
                
 
3225
                if (s_len < ct_len) continue;
 
3226
                
 
3227
                /* check extension in the form "/fcgi_pattern" */
 
3228
                if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
 
3229
                        break;
 
3230
                } else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) {
 
3231
                        /* check extension in the form ".fcg" */
 
3232
                        break;
 
3233
                }
 
3234
        }
 
3235
        
 
3236
        /* extension doesn't match */
 
3237
        if (k == p->conf.exts->used) {
 
3238
                return HANDLER_GO_ON;
 
3239
        }
 
3240
        
 
3241
        /* get best server */
 
3242
        for (k = 0, ndx = -1; k < extension->used; k++) {
 
3243
                fcgi_extension_host *host = extension->hosts[k];
 
3244
                
 
3245
                /* we should have at least one proc that can do somthing */
 
3246
                if (host->active_procs == 0) continue;
 
3247
 
 
3248
                if (used == -1 || host->load < used) {
 
3249
                        used = host->load;
 
3250
                        
 
3251
                        ndx = k;
 
3252
                }
 
3253
        }
 
3254
        
 
3255
        /* found a server */
 
3256
        if (ndx != -1) {
 
3257
                fcgi_extension_host *host = extension->hosts[ndx];
 
3258
                
 
3259
                /* 
 
3260
                 * if check-local is disabled, use the uri.path handler 
 
3261
                 * 
 
3262
                 */
 
3263
                
 
3264
                /* init handler-context */
 
3265
                if (uri_path_handler) {
 
3266
                        if (host->check_local == 0) {
 
3267
                                handler_ctx *hctx;
 
3268
                                char *pathinfo;
 
3269
                                
 
3270
                                hctx = handler_ctx_init();
 
3271
                                
 
3272
                                hctx->remote_conn      = con;
 
3273
                                hctx->plugin_data      = p;
 
3274
                                hctx->host             = host;
 
3275
                                hctx->proc             = NULL;
 
3276
 
 
3277
                                hctx->conf.exts        = p->conf.exts;
 
3278
                                hctx->conf.debug       = p->conf.debug;
 
3279
                                
 
3280
                                con->plugin_ctx[p->id] = hctx;
 
3281
                                
 
3282
                                host->load++;
 
3283
                                
 
3284
                                con->mode = p->id;
 
3285
                                
 
3286
                                if (con->conf.log_request_handling) {
 
3287
                                        log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
 
3288
                                }
 
3289
                                
 
3290
                                /* the prefix is the SCRIPT_NAME, 
 
3291
                                 * everthing from start to the next slash
 
3292
                                 * this is important for check-local = "disable"
 
3293
                                 * 
 
3294
                                 * if prefix = /admin.fcgi
 
3295
                                 * 
 
3296
                                 * /admin.fcgi/foo/bar
 
3297
                                 * 
 
3298
                                 * SCRIPT_NAME = /admin.fcgi
 
3299
                                 * PATH_INFO   = /foo/bar
 
3300
                                 * 
 
3301
                                 * if prefix = /fcgi-bin/
 
3302
                                 * 
 
3303
                                 * /fcgi-bin/foo/bar
 
3304
                                 * 
 
3305
                                 * SCRIPT_NAME = /fcgi-bin/foo
 
3306
                                 * PATH_INFO   = /bar
 
3307
                                 * 
 
3308
                                 */
 
3309
                                
 
3310
                                /* the rewrite is only done for /prefix/? matches */
 
3311
                                if (extension->key->ptr[0] == '/' &&
 
3312
                                    con->uri.path->used > extension->key->used &&
 
3313
                                    NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
 
3314
                                        /* rewrite uri.path and pathinfo */ 
 
3315
                                        
 
3316
                                        buffer_copy_string(con->request.pathinfo, pathinfo);
 
3317
                                        
 
3318
                                        con->uri.path->used -= con->request.pathinfo->used - 1;
 
3319
                                        con->uri.path->ptr[con->uri.path->used - 1] = '\0';
 
3320
                                }
 
3321
                        }
 
3322
                        return HANDLER_GO_ON;
 
3323
                } else {
 
3324
                        handler_ctx *hctx;
 
3325
                        hctx = handler_ctx_init();
 
3326
                        
 
3327
                        hctx->remote_conn      = con;
 
3328
                        hctx->plugin_data      = p;
 
3329
                        hctx->host             = host;
 
3330
                        hctx->proc             = NULL;
 
3331
                        
 
3332
                        hctx->conf.exts        = p->conf.exts;
 
3333
                        hctx->conf.debug       = p->conf.debug;
 
3334
                        
 
3335
                        con->plugin_ctx[p->id] = hctx;
 
3336
                        
 
3337
                        host->load++;
 
3338
                        
 
3339
                        con->mode = p->id;
 
3340
                        
 
3341
                        if (con->conf.log_request_handling) {
 
3342
                                log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
 
3343
                        }
 
3344
                        
 
3345
                        return HANDLER_GO_ON;
 
3346
                }
 
3347
        } else {
 
3348
                /* no handler found */
 
3349
                buffer_reset(con->physical.path);
 
3350
                con->http_status = 500;
 
3351
                
 
3352
                log_error_write(srv, __FILE__, __LINE__,  "sb", 
 
3353
                                "no fcgi-handler found for:", 
 
3354
                                fn);
 
3355
                
 
3356
                return HANDLER_FINISHED;
 
3357
        }
 
3358
        return HANDLER_GO_ON;
 
3359
}
 
3360
 
 
3361
/* uri-path handler */
 
3362
static handler_t fcgi_check_extension_1(server *srv, connection *con, void *p_d) {
 
3363
        return fcgi_check_extension(srv, con, p_d, 1);
 
3364
}
 
3365
 
 
3366
/* start request handler */
 
3367
static handler_t fcgi_check_extension_2(server *srv, connection *con, void *p_d) {
 
3368
        return fcgi_check_extension(srv, con, p_d, 0);
 
3369
}
 
3370
 
 
3371
JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
 
3372
        plugin_data *p = p_d;
 
3373
        handler_ctx *hctx = con->plugin_ctx[p->id];
 
3374
        
 
3375
        if (hctx == NULL) return HANDLER_GO_ON;
 
3376
 
 
3377
        if (hctx->fd != -1) {
 
3378
                switch (hctx->state) {
 
3379
                case FCGI_STATE_READ:
 
3380
                        fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
 
3381
                        
 
3382
                        break;
 
3383
                case FCGI_STATE_CONNECT:
 
3384
                case FCGI_STATE_WRITE:
 
3385
                        fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
 
3386
                        
 
3387
                        break;
 
3388
                case FCGI_STATE_INIT:
 
3389
                        /* at reconnect */
 
3390
                        break;
 
3391
                default:
 
3392
                        log_error_write(srv, __FILE__, __LINE__, "sd", "unhandled fcgi.state", hctx->state);
 
3393
                        break;
 
3394
                }
 
3395
        }
 
3396
 
 
3397
        return HANDLER_GO_ON;
 
3398
}
 
3399
 
 
3400
 
 
3401
static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
 
3402
        plugin_data *p = p_d;
 
3403
        
 
3404
        fcgi_connection_close(srv, con->plugin_ctx[p->id]);
 
3405
 
 
3406
        return HANDLER_GO_ON;
 
3407
}
 
3408
 
 
3409
TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
 
3410
        plugin_data *p = p_d;
 
3411
        size_t i, j, n;
 
3412
        
 
3413
        
 
3414
        /* perhaps we should kill a connect attempt after 10-15 seconds
 
3415
         * 
 
3416
         * currently we wait for the TCP timeout which is on Linux 180 seconds
 
3417
         * 
 
3418
         * 
 
3419
         * 
 
3420
         */
 
3421
 
 
3422
        /* check all childs if they are still up */
 
3423
 
 
3424
        for (i = 0; i < srv->config_context->used; i++) {
 
3425
                plugin_config *conf;
 
3426
                fcgi_exts *exts;
 
3427
 
 
3428
                conf = p->config_storage[i];
 
3429
 
 
3430
                exts = conf->exts;
 
3431
 
 
3432
                for (j = 0; j < exts->used; j++) {
 
3433
                        fcgi_extension *ex;
 
3434
 
 
3435
                        ex = exts->exts[j];
 
3436
                        
 
3437
                        for (n = 0; n < ex->used; n++) {
 
3438
                                
 
3439
                                fcgi_proc *proc;
 
3440
                                unsigned long sum_load = 0;
 
3441
                                fcgi_extension_host *host;
 
3442
                                
 
3443
                                host = ex->hosts[n];
 
3444
                                
 
3445
                                fcgi_restart_dead_procs(srv, p, host);
 
3446
                                
 
3447
                                for (proc = host->first; proc; proc = proc->next) {
 
3448
                                        sum_load += proc->load;
 
3449
                                }
 
3450
                                
 
3451
                                if (host->num_procs &&
 
3452
                                    host->num_procs < host->max_procs &&
 
3453
                                    (sum_load / host->num_procs) > host->max_load_per_proc) {
 
3454
                                        /* overload, spawn new child */
 
3455
                                        fcgi_proc *fp = NULL;
 
3456
                                        
 
3457
                                        if (p->conf.debug) {
 
3458
                                                log_error_write(srv, __FILE__, __LINE__, "s", 
 
3459
                                                                "overload detected, spawning a new child");
 
3460
                                        }
 
3461
                                        
 
3462
                                        for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
 
3463
                                        
 
3464
                                        if (fp) {
 
3465
                                                if (fp == host->unused_procs) host->unused_procs = fp->next;
 
3466
                                                
 
3467
                                                if (fp->next) fp->next->prev = NULL;
 
3468
                                                
 
3469
                                                host->max_id++;
 
3470
                                        } else {
 
3471
                                                fp = fastcgi_process_init();
 
3472
                                                fp->id = host->max_id++;
 
3473
                                        }
 
3474
                                        
 
3475
                                        host->num_procs++;
 
3476
                                        
 
3477
                                        if (buffer_is_empty(host->unixsocket)) {
 
3478
                                                fp->port = host->port + fp->id;
 
3479
                                        } else {
 
3480
                                                buffer_copy_string_buffer(fp->socket, host->unixsocket);
 
3481
                                                buffer_append_string(fp->socket, "-");
 
3482
                                                buffer_append_long(fp->socket, fp->id);
 
3483
                                        }
 
3484
                                        
 
3485
                                        if (fcgi_spawn_connection(srv, p, host, fp)) {
 
3486
                                                log_error_write(srv, __FILE__, __LINE__, "s",
 
3487
                                                                "ERROR: spawning fcgi failed.");
 
3488
                                                return HANDLER_ERROR;
 
3489
                                        }
 
3490
                                        
 
3491
                                        fp->prev = NULL;
 
3492
                                        fp->next = host->first;
 
3493
                                        if (host->first) {
 
3494
                                                host->first->prev = fp;
 
3495
                                        }
 
3496
                                        host->first = fp;
 
3497
                                }
 
3498
                                
 
3499
                                for (proc = host->first; proc; proc = proc->next) {
 
3500
                                        if (proc->load != 0) break;
 
3501
                                        if (host->num_procs <= host->min_procs) break;
 
3502
                                        if (proc->pid == 0) continue;
 
3503
                                        
 
3504
                                        if (srv->cur_ts - proc->last_used > host->idle_timeout) {
 
3505
                                                /* a proc is idling for a long time now,
 
3506
                                                 * terminated it */
 
3507
                                                
 
3508
                                                if (p->conf.debug) {
 
3509
                                                        log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
 
3510
                                                                        "idle-timeout reached, terminating child:", 
 
3511
                                                                        "socket:", proc->socket, 
 
3512
                                                                        "pid", proc->pid);
 
3513
                                                }
 
3514
                                                
 
3515
                                                
 
3516
                                                if (proc->next) proc->next->prev = proc->prev;
 
3517
                                                if (proc->prev) proc->prev->next = proc->next;
 
3518
                                                
 
3519
                                                if (proc->prev == NULL) host->first = proc->next;
 
3520
                                                
 
3521
                                                proc->prev = NULL;
 
3522
                                                proc->next = host->unused_procs;
 
3523
                                                
 
3524
                                                if (host->unused_procs) host->unused_procs->prev = proc;
 
3525
                                                host->unused_procs = proc;
 
3526
                                                
 
3527
                                                kill(proc->pid, SIGTERM);
 
3528
                                                
 
3529
                                                proc->state = PROC_STATE_KILLED;
 
3530
                                                
 
3531
                                                log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
 
3532
                                                                        "killed:", 
 
3533
                                                                        "socket:", proc->socket, 
 
3534
                                                                        "pid", proc->pid);
 
3535
                                                
 
3536
                                                host->num_procs--;
 
3537
                                                
 
3538
                                                /* proc is now in unused, let the next second handle the next process */
 
3539
                                                break;
 
3540
                                        }       
 
3541
                                }
 
3542
                                
 
3543
                                for (proc = host->unused_procs; proc; proc = proc->next) {
 
3544
                                        int status;
 
3545
                                        
 
3546
                                        if (proc->pid == 0) continue;
 
3547
                                        
 
3548
                                        switch (waitpid(proc->pid, &status, WNOHANG)) {
 
3549
                                        case 0:
 
3550
                                                /* child still running after timeout, good */
 
3551
                                                break;
 
3552
                                        case -1:
 
3553
                                                if (errno != EINTR) {
 
3554
                                                        /* no PID found ? should never happen */
 
3555
                                                        log_error_write(srv, __FILE__, __LINE__, "sddss", 
 
3556
                                                                        "pid ", proc->pid, proc->state,
 
3557
                                                                        "not found:", strerror(errno));
 
3558
                                                        
 
3559
#if 0
 
3560
                                                        if (errno == ECHILD) {
 
3561
                                                                /* someone else has cleaned up for us */
 
3562
                                                                proc->pid = 0;
 
3563
                                                                proc->state = PROC_STATE_UNSET;
 
3564
                                                        }
 
3565
#endif
 
3566
                                                }
 
3567
                                                break;
 
3568
                                        default:
 
3569
                                                /* the child should not terminate at all */
 
3570
                                                if (WIFEXITED(status)) {
 
3571
                                                        if (proc->state != PROC_STATE_KILLED) {
 
3572
                                                                log_error_write(srv, __FILE__, __LINE__, "sdb", 
 
3573
                                                                                "child exited:", 
 
3574
                                                                                WEXITSTATUS(status), proc->socket);
 
3575
                                                        }
 
3576
                                                } else if (WIFSIGNALED(status)) {
 
3577
                                                        if (WTERMSIG(status) != SIGTERM) {
 
3578
                                                                log_error_write(srv, __FILE__, __LINE__, "sd", 
 
3579
                                                                                "child signaled:", 
 
3580
                                                                                WTERMSIG(status));
 
3581
                                                        }
 
3582
                                                } else {
 
3583
                                                        log_error_write(srv, __FILE__, __LINE__, "sd", 
 
3584
                                                                        "child died somehow:", 
 
3585
                                                                        status);
 
3586
                                                }
 
3587
                                                proc->pid = 0;
 
3588
                                                proc->state = PROC_STATE_UNSET;
 
3589
                                                host->max_id--;
 
3590
                                        }
 
3591
                                }
 
3592
                        }
 
3593
                }
 
3594
        }
 
3595
 
 
3596
        return HANDLER_GO_ON;
 
3597
}
 
3598
 
 
3599
 
 
3600
int mod_fastcgi_plugin_init(plugin *p) {
 
3601
        p->version     = LIGHTTPD_VERSION_ID;
 
3602
        p->name         = buffer_init_string("fastcgi");
 
3603
 
 
3604
        p->init         = mod_fastcgi_init;
 
3605
        p->cleanup      = mod_fastcgi_free;
 
3606
        p->set_defaults = mod_fastcgi_set_defaults;
 
3607
        p->connection_reset        = fcgi_connection_reset;
 
3608
        p->handle_connection_close = fcgi_connection_close_callback;
 
3609
        p->handle_uri_clean        = fcgi_check_extension_1;
 
3610
        p->handle_subrequest_start = fcgi_check_extension_2;
 
3611
        p->handle_subrequest       = mod_fastcgi_handle_subrequest;
 
3612
        p->handle_joblist          = mod_fastcgi_handle_joblist;
 
3613
        p->handle_trigger          = mod_fastcgi_handle_trigger;
 
3614
        
 
3615
        p->data         = NULL;
 
3616
        
 
3617
        return 0;
 
3618
}