1 /*
2  * mod_fastcgi.c --
3  *
4  *      Apache server module for FastCGI.
5  *
6  *  $Id: mod_fastcgi.c,v 1.169 2008/11/09 14:31:03 robs Exp $
7  *
8  *  Copyright (c) 1995-1996 Open Market, Inc.
9  *
10  *  See the file "LICENSE.TERMS" for information on usage and redistribution
11  *  of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12  *
13  *
14  *  Patches for Apache-1.1 provided by
15  *  Ralf S. Engelschall
16  *  <rse@en.muc.de>
17  *
18  *  Patches for Linux provided by
19  *  Scott Langley
20  *  <langles@vote-smart.org>
21  *
22  *  Patches for suexec handling by
23  *  Brian Grossman <brian@SoftHome.net> and
24  *  Rob Saccoccio <robs@ipass.net>
25  */
26 
27 /*
28  * Module design notes.
29  *
30  * 1. Restart cleanup.
31  *
32  *   mod_fastcgi spawns several processes: one process manager process
33  *   and several application processes.  None of these processes
34  *   handle SIGHUP, so they just go away when the Web server performs
35  *   a restart (as Apache does every time it starts.)
36  *
37  *   In order to allow the process manager to properly cleanup the
38  *   running fastcgi processes (without being disturbed by Apache),
39  *   an intermediate process was introduced.  The diagram is as follows;
40  *
41  *   ApacheWS --> MiddleProc --> ProcMgr --> FCGI processes
42  *
43  *   On a restart, ApacheWS sends a SIGKILL to MiddleProc and then
44  *   collects it via waitpid().  The ProcMgr periodically checks for
45  *   its parent (via getppid()) and if it does not have one, as in
46  *   case when MiddleProc has terminated, ProcMgr issues a SIGTERM
47  *   to all FCGI processes, waitpid()s on them and then exits, so it
48  *   can be collected by init(1).  Doing it any other way (short of
49  *   changing Apache API), results either in inconsistent results or
50  *   in generation of zombie processes.
51  *
52  *   XXX: How does Apache 1.2 implement "gentle" restart
53  *   that does not disrupt current connections?  How does
54  *   gentle restart interact with restart cleanup?
55  *
56  * 2. Request timeouts.
57  *
58  *   Earlier versions of this module used ap_soft_timeout() rather than
59  *   ap_hard_timeout() and ate FastCGI server output until it completed.
60  *   This precluded the FastCGI server from having to implement a
61  *   SIGPIPE handler, but meant hanging the application longer than
62  *   necessary.  SIGPIPE handler now must be installed in ALL FastCGI
63  *   applications.  The handler should abort further processing and go
64  *   back into the accept() loop.
65  *
66  *   Although using ap_soft_timeout() is better than ap_hard_timeout()
67  *   we have to be more careful about SIGINT handling and subsequent
68  *   processing, so, for now, make it hard.
69  */
70 
71 
72 #include "fcgi.h"
73 
74 #ifdef APACHE2
75 #ifndef WIN32
76 
77 #include <unistd.h>
78 
79 #if APR_HAVE_CTYPE_H
80 #include <ctype.h>
81 #endif
82 
83 #include "unixd.h"
84 
85 #endif
86 #endif
87 
88 #ifndef timersub
89 #define	timersub(a, b, result)                              \
90 do {                                                  \
91     (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;           \
92     (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;        \
93     if ((result)->tv_usec < 0) {                            \
94         --(result)->tv_sec;                                 \
95         (result)->tv_usec += 1000000;                       \
96     }                                                       \
97 } while (0)
98 #endif
99 
100 /*
101  * Global variables
102  */
103 
104 pool *fcgi_config_pool;            	 /* the config pool */
105 server_rec *fcgi_apache_main_server;
106 
107 const char *fcgi_wrapper = NULL;          /* wrapper path */
108 uid_t fcgi_user_id;                       /* the run uid of Apache & PM */
109 gid_t fcgi_group_id;                      /* the run gid of Apache & PM */
110 
111 fcgi_server *fcgi_servers = NULL;         /* AppClasses */
112 
113 char *fcgi_socket_dir = NULL;             /* default FastCgiIpcDir */
114 
115 char *fcgi_dynamic_dir = NULL;            /* directory for the dynamic
116                                            * fastcgi apps' sockets */
117 
118 #ifdef WIN32
119 
120 #pragma warning( disable : 4706 4100 4127)
121 fcgi_pm_job *fcgi_dynamic_mbox = NULL;
122 HANDLE *fcgi_dynamic_mbox_mutex = NULL;
123 HANDLE fcgi_pm_thread = INVALID_HANDLE_VALUE;
124 
125 #else
126 
127 int fcgi_pm_pipe[2] = { -1, -1 };
128 pid_t fcgi_pm_pid = -1;
129 
130 #endif
131 
132 char *fcgi_empty_env = NULL;
133 
134 u_int dynamicMaxProcs = FCGI_DEFAULT_MAX_PROCS;
135 int   dynamicMinProcs = FCGI_DEFAULT_MIN_PROCS;
136 int dynamicMaxClassProcs = FCGI_DEFAULT_MAX_CLASS_PROCS;
137 u_int dynamicKillInterval = FCGI_DEFAULT_KILL_INTERVAL;
138 u_int dynamicUpdateInterval = FCGI_DEFAULT_UPDATE_INTERVAL;
139 float dynamicGain = FCGI_DEFAULT_GAIN;
140 int dynamicThreshold1 = FCGI_DEFAULT_THRESHOLD_1;
141 int dynamicThresholdN = FCGI_DEFAULT_THRESHOLD_N;
142 u_int dynamicPleaseStartDelay = FCGI_DEFAULT_START_PROCESS_DELAY;
143 u_int dynamicAppConnectTimeout = FCGI_DEFAULT_APP_CONN_TIMEOUT;
144 char **dynamicEnvp = &fcgi_empty_env;
145 u_int dynamicProcessSlack = FCGI_DEFAULT_PROCESS_SLACK;
146 int dynamicAutoRestart = FCGI_DEFAULT_RESTART_DYNAMIC;
147 int dynamicAutoUpdate = FCGI_DEFAULT_AUTOUPDATE;
148 int dynamicFlush = FCGI_FLUSH;
149 u_int dynamicListenQueueDepth = FCGI_DEFAULT_LISTEN_Q;
150 u_int dynamicInitStartDelay = DEFAULT_INIT_START_DELAY;
151 u_int dynamicRestartDelay = FCGI_DEFAULT_RESTART_DELAY;
152 array_header *dynamic_pass_headers = NULL;
153 u_int dynamic_idle_timeout = FCGI_DEFAULT_IDLE_TIMEOUT;
154 int dynamicMinServerLife = FCGI_DEFAULT_MIN_SERVER_LIFE;
155 
156 #ifdef APLOG_USE_MODULE
157 APLOG_USE_MODULE(fastcgi);
158 #endif
159 
160 /*******************************************************************************
161  * Construct a message and write it to the pm_pipe.
162  */
send_to_pm(const char id,const char * const fs_path,const char * user,const char * const group,const unsigned long q_usec,const unsigned long req_usec)163 static void send_to_pm(const char id, const char * const fs_path,
164      const char *user, const char * const group, const unsigned long q_usec,
165      const unsigned long req_usec)
166 {
167 #ifdef WIN32
168     fcgi_pm_job *job = NULL;
169 
170     if (!(job = (fcgi_pm_job *) malloc(sizeof(fcgi_pm_job))))
171        return;
172 #else
173     static int failed_count = 0;
174     int buflen = 0;
175     char buf[FCGI_MAX_MSG_LEN];
176 #endif
177 
178     if (strlen(fs_path) > FCGI_MAXPATH) {
179         ap_log_error(FCGI_LOG_ERR_NOERRNO, fcgi_apache_main_server,
180             "FastCGI: the path \"%s\" is too long (>%d) for a dynamic server", fs_path, FCGI_MAXPATH);
181         return;
182     }
183 
184     switch(id) {
185 
186     case FCGI_SERVER_START_JOB:
187     case FCGI_SERVER_RESTART_JOB:
188 #ifdef WIN32
189         job->id = id;
190         job->fs_path = strdup(fs_path);
191         job->user = strdup(user);
192         job->group = strdup(group);
193         job->qsec = 0L;
194         job->start_time = 0L;
195 #else
196         buflen = sprintf(buf, "%c %s %s %s*", id, fs_path, user, group);
197 #endif
198         break;
199 
200     case FCGI_REQUEST_TIMEOUT_JOB:
201 #ifdef WIN32
202         job->id = id;
203         job->fs_path = strdup(fs_path);
204         job->user = strdup(user);
205         job->group = strdup(group);
206         job->qsec = 0L;
207         job->start_time = 0L;
208 #else
209         buflen = sprintf(buf, "%c %s %s %s*", id, fs_path, user, group);
210 #endif
211         break;
212 
213     case FCGI_REQUEST_COMPLETE_JOB:
214 #ifdef WIN32
215         job->id = id;
216         job->fs_path = strdup(fs_path);
217         job->qsec = q_usec;
218         job->start_time = req_usec;
219         job->user = strdup(user);
220         job->group = strdup(group);
221 #else
222         buflen = sprintf(buf, "%c %s %s %s %lu %lu*", id, fs_path, user, group, q_usec, req_usec);
223 #endif
224         break;
225     }
226 
227 #ifdef WIN32
228     if (fcgi_pm_add_job(job)) return;
229 
230     SetEvent(fcgi_event_handles[MBOX_EVENT]);
231 #else
232     ASSERT(buflen <= FCGI_MAX_MSG_LEN);
233 
234     /* There is no apache flag or function that can be used to id
235      * restart/shutdown pending so ignore the first few failures as
236      * once it breaks it will stay broke */
237     if (write(fcgi_pm_pipe[1], (const void *)buf, buflen) != buflen
238         && failed_count++ > 10)
239     {
240         ap_log_error(FCGI_LOG_WARN, fcgi_apache_main_server,
241             "FastCGI: write() to PM failed (ignore if a restart or shutdown is pending)");
242     }
243 #endif
244 }
245 
246 /*
247  *----------------------------------------------------------------------
248  *
249  * init_module
250  *
251  *      An Apache module initializer, called by the Apache core
252  *      after reading the server config.
253  *
254  *      Start the process manager no matter what, since there may be a
255  *      request for dynamic FastCGI applications without any being
256  *      configured as static applications.  Also, check for the existence
257  *      and create if necessary a subdirectory into which all dynamic
258  *      sockets will go.
259  *
260  *----------------------------------------------------------------------
261  */
262 #ifdef APACHE2
init_module(apr_pool_t * p,apr_pool_t * plog,apr_pool_t * tp,server_rec * s)263 static apcb_t init_module(apr_pool_t * p, apr_pool_t * plog,
264                           apr_pool_t * tp, server_rec * s)
265 #else
266 static apcb_t init_module(server_rec *s, pool *p)
267 #endif
268 {
269 #ifndef WIN32
270     const char *err;
271 #endif
272 
273     /* Register to reset to default values when the config pool is cleaned */
274     ap_block_alarms();
275     ap_register_cleanup(p, NULL, fcgi_config_reset_globals, ap_null_cleanup);
276     ap_unblock_alarms();
277 
278 #ifdef APACHE2
279     ap_add_version_component(p, "mod_fastcgi/" MOD_FASTCGI_VERSION);
280 #else
281     ap_add_version_component("mod_fastcgi/" MOD_FASTCGI_VERSION);
282 #endif
283 
284     fcgi_config_set_fcgi_uid_n_gid(1);
285 
286     /* keep these handy */
287     fcgi_config_pool = p;
288     fcgi_apache_main_server = s;
289 
290 #ifdef WIN32
291     if (fcgi_socket_dir == NULL)
292         fcgi_socket_dir = DEFAULT_SOCK_DIR;
293     fcgi_dynamic_dir = ap_pstrcat(p, fcgi_socket_dir, "dynamic", NULL);
294 #else
295 
296     if (fcgi_socket_dir == NULL)
297         fcgi_socket_dir = ap_server_root_relative(p, DEFAULT_SOCK_DIR);
298 
299     /* Create Unix/Domain socket directory */
300     if ((err = fcgi_config_make_dir(p, fcgi_socket_dir)))
301         ap_log_error(FCGI_LOG_ERR, s, "FastCGI: %s", err);
302 
303     /* Create Dynamic directory */
304     if ((err = fcgi_config_make_dynamic_dir(p, 1)))
305         ap_log_error(FCGI_LOG_ERR, s, "FastCGI: %s", err);
306 
307     /* Spawn the PM only once.  Under Unix, Apache calls init() routines
308      * twice, once before detach() and once after.  Win32 doesn't detach.
309      * Under DSO, DSO modules are unloaded between the two init() calls.
310      * Under Unix, the -X switch causes two calls to init() but no detach
311      * (but all subprocesses are wacked so the PM is toasted anyway)! */
312 
313 #ifdef APACHE2
314     {
315         void * first_pass;
316         apr_pool_userdata_get(&first_pass, "mod_fastcgi", s->process->pool);
317         if (first_pass == NULL)
318         {
319             apr_pool_userdata_set((const void *)1, "mod_fastcgi",
320                                   apr_pool_cleanup_null, s->process->pool);
321             return APCB_OK;
322         }
323     }
324 #else /* !APACHE2 */
325 
326     if (ap_standalone && ap_restart_time == 0)
327         return;
328 
329 #endif
330 
331     /* Create the pipe for comm with the PM */
332     if (pipe(fcgi_pm_pipe) < 0) {
333         ap_log_error(FCGI_LOG_ERR, s, "FastCGI: pipe() failed");
334     }
335 
336     /* Start the Process Manager */
337 
338 #ifdef APACHE2
339     {
340         apr_proc_t * proc = apr_palloc(p, sizeof(*proc));
341         apr_status_t rv;
342 
343         rv = apr_proc_fork(proc, tp);
344 
345         if (rv == APR_INCHILD)
346         {
347             /* child */
348             fcgi_pm_main(NULL);
349             exit(1);
350         }
351         else if (rv != APR_INPARENT)
352         {
353             return rv;
354         }
355 
356         /* parent */
357 
358         apr_pool_note_subprocess(p, proc, APR_KILL_ONLY_ONCE);
359     }
360 #else /* !APACHE2 */
361 
362     fcgi_pm_pid = ap_spawn_child(p, fcgi_pm_main, NULL, kill_only_once, NULL, NULL, NULL);
363     if (fcgi_pm_pid <= 0) {
364         ap_log_error(FCGI_LOG_ALERT, s,
365             "FastCGI: can't start the process manager, spawn_child() failed");
366     }
367 
368 #endif /* !APACHE2 */
369 
370     close(fcgi_pm_pipe[0]);
371 
372 #endif /* !WIN32 */
373 
374     return APCB_OK;
375 }
376 
377 #ifdef WIN32
378 #ifdef APACHE2
fcgi_child_exit(void * dc)379 static apcb_t fcgi_child_exit(void * dc)
380 #else
381 static apcb_t fcgi_child_exit(server_rec *dc0, pool *dc1)
382 #endif
383 {
384     /* Signal the PM thread to exit*/
385     SetEvent(fcgi_event_handles[TERM_EVENT]);
386 
387     /* Waiting on pm thread to exit */
388     WaitForSingleObject(fcgi_pm_thread, INFINITE);
389 
390     return APCB_OK;
391 }
392 #endif /* WIN32 */
393 
394 #ifdef APACHE2
fcgi_child_init(apr_pool_t * p,server_rec * dc)395 static void fcgi_child_init(apr_pool_t * p, server_rec * dc)
396 #else
397 static void fcgi_child_init(server_rec *dc, pool *p)
398 #endif
399 {
400 #ifdef WIN32
401     /* Create the MBOX, TERM, and WAKE event handlers */
402     fcgi_event_handles[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
403     if (fcgi_event_handles[0] == NULL) {
404         ap_log_error(FCGI_LOG_ALERT, fcgi_apache_main_server,
405             "FastCGI: CreateEvent() failed");
406     }
407     fcgi_event_handles[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
408     if (fcgi_event_handles[1] == NULL) {
409         ap_log_error(FCGI_LOG_ALERT, fcgi_apache_main_server,
410             "FastCGI: CreateEvent() failed");
411     }
412     fcgi_event_handles[2] = CreateEvent(NULL, FALSE, FALSE, NULL);
413     if (fcgi_event_handles[2] == NULL) {
414         ap_log_error(FCGI_LOG_ALERT, fcgi_apache_main_server,
415             "FastCGI: CreateEvent() failed");
416     }
417 
418     /* Create the mbox mutex (PM - request threads) */
419     fcgi_dynamic_mbox_mutex = CreateMutex(NULL, FALSE, NULL);
420     if (fcgi_dynamic_mbox_mutex == NULL) {
421         ap_log_error(FCGI_LOG_ALERT, fcgi_apache_main_server,
422             "FastCGI: CreateMutex() failed");
423     }
424 
425     /* Spawn of the process manager thread */
426     fcgi_pm_thread = (HANDLE) _beginthread(fcgi_pm_main, 0, NULL);
427     if (fcgi_pm_thread == (HANDLE) -1) {
428         ap_log_error(FCGI_LOG_ALERT, fcgi_apache_main_server,
429             "_beginthread() failed to spawn the process manager");
430     }
431 
432 #ifdef APACHE2
433     apr_pool_cleanup_register(p, NULL, fcgi_child_exit, fcgi_child_exit);
434 #endif
435 #endif
436 }
437 
438 /*
439  *----------------------------------------------------------------------
440  *
441  * get_header_line --
442  *
443  *      Terminate a line:  scan to the next newline, scan back to the
444  *      first non-space character and store a terminating zero.  Return
445  *      the next character past the end of the newline.
446  *
447  *      If the end of the string is reached, ASSERT!
448  *
449  *      If the FIRST character(s) in the line are '\n' or "\r\n", the
450  *      first character is replaced with a NULL and next character
451  *      past the newline is returned.  NOTE: this condition supercedes
452  *      the processing of RFC-822 continuation lines.
453  *
454  *      If continuation is set to 'TRUE', then it parses a (possible)
455  *      sequence of RFC-822 continuation lines.
456  *
457  * Results:
458  *      As above.
459  *
460  * Side effects:
461  *      Termination byte stored in string.
462  *
463  *----------------------------------------------------------------------
464  */
get_header_line(char * start,int continuation)465 static char *get_header_line(char *start, int continuation)
466 {
467     char *p = start;
468     char *end = start;
469 
470     if(p[0] == '\r'  &&  p[1] == '\n') { /* If EOL in 1st 2 chars */
471         p++;                              /*   point to \n and stop */
472     } else if(*p != '\n') {
473         if(continuation) {
474             while(*p != '\0') {
475                 if(*p == '\n' && p[1] != ' ' && p[1] != '\t')
476                     break;
477                 p++;
478             }
479         } else {
480             while(*p != '\0' && *p != '\n') {
481                 p++;
482             }
483         }
484     }
485 
486     ASSERT(*p != '\0');
487     end = p;
488     end++;
489 
490     /*
491      * Trim any trailing whitespace.
492      */
493     while(isspace((unsigned char)p[-1]) && p > start) {
494         p--;
495     }
496 
497     *p = '\0';
498     return end;
499 }
500 
501 #ifdef WIN32
502 
set_nonblocking(const fcgi_request * fr,int nonblocking)503 static int set_nonblocking(const fcgi_request * fr, int nonblocking)
504 {
505     if (fr->using_npipe_io)
506     {
507         if (nonblocking)
508         {
509             DWORD mode = PIPE_NOWAIT | PIPE_READMODE_BYTE;
510             if (SetNamedPipeHandleState((HANDLE) fr->fd, &mode, NULL, NULL) == 0)
511             {
512 		        ap_log_rerror(FCGI_LOG_ERR, fr->r,
513                     "FastCGI: SetNamedPipeHandleState() failed");
514                 return -1;
515             }
516         }
517     }
518     else
519     {
520         unsigned long ioctl_arg = (nonblocking) ? 1 : 0;
521         if (ioctlsocket(fr->fd, FIONBIO, &ioctl_arg) != 0)
522         {
523             errno = WSAGetLastError();
524             ap_log_rerror(FCGI_LOG_ERR_ERRNO, fr->r,
525                 "FastCGI: ioctlsocket() failed");
526             return -1;
527         }
528     }
529 
530     return 0;
531 }
532 
533 #else
534 
set_nonblocking(const fcgi_request * fr,int nonblocking)535 static int set_nonblocking(const fcgi_request * fr, int nonblocking)
536 {
537     int nb_flag = 0;
538     int fd_flags = fcntl(fr->fd, F_GETFL, 0);
539 
540     if (fd_flags < 0) return -1;
541 
542 #if defined(O_NONBLOCK)
543     nb_flag = O_NONBLOCK;
544 #elif defined(O_NDELAY)
545     nb_flag = O_NDELAY;
546 #elif defined(FNDELAY)
547     nb_flag = FNDELAY;
548 #else
549 #error "TODO - don't read from app until all data from client is posted."
550 #endif
551 
552     fd_flags = (nonblocking) ? (fd_flags | nb_flag) : (fd_flags & ~nb_flag);
553 
554     return fcntl(fr->fd, F_SETFL, fd_flags);
555 }
556 
557 #endif
558 
559 /*******************************************************************************
560  * Close the connection to the FastCGI server.  This is normally called by
561  * do_work(), but may also be called as in request pool cleanup.
562  */
close_connection_to_fs(fcgi_request * fr)563 static void close_connection_to_fs(fcgi_request *fr)
564 {
565 #ifdef WIN32
566 
567     if (fr->fd != INVALID_SOCKET)
568     {
569         set_nonblocking(fr, FALSE);
570 
571         if (fr->using_npipe_io)
572         {
573             CloseHandle((HANDLE) fr->fd);
574         }
575         else
576         {
577             /* abort the connection entirely */
578             struct linger linger = {0, 0};
579             setsockopt(fr->fd, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
580             closesocket(fr->fd);
581         }
582 
583         fr->fd = INVALID_SOCKET;
584 
585 #else /* ! WIN32 */
586 
587     if (fr->fd >= 0)
588     {
589         struct linger linger = {0, 0};
590         set_nonblocking(fr, FALSE);
591         /* abort the connection entirely */
592         setsockopt(fr->fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
593         close(fr->fd);
594         fr->fd = -1;
595 
596 #endif /* ! WIN32 */
597 
598         if (fr->dynamic && fr->keepReadingFromFcgiApp == FALSE)
599         {
600             /* XXX FCGI_REQUEST_COMPLETE_JOB is only sent for requests which complete
601              * normally WRT the fcgi app.  There is no data sent for
602              * connect() timeouts or requests which complete abnormally.
603              * KillDynamicProcs() and RemoveRecords() need to be looked at
604              * to be sure they can reasonably handle these cases before
605              * sending these sort of stats - theres some funk in there.
606              */
607             if (fcgi_util_ticks(&fr->completeTime) < 0)
608             {
609                 /* there's no point to aborting the request, just log it */
610                 ap_log_error(FCGI_LOG_ERR, fr->r->server, "FastCGI: can't get time of day");
611             }
612         }
613     }
614 }
615 
616 
617 /*
618  *----------------------------------------------------------------------
619  *
620  * process_headers --
621  *
622  *      Call with r->parseHeader == SCAN_CGI_READING_HEADERS
623  *      and initial script output in fr->header.
624  *
625  *      If the initial script output does not include the header
626  *      terminator ("\r\n\r\n") process_headers returns with no side
627  *      effects, to be called again when more script output
628  *      has been appended to fr->header.
629  *
630  *      If the initial script output includes the header terminator,
631  *      process_headers parses the headers and determines whether or
632  *      not the remaining script output will be sent to the client.
633  *      If so, process_headers sends the HTTP response headers to the
634  *      client and copies any non-header script output to the output
635  *      buffer reqOutbuf.
636  *
637  * Results:
638  *      none.
639  *
640  * Side effects:
641  *      May set r->parseHeader to:
642  *        SCAN_CGI_FINISHED -- headers parsed, returning script response
643  *        SCAN_CGI_BAD_HEADER -- malformed header from script
644  *        SCAN_CGI_INT_REDIRECT -- handler should perform internal redirect
645  *        SCAN_CGI_SRV_REDIRECT -- handler should return REDIRECT
646  *
647  *----------------------------------------------------------------------
648  */
649 
650 static const char *process_headers(request_rec *r, fcgi_request *fr)
651 {
652     char *p, *next, *name, *value;
653     int len, flag;
654     int hasLocation = FALSE;
655 
656     ASSERT(fr->parseHeader == SCAN_CGI_READING_HEADERS);
657 
658     if (fr->header == NULL)
659         return NULL;
660 
661     /*
662      * Do we have the entire header?  Scan for the blank line that
663      * terminates the header.
664      */
665     p = (char *)fr->header->elts;
666     len = fr->header->nelts;
667     flag = 0;
668     while(len-- && flag < 2) {
669         switch(*p) {
670             case '\r':
671                 break;
672             case '\n':
673                 flag++;
674                 break;
675             case '\0':
676             case '\v':
677             case '\f':
678                 name = "Invalid Character";
679                 goto BadHeader;
680             default:
681                 flag = 0;
682                 break;
683         }
684         p++;
685     }
686 
687     /* Return (to be called later when we have more data)
688      * if we don't have an entire header. */
689     if (flag < 2)
690         return NULL;
691 
692     /*
693      * Parse all the headers.
694      */
695     fr->parseHeader = SCAN_CGI_FINISHED;
696     next = (char *)fr->header->elts;
697     for(;;) {
698         next = get_header_line(name = next, TRUE);
699         if (*name == '\0') {
700             break;
701         }
702         if ((p = strchr(name, ':')) == NULL) {
703             goto BadHeader;
704         }
705         value = p + 1;
706         while (p != name && isspace((unsigned char)*(p - 1))) {
707             p--;
708         }
709         if (p == name) {
710             goto BadHeader;
711         }
712         *p = '\0';
713         if (strpbrk(name, " \t") != NULL) {
714             *p = ' ';
715             goto BadHeader;
716         }
717         while (isspace((unsigned char)*value)) {
718             value++;
719         }
720 
721         if (strcasecmp(name, "Status") == 0) {
722             int statusValue = strtol(value, NULL, 10);
723 
724             if (statusValue < 0) {
725                 fr->parseHeader = SCAN_CGI_BAD_HEADER;
726                 return ap_psprintf(r->pool, "invalid Status '%s'", value);
727             }
728             r->status = statusValue;
729             r->status_line = ap_pstrdup(r->pool, value);
730             continue;
731         }
732 
733         if (fr->role == FCGI_RESPONDER) {
734             if (strcasecmp(name, "Content-type") == 0) {
735 #ifdef APACHE2
736                 ap_set_content_type(r, value);
737 #else
738                 r->content_type = ap_pstrdup(r->pool, value);
739 #endif
740                 continue;
741             }
742 
743             /*
744              * Special case headers that should not persist on error
745              * or across redirects, i.e. use headers_out rather than
746              * err_headers_out.
747              */
748 
749             if (strcasecmp(name, "Location") == 0) {
750                 hasLocation = TRUE;
751                 ap_table_set(r->headers_out, name, value);
752                 continue;
753             }
754 
755             if (strcasecmp(name, "Content-Length") == 0) {
756                 ap_table_set(r->headers_out, name, value);
757                 continue;
758             }
759 
760             /* If the script wants them merged, it can do it */
761             ap_table_add(r->err_headers_out, name, value);
762             continue;
763         }
764         else {
765             ap_table_add(fr->authHeaders, name, value);
766         }
767     }
768 
769     if (fr->role != FCGI_RESPONDER)
770         return NULL;
771 
772     /*
773      * Who responds, this handler or Apache?
774      */
775     if (hasLocation) {
776         const char *location = ap_table_get(r->headers_out, "Location");
777         /*
778          * Based on internal redirect handling in mod_cgi.c...
779          *
780          * If a script wants to produce its own Redirect
781          * body, it now has to explicitly *say* "Status: 302"
782          */
783         if (r->status == 200) {
784             if(location[0] == '/') {
785                 /*
786                  * Location is an relative path.  This handler will
787                  * consume all script output, then have Apache perform an
788                  * internal redirect.
789                  */
790                 fr->parseHeader = SCAN_CGI_INT_REDIRECT;
791                 return NULL;
792             } else {
793                 /*
794                  * Location is an absolute URL.  If the script didn't
795                  * produce a Content-type header, this handler will
796                  * consume all script output and then have Apache generate
797                  * its standard redirect response.  Otherwise this handler
798                  * will transmit the script's response.
799                  */
800                 fr->parseHeader = SCAN_CGI_SRV_REDIRECT;
801                 return NULL;
802             }
803         }
804     }
805     /*
806      * We're responding.  Send headers, buffer excess script output.
807      */
808     ap_send_http_header(r);
809 
810     /* We need to reinstate our timeout, send_http_header() kill()s it */
811     ap_hard_timeout("FastCGI request processing", r);
812 
813     if (r->header_only) {
814         /* we've got all we want from the server */
815         close_connection_to_fs(fr);
816         fr->exitStatusSet = 1;
817         fcgi_buf_reset(fr->clientOutputBuffer);
818         fcgi_buf_reset(fr->serverOutputBuffer);
819         return NULL;
820     }
821 
822     len = fr->header->nelts - (next - fr->header->elts);
823 
824     ASSERT(len >= 0);
825     ASSERT(BufferLength(fr->clientOutputBuffer) == 0);
826 
827     if (BufferFree(fr->clientOutputBuffer) < len) {
828         fr->clientOutputBuffer = fcgi_buf_new(r->pool, len);
829     }
830 
831     ASSERT(BufferFree(fr->clientOutputBuffer) >= len);
832 
833     if (len > 0) {
834         int sent;
835         sent = fcgi_buf_add_block(fr->clientOutputBuffer, next, len);
836         ASSERT(sent == len);
837     }
838 
839     return NULL;
840 
841 BadHeader:
842     /* Log first line of a multi-line header */
843     if ((p = strpbrk(name, "\r\n")) != NULL)
844         *p = '\0';
845     fr->parseHeader = SCAN_CGI_BAD_HEADER;
846     return ap_psprintf(r->pool, "malformed header '%s'", name);
847 }
848 
849 /*
850  * Read from the client filling both the FastCGI server buffer and the
851  * client buffer with the hopes of buffering the client data before
852  * making the connect() to the FastCGI server.  This prevents slow
853  * clients from keeping the FastCGI server in processing longer than is
854  * necessary.
855  */
856 static int read_from_client_n_queue(fcgi_request *fr)
857 {
858     char *end;
859     int count;
860     long int countRead;
861 
862     while (BufferFree(fr->clientInputBuffer) > 0 || BufferFree(fr->serverOutputBuffer) > 0) {
863         fcgi_protocol_queue_client_buffer(fr);
864 
865         if (fr->expectingClientContent <= 0)
866             return OK;
867 
868         fcgi_buf_get_free_block_info(fr->clientInputBuffer, &end, &count);
869         if (count == 0)
870             return OK;
871 
872         if ((countRead = ap_get_client_block(fr->r, end, count)) < 0)
873         {
874             /* set the header scan state to done to prevent logging an error
875              * - hokey approach - probably should be using a unique value */
876             fr->parseHeader = SCAN_CGI_FINISHED;
877             return -1;
878         }
879 
880         if (countRead == 0) {
881             fr->expectingClientContent = 0;
882         }
883         else {
884             fcgi_buf_add_update(fr->clientInputBuffer, countRead);
885             ap_reset_timeout(fr->r);
886         }
887     }
888     return OK;
889 }
890 
891 static int write_to_client(fcgi_request *fr)
892 {
893     char *begin;
894     int count;
895     int rv;
896 #ifdef APACHE2
897     apr_bucket * bkt;
898     apr_bucket_brigade * bde;
899     apr_bucket_alloc_t * const bkt_alloc = fr->r->connection->bucket_alloc;
900 #endif
901 
902     fcgi_buf_get_block_info(fr->clientOutputBuffer, &begin, &count);
903     if (count == 0)
904         return OK;
905 
906     /* If fewer than count bytes are written, an error occured.
907      * ap_bwrite() typically forces a flushed write to the client, this
908      * effectively results in a block (and short packets) - it should
909      * be fixed, but I didn't win much support for the idea on new-httpd.
910      * So, without patching Apache, the best way to deal with this is
911      * to size the fcgi_bufs to hold all of the script output (within
912      * reason) so the script can be released from having to wait around
913      * for the transmission to the client to complete. */
914 
915 #ifdef APACHE2
916 
917     bde = apr_brigade_create(fr->r->pool, bkt_alloc);
918     bkt = apr_bucket_transient_create(begin, count, bkt_alloc);
919     APR_BRIGADE_INSERT_TAIL(bde, bkt);
920 
921     if (fr->fs ? fr->fs->flush : dynamicFlush)
922     {
923         bkt = apr_bucket_flush_create(bkt_alloc);
924         APR_BRIGADE_INSERT_TAIL(bde, bkt);
925     }
926 
927     rv = ap_pass_brigade(fr->r->output_filters, bde);
928 
929 #elif defined(RUSSIAN_APACHE)
930 
931     rv = (ap_rwrite(begin, count, fr->r) != count);
932 
933 #else
934 
935     rv = (ap_bwrite(fr->r->connection->client, begin, count) != count);
936 
937 #endif
938 
939     if (rv || fr->r->connection->aborted) {
940         ap_log_rerror(FCGI_LOG_INFO_NOERRNO, fr->r,
941             "FastCGI: client stopped connection before send body completed");
942         return -1;
943     }
944 
945 #ifndef APACHE2
946 
947     ap_reset_timeout(fr->r);
948 
949     /* Don't bother with a wrapped buffer, limiting exposure to slow
950      * clients.  The BUFF routines don't allow a writev from above,
951      * and don't always memcpy to minimize small write()s, this should
952      * be fixed, but I didn't win much support for the idea on
953      * new-httpd - I'll have to _prove_ its a problem first.. */
954 
955     /* The default behaviour used to be to flush with every write, but this
956      * can tie up the FastCGI server longer than is necessary so its an option now */
957 
958     if (fr->fs ? fr->fs->flush : dynamicFlush)
959     {
960 #ifdef RUSSIAN_APACHE
961         rv = ap_rflush(fr->r);
962 #else
963         rv = ap_bflush(fr->r->connection->client);
964 #endif
965 
966         if (rv)
967         {
968             ap_log_rerror(FCGI_LOG_INFO_NOERRNO, fr->r,
969                 "FastCGI: client stopped connection before send body completed");
970             return -1;
971         }
972 
973         ap_reset_timeout(fr->r);
974     }
975 
976 #endif /* !APACHE2 */
977 
978     fcgi_buf_toss(fr->clientOutputBuffer, count);
979     return OK;
980 }
981 
982 static void
983 get_request_identity(request_rec * const r,
984                      uid_t * const uid,
985                      gid_t * const gid)
986 {
987 #if defined(WIN32)
988     *uid = (uid_t) 0;
989     *gid = (gid_t) 0;
990 #elif defined(APACHE2)
991     ap_unix_identity_t * identity = ap_run_get_suexec_identity(r);
992     if (identity)
993     {
994         *uid = identity->uid;
995         *gid = identity->gid;
996     }
997     else
998     {
999         *uid = 0;
1000         *gid = 0;
1001     }
1002 #else
1003     *uid = r->server->server_uid;
1004     *gid = r->server->server_gid;
1005 #endif
1006 }
1007 
1008 /*******************************************************************************
1009  * Determine the user and group the wrapper should be called with.
1010  * Based on code in Apache's create_argv_cmd() (util_script.c).
1011  */
1012 static void set_uid_n_gid(request_rec *r, const char **user, const char **group)
1013 {
1014     if (fcgi_wrapper == NULL) {
1015         *user = "-";
1016         *group = "-";
1017         return;
1018     }
1019 
1020     if (strncmp("/~", r->uri, 2) == 0) {
1021         /* its a user dir uri, just send the ~user, and leave it to the PM */
1022         char *end = strchr(r->uri + 2, '/');
1023 
1024         if (end)
1025             *user = memcpy(ap_pcalloc(r->pool, end - r->uri), r->uri + 1, end - r->uri - 1);
1026         else
1027             *user = ap_pstrdup(r->pool, r->uri + 1);
1028         *group = "-";
1029     }
1030     else {
1031         uid_t uid;
1032         gid_t gid;
1033 
1034         get_request_identity(r, &uid, &gid);
1035 
1036         *user = ap_psprintf(r->pool, "%ld", (long) uid);
1037         *group = ap_psprintf(r->pool, "%ld", (long) gid);
1038     }
1039 }
1040 
1041 static void send_request_complete(fcgi_request *fr)
1042 {
1043     if (fr->completeTime.tv_sec)
1044     {
1045         struct timeval qtime, rtime;
1046 
1047         timersub(&fr->queueTime, &fr->startTime, &qtime);
1048         timersub(&fr->completeTime, &fr->queueTime, &rtime);
1049 
1050         send_to_pm(FCGI_REQUEST_COMPLETE_JOB, fr->fs_path,
1051             fr->user, fr->group,
1052             qtime.tv_sec * 1000000 + qtime.tv_usec,
1053             rtime.tv_sec * 1000000 + rtime.tv_usec);
1054     }
1055 }
1056 
1057 
1058 /*******************************************************************************
1059  * Connect to the FastCGI server.
1060  */
1061 static int open_connection_to_fs(fcgi_request *fr)
1062 {
1063     struct timeval  tval;
1064     fd_set          write_fds, read_fds;
1065     int             status;
1066     request_rec * const r = fr->r;
1067     pool * const rp = r->pool;
1068     const char *socket_path = NULL;
1069     struct sockaddr *socket_addr = NULL;
1070     int socket_addr_len = 0;
1071 #ifndef WIN32
1072     const char *err = NULL;
1073 #endif
1074 
1075     /* Create the connection point */
1076     if (fr->dynamic)
1077     {
1078         socket_path = fcgi_util_socket_hash_filename(rp, fr->fs_path, fr->user, fr->group);
1079         socket_path = fcgi_util_socket_make_path_absolute(rp, socket_path, 1);
1080 
1081 #ifndef WIN32
1082         err = fcgi_util_socket_make_domain_addr(rp, (struct sockaddr_un **)&socket_addr,
1083                                       &socket_addr_len, socket_path);
1084         if (err) {
1085             ap_log_rerror(FCGI_LOG_ERR, r,
1086                 "FastCGI: failed to connect to (dynamic) server \"%s\": "
1087                 "%s", fr->fs_path, err);
1088             return FCGI_FAILED;
1089         }
1090 #endif
1091     }
1092     else
1093     {
1094 #ifdef WIN32
1095         if (fr->fs->dest_addr != NULL) {
1096             socket_addr = fr->fs->dest_addr;
1097         }
1098         else if (fr->fs->socket_addr) {
1099             socket_addr = fr->fs->socket_addr;
1100         }
1101         else {
1102             socket_path = fr->fs->socket_path;
1103         }
1104 #else
1105         socket_addr = fr->fs->socket_addr;
1106 #endif
1107         socket_addr_len = fr->fs->socket_addr_len;
1108     }
1109 
1110     if (fr->dynamic)
1111     {
1112 #ifdef WIN32
1113         if (fr->fs && fr->fs->restartTime)
1114 #else
1115         struct stat sock_stat;
1116 
1117         if (stat(socket_path, &sock_stat) == 0)
1118 #endif
1119         {
1120             /* It exists */
1121             if (dynamicAutoUpdate)
1122             {
1123                 struct stat app_stat;
1124 
1125                 /* TODO: follow sym links */
1126 
1127                 if (stat(fr->fs_path, &app_stat) == 0)
1128                 {
1129 #ifdef WIN32
1130                     if (fr->fs->startTime < app_stat.st_mtime)
1131 #else
1132                     if (sock_stat.st_mtime < app_stat.st_mtime)
1133 #endif
1134                     {
1135 #ifndef WIN32
1136                         struct timeval tv;
1137 
1138                         tv.tv_sec = 1;
1139                         tv.tv_usec = 0;
1140 #endif
1141                         /*
1142                          * There's a newer one, request a restart.
1143                          */
1144                         send_to_pm(FCGI_SERVER_RESTART_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
1145 
1146 #ifdef WIN32
1147                         Sleep(1000);
1148 #else
1149                         /* Avoid sleep/alarm interactions */
1150                         ap_select(0, NULL, NULL, NULL, &tv);
1151 #endif
1152                     }
1153                 }
1154             }
1155         }
1156         else
1157         {
1158             int i;
1159 
1160             send_to_pm(FCGI_SERVER_START_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
1161 
1162             /* wait until it looks like its running - this shouldn't take
1163              * very long at all - the exception is when the sockets are
1164              * removed out from under a running application - the loop
1165              * limit addresses this (preventing spinning) */
1166 
1167             for (i = 10; i > 0; i--)
1168             {
1169 #ifdef WIN32
1170                 Sleep(500);
1171 
1172                 fr->fs = fcgi_util_fs_get_by_id(fr->fs_path, 0, 0);
1173 
1174                 if (fr->fs && fr->fs->restartTime)
1175 #else
1176             	struct timeval tv;
1177 
1178                 tv.tv_sec = 0;
1179               	tv.tv_usec =  500000;
1180 
1181                 /* Avoid sleep/alarm interactions */
1182                 ap_select(0, NULL, NULL, NULL, &tv);
1183 
1184                 if (stat(socket_path, &sock_stat) == 0)
1185 #endif
1186                 {
1187                     break;
1188                 }
1189             }
1190 
1191             if (i <= 0)
1192             {
1193                 ap_log_rerror(FCGI_LOG_ALERT, r,
1194                     "FastCGI: failed to connect to (dynamic) server \"%s\": "
1195                     "something is seriously wrong, any chance the "
1196                     "socket/named_pipe directory was removed?, see the "
1197                     "FastCgiIpcDir directive", fr->fs_path);
1198                 return FCGI_FAILED;
1199             }
1200         }
1201     }
1202 
1203 #ifdef WIN32
1204     if (socket_path)
1205     {
1206         BOOL ready;
1207         DWORD connect_time;
1208         int rv;
1209         HANDLE wait_npipe_mutex;
1210         DWORD interval;
1211         DWORD max_connect_time = FCGI_NAMED_PIPE_CONNECT_TIMEOUT;
1212 
1213         fr->using_npipe_io = TRUE;
1214 
1215         if (fr->dynamic)
1216         {
1217             interval = dynamicPleaseStartDelay * 1000;
1218 
1219             if (dynamicAppConnectTimeout) {
1220                 max_connect_time = dynamicAppConnectTimeout;
1221             }
1222         }
1223         else
1224         {
1225             interval = FCGI_NAMED_PIPE_CONNECT_TIMEOUT * 1000;
1226 
1227             if (fr->fs->appConnectTimeout) {
1228                 max_connect_time = fr->fs->appConnectTimeout;
1229             }
1230         }
1231 
1232         fcgi_util_ticks(&fr->startTime);
1233 
1234         {
1235             /* xxx this handle should live somewhere (see CloseHandle()s below too) */
1236             char * wait_npipe_mutex_name, * cp;
1237             wait_npipe_mutex_name = cp = ap_pstrdup(rp, socket_path);
1238             while ((cp = strchr(cp, '\\'))) *cp = '/';
1239 
1240             wait_npipe_mutex = CreateMutex(NULL, FALSE, wait_npipe_mutex_name);
1241         }
1242 
1243         if (wait_npipe_mutex == NULL)
1244         {
1245             ap_log_rerror(FCGI_LOG_ERR, r,
1246                 "FastCGI: failed to connect to server \"%s\": "
1247                 "can't create the WaitNamedPipe mutex", fr->fs_path);
1248             return FCGI_FAILED;
1249         }
1250 
1251         SetLastError(ERROR_SUCCESS);
1252 
1253         rv = WaitForSingleObject(wait_npipe_mutex, max_connect_time * 1000);
1254 
1255         if (rv == WAIT_TIMEOUT || rv == WAIT_FAILED)
1256         {
1257             if (fr->dynamic)
1258             {
1259                 send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
1260             }
1261             ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
1262                 "FastCGI: failed to connect to server \"%s\": "
1263                 "wait for a npipe instance failed", fr->fs_path);
1264             FCGIDBG3("interval=%d, max_connect_time=%d", interval, max_connect_time);
1265             CloseHandle(wait_npipe_mutex);
1266             return FCGI_FAILED;
1267         }
1268 
1269         fcgi_util_ticks(&fr->queueTime);
1270 
1271         connect_time = fr->queueTime.tv_sec - fr->startTime.tv_sec;
1272 
1273         if (fr->dynamic)
1274         {
1275             if (connect_time >= interval)
1276             {
1277                 send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
1278                 FCGIDBG4("connect_time=%d, interval=%d, max_connect_time=%d", connect_time, interval, max_connect_time);
1279             }
1280             if (max_connect_time - connect_time < interval)
1281             {
1282                 interval = max_connect_time - connect_time;
1283             }
1284         }
1285         else
1286         {
1287             interval -= connect_time * 1000;
1288         }
1289 
1290         for (;;)
1291         {
1292             ready = WaitNamedPipe(socket_path, interval);
1293 
1294             if (ready)
1295             {
1296                 fr->fd = (SOCKET) CreateFile(socket_path,
1297                     GENERIC_READ | GENERIC_WRITE,
1298                     FILE_SHARE_READ | FILE_SHARE_WRITE,
1299                     NULL,                  /* no security attributes */
1300                     OPEN_EXISTING,         /* opens existing pipe */
1301                     FILE_FLAG_OVERLAPPED,
1302                     NULL);                 /* no template file */
1303 
1304                 if (fr->fd != (SOCKET) INVALID_HANDLE_VALUE)
1305                 {
1306                     ReleaseMutex(wait_npipe_mutex);
1307                     CloseHandle(wait_npipe_mutex);
1308                     fcgi_util_ticks(&fr->queueTime);
1309                     FCGIDBG2("got npipe connect: %s", fr->fs_path);
1310                     return FCGI_OK;
1311                 }
1312 
1313                 if (GetLastError() != ERROR_PIPE_BUSY
1314                     && GetLastError() != ERROR_FILE_NOT_FOUND)
1315                 {
1316                     ap_log_rerror(FCGI_LOG_ERR, r,
1317                         "FastCGI: failed to connect to server \"%s\": "
1318                         "CreateFile() failed", fr->fs_path);
1319                     break;
1320                 }
1321 
1322                 FCGIDBG2("missed npipe connect: %s", fr->fs_path);
1323             }
1324 
1325             if (fr->dynamic)
1326             {
1327                 send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
1328             }
1329 
1330             fcgi_util_ticks(&fr->queueTime);
1331 
1332             connect_time = fr->queueTime.tv_sec - fr->startTime.tv_sec;
1333 
1334             FCGIDBG5("interval=%d, max_connect_time=%d, connect_time=%d, ready=%d", interval, max_connect_time, connect_time, ready);
1335 
1336             if (connect_time >= max_connect_time)
1337             {
1338                 ap_log_rerror(FCGI_LOG_ERR, r,
1339                     "FastCGI: failed to connect to server \"%s\": "
1340                     "CreateFile()/WaitNamedPipe() timed out", fr->fs_path);
1341                 break;
1342             }
1343         }
1344 
1345         ReleaseMutex(wait_npipe_mutex);
1346         CloseHandle(wait_npipe_mutex);
1347         fr->fd = INVALID_SOCKET;
1348         return FCGI_FAILED;
1349     }
1350 
1351 #endif
1352 
1353     /* Create the socket */
1354     fr->fd = socket(socket_addr->sa_family, SOCK_STREAM, 0);
1355 
1356 #ifdef WIN32
1357     if (fr->fd == INVALID_SOCKET) {
1358         errno = WSAGetLastError();  /* Not sure this is going to work as expected */
1359 #else
1360     if (fr->fd < 0) {
1361 #endif
1362         ap_log_rerror(FCGI_LOG_ERR_ERRNO, r,
1363             "FastCGI: failed to connect to server \"%s\": "
1364             "socket() failed", fr->fs_path);
1365         return FCGI_FAILED;
1366     }
1367 
1368 #ifndef WIN32
1369     if (fr->fd >= FD_SETSIZE) {
1370         ap_log_rerror(FCGI_LOG_ERR, r,
1371             "FastCGI: failed to connect to server \"%s\": "
1372             "socket file descriptor (%u) is larger than "
1373             "FD_SETSIZE (%u), you probably need to rebuild Apache with a "
1374             "larger FD_SETSIZE", fr->fs_path, fr->fd, FD_SETSIZE);
1375         return FCGI_FAILED;
1376     }
1377 #endif
1378 
1379     /* If appConnectTimeout is non-zero, setup do a non-blocking connect */
1380     if ((fr->dynamic && dynamicAppConnectTimeout) || (!fr->dynamic && fr->fs->appConnectTimeout)) {
1381         set_nonblocking(fr, TRUE);
1382     }
1383 
1384     if (fr->dynamic) {
1385         fcgi_util_ticks(&fr->startTime);
1386     }
1387 
1388     /* Connect */
1389     do {
1390     	if (connect(fr->fd, (struct sockaddr *) socket_addr, socket_addr_len) == 0) {
1391         goto ConnectionComplete;
1392     	}
1393     } while (errno == EINTR);
1394 
1395 #ifdef WIN32
1396 
1397     errno = WSAGetLastError();
1398     if (errno != WSAEWOULDBLOCK) {
1399         ap_log_rerror(FCGI_LOG_ERR_ERRNO, r,
1400             "FastCGI: failed to connect to server \"%s\": "
1401             "connect() failed", fr->fs_path);
1402         return FCGI_FAILED;
1403     }
1404 
1405 #else
1406 
1407     /* ECONNREFUSED means the listen queue is full (or there isn't one).
1408      * With dynamic I can at least make sure the PM knows this is occuring */
1409     if (fr->dynamic && errno == ECONNREFUSED) {
1410         /* @@@ This might be better as some other "kind" of message */
1411         send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
1412 
1413         errno = ECONNREFUSED;
1414     }
1415 
1416     if (errno != EINPROGRESS) {
1417         ap_log_rerror(FCGI_LOG_ERR, r,
1418             "FastCGI: failed to connect to server \"%s\": "
1419             "connect() failed", fr->fs_path);
1420         return FCGI_FAILED;
1421     }
1422 
1423 #endif
1424 
1425     /* The connect() is non-blocking */
1426 
1427     errno = 0;
1428 
1429     if (fr->dynamic) {
1430         do {
1431             FD_ZERO(&write_fds);
1432             FD_SET(fr->fd, &write_fds);
1433             read_fds = write_fds;
1434             tval.tv_sec = dynamicPleaseStartDelay;
1435             tval.tv_usec = 0;
1436 
1437             do {
1438             	status = ap_select(fr->fd + 1, &read_fds, &write_fds, NULL, &tval);
1439             } while (status < 0 && errno == EINTR);
1440 
1441             if (status < 0)
1442                 break;
1443 
1444             fcgi_util_ticks(&fr->queueTime);
1445 
1446             if (status > 0)
1447                 break;
1448 
1449             /* select() timed out */
1450             send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
1451         } while ((fr->queueTime.tv_sec - fr->startTime.tv_sec) < (int)dynamicAppConnectTimeout);
1452 
1453         /* XXX These can be moved down when dynamic vars live is a struct */
1454         if (status == 0) {
1455             ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
1456                 "FastCGI: failed to connect to server \"%s\": "
1457                 "connect() timed out (appConnTimeout=%dsec)",
1458                 fr->fs_path, dynamicAppConnectTimeout);
1459             return FCGI_FAILED;
1460         }
1461     }  /* dynamic */
1462     else {
1463         tval.tv_sec = fr->fs->appConnectTimeout;
1464         tval.tv_usec = 0;
1465         FD_ZERO(&write_fds);
1466         FD_SET(fr->fd, &write_fds);
1467         read_fds = write_fds;
1468 
1469         do {
1470         	status = ap_select(fr->fd + 1, &read_fds, &write_fds, NULL, &tval);
1471         } while (status < 0 && errno == EINTR);
1472 
1473         if (status == 0) {
1474             ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
1475                 "FastCGI: failed to connect to server \"%s\": "
1476                 "connect() timed out (appConnTimeout=%dsec)",
1477                 fr->fs_path, dynamicAppConnectTimeout);
1478             return FCGI_FAILED;
1479         }
1480     }  /* !dynamic */
1481 
1482     if (status < 0) {
1483 #ifdef WIN32
1484         errno = WSAGetLastError();
1485 #endif
1486         ap_log_rerror(FCGI_LOG_ERR_ERRNO, r,
1487             "FastCGI: failed to connect to server \"%s\": "
1488             "select() failed", fr->fs_path);
1489         return FCGI_FAILED;
1490     }
1491 
1492     if (FD_ISSET(fr->fd, &write_fds) || FD_ISSET(fr->fd, &read_fds)) {
1493         int error = 0;
1494         NET_SIZE_T len = sizeof(error);
1495 
1496         if (getsockopt(fr->fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len) < 0) {
1497             /* Solaris pending error */
1498 #ifdef WIN32
1499             errno = WSAGetLastError();
1500 #endif
1501             ap_log_rerror(FCGI_LOG_ERR_ERRNO, r,
1502                 "FastCGI: failed to connect to server \"%s\": "
1503                 "select() failed (Solaris pending error)", fr->fs_path);
1504             return FCGI_FAILED;
1505         }
1506 
1507         if (error != 0) {
1508             /* Berkeley-derived pending error */
1509             errno = error;
1510             ap_log_rerror(FCGI_LOG_ERR_ERRNO, r,
1511                 "FastCGI: failed to connect to server \"%s\": "
1512                 "select() failed (pending error)", fr->fs_path);
1513             return FCGI_FAILED;
1514         }
1515     }
1516     else {
1517 #ifdef WIN32
1518         errno = WSAGetLastError();
1519 #endif
1520         ap_log_rerror(FCGI_LOG_ERR_ERRNO, r,
1521             "FastCGI: failed to connect to server \"%s\": "
1522             "select() error - THIS CAN'T HAPPEN!", fr->fs_path);
1523         return FCGI_FAILED;
1524     }
1525 
1526 ConnectionComplete:
1527     /* Return to blocking mode if it was set up */
1528     if ((fr->dynamic && dynamicAppConnectTimeout) || (!fr->dynamic && fr->fs->appConnectTimeout)) {
1529         set_nonblocking(fr, FALSE);
1530     }
1531 
1532 #ifdef TCP_NODELAY
1533     if (socket_addr->sa_family == AF_INET) {
1534         /* We shouldn't be sending small packets and there's no application
1535          * level ack of the data we send, so disable Nagle */
1536         int set = 1;
1537         setsockopt(fr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&set, sizeof(set));
1538     }
1539 #endif
1540 
1541     return FCGI_OK;
1542 }
1543 
1544 static void sink_client_data(fcgi_request *fr)
1545 {
1546     char *base;
1547     int size;
1548 
1549     fcgi_buf_reset(fr->clientInputBuffer);
1550     fcgi_buf_get_free_block_info(fr->clientInputBuffer, &base, &size);
1551 	while (ap_get_client_block(fr->r, base, size) > 0);
1552 }
1553 
1554 static apcb_t cleanup(void *data)
1555 {
1556     fcgi_request * const fr = (fcgi_request *) data;
1557 
1558     if (fr == NULL) return APCB_OK;
1559 
1560     /* its more than likely already run, but... */
1561     close_connection_to_fs(fr);
1562 
1563     send_request_complete(fr);
1564 
1565     if (fr->fs_stderr_len) {
1566         ap_log_rerror(FCGI_LOG_ERR_NOERRNO, fr->r,
1567             "FastCGI: server \"%s\" stderr: %s", fr->fs_path, fr->fs_stderr);
1568     }
1569 
1570     return APCB_OK;
1571 }
1572 
1573 #ifdef WIN32
1574 static int npipe_io(fcgi_request * const fr)
1575 {
1576     request_rec * const r = fr->r;
1577     enum
1578     {
1579         STATE_ENV_SEND,
1580         STATE_CLIENT_RECV,
1581         STATE_SERVER_SEND,
1582         STATE_SERVER_RECV,
1583         STATE_CLIENT_SEND,
1584         STATE_ERROR
1585     }
1586     state = STATE_ENV_SEND;
1587     env_status env_status;
1588     int client_recv;
1589     int dynamic_first_recv = fr->dynamic;
1590     int idle_timeout = fr->dynamic ? dynamic_idle_timeout : fr->fs->idle_timeout;
1591     int send_pending = 0;
1592     int recv_pending = 0;
1593     int client_send = 0;
1594     int rv;
1595     OVERLAPPED rov = { 0 };
1596     OVERLAPPED sov = { 0 };
1597     HANDLE events[2];
1598     struct timeval timeout;
1599     struct timeval dynamic_last_io_time;
1600     int did_io = 1;
1601     pool * const rp = r->pool;
1602     int is_connected = 0;
1603 DWORD recv_count = 0;
1604 
1605     dynamic_last_io_time.tv_sec = 0;
1606     dynamic_last_io_time.tv_usec = 0;
1607 
1608     if (fr->role == FCGI_RESPONDER)
1609     {
1610         client_recv = (fr->expectingClientContent != 0);
1611     }
1612 
1613     idle_timeout = fr->dynamic ? dynamic_idle_timeout : fr->fs->idle_timeout;
1614 
1615     env_status.envp = NULL;
1616 
1617     events[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
1618     events[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
1619     sov.hEvent = events[0];
1620     rov.hEvent = events[1];
1621 
1622     if (fr->dynamic)
1623     {
1624         dynamic_last_io_time = fr->startTime;
1625 
1626         if (dynamicAppConnectTimeout)
1627         {
1628             struct timeval qwait;
1629             timersub(&fr->queueTime, &fr->startTime, &qwait);
1630             dynamic_first_recv = qwait.tv_sec / dynamicPleaseStartDelay + 1;
1631         }
1632     }
1633 
1634     ap_hard_timeout("FastCGI request processing", r);
1635 
1636     while (state != STATE_CLIENT_SEND)
1637     {
1638         DWORD msec_timeout;
1639 
1640         switch (state)
1641         {
1642         case STATE_ENV_SEND:
1643 
1644             if (fcgi_protocol_queue_env(r, fr, &env_status) == 0)
1645             {
1646                 goto SERVER_SEND;
1647             }
1648 
1649             state = STATE_CLIENT_RECV;
1650 
1651             /* fall through */
1652 
1653         case STATE_CLIENT_RECV:
1654 
1655             if (read_from_client_n_queue(fr) != OK)
1656             {
1657                 state = STATE_ERROR;
1658                 break;
1659             }
1660 
1661             if (fr->eofSent)
1662             {
1663                 state = STATE_SERVER_SEND;
1664             }
1665 
1666             /* fall through */
1667 
1668 SERVER_SEND:
1669 
1670         case STATE_SERVER_SEND:
1671 
1672             if (! is_connected)
1673             {
1674                 if (open_connection_to_fs(fr) != FCGI_OK)
1675                 {
1676                     ap_kill_timeout(r);
1677                     return HTTP_INTERNAL_SERVER_ERROR;
1678                 }
1679 
1680                 is_connected = 1;
1681             }
1682 
1683             if (! send_pending && BufferLength(fr->serverOutputBuffer))
1684             {
1685                 Buffer * b = fr->serverOutputBuffer;
1686                 DWORD sent, len;
1687 
1688                 len = min(b->length, b->data + b->size - b->begin);
1689 
1690                 if (WriteFile((HANDLE) fr->fd, b->begin, len, &sent, &sov))
1691                 {
1692                     /* sov.hEvent is set */
1693                     fcgi_buf_removed(b, sent);
1694                 }
1695                 else if (GetLastError() == ERROR_IO_PENDING)
1696                 {
1697                     send_pending = 1;
1698                 }
1699                 else
1700                 {
1701                     ap_log_rerror(FCGI_LOG_ERR, r, "FastCGI: comm with server "
1702                         "\"%s\" aborted: WriteFile() failed", fr->fs_path);
1703                     state = STATE_ERROR;
1704                     break;
1705                 }
1706             }
1707 
1708             /* fall through */
1709 
1710         case STATE_SERVER_RECV:
1711 
1712             /*
1713              * Only get more data when the serverInputBuffer is empty.
1714              * Otherwise we may already have the END_REQUEST buffered
1715              * (but not processed) and a read on a closed named pipe
1716              * results in an error that is normally abnormal.
1717              */
1718             if (! recv_pending && BufferLength(fr->serverInputBuffer) == 0)
1719             {
1720                 Buffer * b = fr->serverInputBuffer;
1721                 DWORD rcvd, len;
1722 
1723                 len = min(b->size - b->length, b->data + b->size - b->end);
1724 
1725                 if (ReadFile((HANDLE) fr->fd, b->end, len, &rcvd, &rov))
1726                 {
1727                     fcgi_buf_added(b, rcvd);
1728                     recv_count += rcvd;
1729                     ResetEvent(rov.hEvent);
1730                     if (dynamic_first_recv)
1731                     {
1732                         dynamic_first_recv = 0;
1733                     }
1734                 }
1735                 else if (GetLastError() == ERROR_IO_PENDING)
1736                 {
1737                     recv_pending = 1;
1738                 }
1739                 else if (GetLastError() == ERROR_HANDLE_EOF)
1740                 {
1741                     fr->keepReadingFromFcgiApp = FALSE;
1742                     state = STATE_CLIENT_SEND;
1743                     ResetEvent(rov.hEvent);
1744                     break;
1745                 }
1746                 else if (GetLastError() == ERROR_NO_DATA)
1747                 {
1748                     break;
1749                 }
1750                 else
1751                 {
1752                     ap_log_rerror(FCGI_LOG_ERR, r, "FastCGI: comm with server "
1753                         "\"%s\" aborted: ReadFile() failed", fr->fs_path);
1754                     state = STATE_ERROR;
1755                     break;
1756                 }
1757             }
1758 
1759             /* fall through */
1760 
1761         case STATE_CLIENT_SEND:
1762 
1763             if (client_send || ! BufferFree(fr->clientOutputBuffer))
1764             {
1765                 if (write_to_client(fr))
1766                 {
1767                     state = STATE_ERROR;
1768                     break;
1769                 }
1770 
1771                 client_send = 0;
1772 
1773                 if (fcgi_protocol_dequeue(rp, fr))
1774                 {
1775                     state = STATE_ERROR;
1776                     break;
1777                 }
1778             }
1779 
1780             break;
1781 
1782         default:
1783 
1784             ASSERT(0);
1785         }
1786 
1787         if (state == STATE_ERROR)
1788         {
1789             break;
1790         }
1791 
1792         /* setup the io timeout */
1793 
1794         if (BufferLength(fr->clientOutputBuffer))
1795         {
1796             /* don't let client data sit too long, it might be a push */
1797             timeout.tv_sec = 0;
1798             timeout.tv_usec = 100000;
1799         }
1800         else if (dynamic_first_recv)
1801         {
1802             int delay;
1803             struct timeval qwait;
1804 
1805             fcgi_util_ticks(&fr->queueTime);
1806 
1807             if (did_io)
1808             {
1809                 /* a send() succeeded last pass */
1810                 dynamic_last_io_time = fr->queueTime;
1811             }
1812             else
1813             {
1814                 /* timed out last pass */
1815                 struct timeval idle_time;
1816 
1817                 timersub(&fr->queueTime, &dynamic_last_io_time, &idle_time);
1818 
1819                 if (idle_time.tv_sec > idle_timeout)
1820                 {
1821                     send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
1822                     ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r, "FastCGI: comm "
1823                         "with (dynamic) server \"%s\" aborted: (first read) "
1824                         "idle timeout (%d sec)", fr->fs_path, idle_timeout);
1825                     state = STATE_ERROR;
1826                     break;
1827                 }
1828             }
1829 
1830             timersub(&fr->queueTime, &fr->startTime, &qwait);
1831 
1832             delay = dynamic_first_recv * dynamicPleaseStartDelay;
1833 
1834             if (qwait.tv_sec < delay)
1835             {
1836                 timeout.tv_sec = delay;
1837                 timeout.tv_usec = 100000;  /* fudge for select() slop */
1838                 timersub(&timeout, &qwait, &timeout);
1839             }
1840             else
1841             {
1842                 /* Killed time somewhere.. client read? */
1843                 send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
1844                 dynamic_first_recv = qwait.tv_sec / dynamicPleaseStartDelay + 1;
1845                 timeout.tv_sec = dynamic_first_recv * dynamicPleaseStartDelay;
1846                 timeout.tv_usec = 100000;  /* fudge for select() slop */
1847                 timersub(&timeout, &qwait, &timeout);
1848             }
1849         }
1850         else
1851         {
1852             timeout.tv_sec = idle_timeout;
1853             timeout.tv_usec = 0;
1854         }
1855 
1856         /* require a pended recv otherwise the app can deadlock */
1857         if (recv_pending)
1858         {
1859             msec_timeout = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
1860 
1861             rv = WaitForMultipleObjects(2, events, FALSE, msec_timeout);
1862 
1863             if (rv == WAIT_TIMEOUT)
1864             {
1865                 did_io = 0;
1866 
1867                 if (BufferLength(fr->clientOutputBuffer))
1868                 {
1869                     client_send = 1;
1870                 }
1871                 else if (dynamic_first_recv)
1872                 {
1873                     struct timeval qwait;
1874 
1875                     fcgi_util_ticks(&fr->queueTime);
1876                     timersub(&fr->queueTime, &fr->startTime, &qwait);
1877 
1878                     send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
1879 
1880                     dynamic_first_recv = qwait.tv_sec / dynamicPleaseStartDelay + 1;
1881                 }
1882                 else
1883                 {
1884                     ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r, "FastCGI: comm with "
1885                         "server \"%s\" aborted: idle timeout (%d sec)",
1886                         fr->fs_path, idle_timeout);
1887                     state = STATE_ERROR;
1888                     break;
1889                 }
1890             }
1891             else
1892             {
1893                 int i = rv - WAIT_OBJECT_0;
1894 
1895                 did_io = 1;
1896 
1897                 if (i == 0)
1898                 {
1899                     if (send_pending)
1900                     {
1901                         DWORD sent;
1902 
1903                         if (GetOverlappedResult((HANDLE) fr->fd, &sov, &sent, FALSE))
1904                         {
1905                             send_pending = 0;
1906                             fcgi_buf_removed(fr->serverOutputBuffer, sent);
1907                         }
1908                         else
1909                         {
1910                             ap_log_rerror(FCGI_LOG_ERR, r, "FastCGI: comm with server "
1911                                 "\"%s\" aborted: GetOverlappedResult() failed", fr->fs_path);
1912                             state = STATE_ERROR;
1913                             break;
1914                         }
1915                     }
1916 
1917                     ResetEvent(sov.hEvent);
1918                 }
1919                 else
1920                 {
1921                     DWORD rcvd;
1922 
1923                     ASSERT(i == 1);
1924 
1925                     recv_pending = 0;
1926                     ResetEvent(rov.hEvent);
1927 
1928                     if (GetOverlappedResult((HANDLE) fr->fd, &rov, &rcvd, FALSE))
1929                     {
1930                         fcgi_buf_added(fr->serverInputBuffer, rcvd);
1931                         if (dynamic_first_recv)
1932                         {
1933                             dynamic_first_recv = 0;
1934                         }
1935                     }
1936                     else
1937                     {
1938                         ap_log_rerror(FCGI_LOG_ERR, r, "FastCGI: comm with server "
1939                             "\"%s\" aborted: GetOverlappedResult() failed", fr->fs_path);
1940                         state = STATE_ERROR;
1941                         break;
1942                     }
1943                 }
1944             }
1945         }
1946 
1947         if (fcgi_protocol_dequeue(rp, fr))
1948         {
1949             state = STATE_ERROR;
1950             break;
1951         }
1952 
1953         if (fr->parseHeader == SCAN_CGI_READING_HEADERS)
1954         {
1955             const char * err = process_headers(r, fr);
1956             if (err)
1957             {
1958                 ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
1959                     "FastCGI: comm with server \"%s\" aborted: "
1960                     "error parsing headers: %s", fr->fs_path, err);
1961                 state = STATE_ERROR;
1962                 break;
1963             }
1964         }
1965 
1966         if (fr->exitStatusSet)
1967         {
1968             fr->keepReadingFromFcgiApp = FALSE;
1969             state = STATE_CLIENT_SEND;
1970             break;
1971         }
1972     }
1973 
1974     if (! fr->exitStatusSet || ! fr->eofSent)
1975     {
1976         CancelIo((HANDLE) fr->fd);
1977     }
1978 
1979     CloseHandle(rov.hEvent);
1980     CloseHandle(sov.hEvent);
1981 
1982     return (state == STATE_ERROR);
1983 }
1984 #endif /* WIN32 */
1985 
1986 static int socket_io(fcgi_request * const fr)
1987 {
1988     enum
1989     {
1990         STATE_SOCKET_NONE,
1991         STATE_ENV_SEND,
1992         STATE_CLIENT_RECV,
1993         STATE_SERVER_SEND,
1994         STATE_SERVER_RECV,
1995         STATE_CLIENT_SEND,
1996         STATE_ERROR,
1997         STATE_CLIENT_ERROR
1998     }
1999     state = STATE_ENV_SEND;
2000 
2001     request_rec * const r = fr->r;
2002 
2003     struct timeval timeout;
2004     struct timeval dynamic_last_io_time;
2005     fd_set read_set;
2006     fd_set write_set;
2007     int nfds = 0;
2008     int select_status = 1;
2009     int idle_timeout;
2010     int rv;
2011     int dynamic_first_recv = fr->dynamic ? 1 : 0;
2012     int client_send = FALSE;
2013     int client_recv = FALSE;
2014     env_status env;
2015     pool *rp = r->pool;
2016     int is_connected = 0;
2017 
2018     dynamic_last_io_time.tv_sec = 0;
2019     dynamic_last_io_time.tv_usec = 0;
2020 
2021     if (fr->role == FCGI_RESPONDER)
2022     {
2023         client_recv = (fr->expectingClientContent != 0);
2024     }
2025 
2026     idle_timeout = fr->dynamic ? dynamic_idle_timeout : fr->fs->idle_timeout;
2027 
2028     env.envp = NULL;
2029 
2030     if (fr->dynamic)
2031     {
2032         dynamic_last_io_time = fr->startTime;
2033 
2034         if (dynamicAppConnectTimeout)
2035         {
2036             struct timeval qwait;
2037             timersub(&fr->queueTime, &fr->startTime, &qwait);
2038             dynamic_first_recv = qwait.tv_sec / dynamicPleaseStartDelay + 1;
2039         }
2040     }
2041 
2042     ap_hard_timeout("FastCGI request processing", r);
2043 
2044     for (;;)
2045     {
2046         FD_ZERO(&read_set);
2047         FD_ZERO(&write_set);
2048 
2049         switch (state)
2050         {
2051         case STATE_ENV_SEND:
2052 
2053             if (fcgi_protocol_queue_env(r, fr, &env) == 0)
2054             {
2055                 goto SERVER_SEND;
2056             }
2057 
2058             state = STATE_CLIENT_RECV;
2059 
2060             /* fall through */
2061 
2062         case STATE_CLIENT_RECV:
2063 
2064             if (read_from_client_n_queue(fr))
2065             {
2066                 state = STATE_CLIENT_ERROR;
2067                 break;
2068             }
2069 
2070             if (fr->eofSent)
2071             {
2072                 state = STATE_SERVER_SEND;
2073             }
2074 
2075             /* fall through */
2076 
2077 SERVER_SEND:
2078 
2079         case STATE_SERVER_SEND:
2080 
2081             if (! is_connected)
2082             {
2083                 if (open_connection_to_fs(fr) != FCGI_OK)
2084                 {
2085                     ap_kill_timeout(r);
2086                     return HTTP_INTERNAL_SERVER_ERROR;
2087                 }
2088 
2089                 set_nonblocking(fr, TRUE);
2090                 is_connected = 1;
2091                 nfds = fr->fd + 1;
2092             }
2093 
2094             if (BufferLength(fr->serverOutputBuffer))
2095             {
2096                 FD_SET(fr->fd, &write_set);
2097             }
2098             else
2099             {
2100                 ASSERT(fr->eofSent);
2101                 state = STATE_SERVER_RECV;
2102             }
2103 
2104             /* fall through */
2105 
2106         case STATE_SERVER_RECV:
2107 
2108             FD_SET(fr->fd, &read_set);
2109 
2110             /* fall through */
2111 
2112         case STATE_CLIENT_SEND:
2113 
2114             if (client_send || ! BufferFree(fr->clientOutputBuffer))
2115             {
2116                 if (write_to_client(fr))
2117                 {
2118                     state = STATE_CLIENT_ERROR;
2119                     break;
2120                 }
2121 
2122                 client_send = 0;
2123 
2124                 if (fcgi_protocol_dequeue(rp, fr))
2125                 {
2126                     state = STATE_ERROR;
2127                     break;
2128                 }
2129             }
2130 
2131             break;
2132 
2133         case STATE_ERROR:
2134         case STATE_CLIENT_ERROR:
2135 
2136             break;
2137 
2138         default:
2139 
2140             ASSERT(0);
2141         }
2142 
2143         if (state == STATE_CLIENT_ERROR || state == STATE_ERROR)
2144         {
2145             break;
2146         }
2147 
2148         /* setup the io timeout */
2149 
2150         if (BufferLength(fr->clientOutputBuffer))
2151         {
2152             /* don't let client data sit too long, it might be a push */
2153             timeout.tv_sec = 0;
2154             timeout.tv_usec = 100000;
2155         }
2156         else if (dynamic_first_recv)
2157         {
2158             int delay;
2159             struct timeval qwait;
2160 
2161             fcgi_util_ticks(&fr->queueTime);
2162 
2163             if (select_status)
2164             {
2165                 /* a send() succeeded last pass */
2166                 dynamic_last_io_time = fr->queueTime;
2167             }
2168             else
2169             {
2170                 /* timed out last pass */
2171                 struct timeval idle_time;
2172 
2173                 timersub(&fr->queueTime, &dynamic_last_io_time, &idle_time);
2174 
2175                 if (idle_time.tv_sec > idle_timeout)
2176                 {
2177                     send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
2178                     ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r, "FastCGI: comm "
2179                         "with (dynamic) server \"%s\" aborted: (first read) "
2180                         "idle timeout (%d sec)", fr->fs_path, idle_timeout);
2181                     state = STATE_ERROR;
2182                     break;
2183                 }
2184             }
2185 
2186             timersub(&fr->queueTime, &fr->startTime, &qwait);
2187 
2188             delay = dynamic_first_recv * dynamicPleaseStartDelay;
2189 
2190 	    FCGIDBG5("qwait=%ld.%06ld delay=%d first_recv=%d", qwait.tv_sec, qwait.tv_usec, delay, dynamic_first_recv);
2191 
2192             if (qwait.tv_sec < delay)
2193             {
2194                 timeout.tv_sec = delay;
2195                 timeout.tv_usec = 100000;  /* fudge for select() slop */
2196                 timersub(&timeout, &qwait, &timeout);
2197             }
2198             else
2199             {
2200                 /* Killed time somewhere.. client read? */
2201                 send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
2202                 dynamic_first_recv = qwait.tv_sec / dynamicPleaseStartDelay + 1;
2203                 timeout.tv_sec = dynamic_first_recv * dynamicPleaseStartDelay;
2204                 timeout.tv_usec = 100000;  /* fudge for select() slop */
2205                 timersub(&timeout, &qwait, &timeout);
2206             }
2207         }
2208         else
2209         {
2210             timeout.tv_sec = idle_timeout;
2211             timeout.tv_usec = 0;
2212         }
2213 
2214         /* wait on the socket */
2215         do {
2216         select_status = ap_select(nfds, &read_set, &write_set, NULL, &timeout);
2217         } while (select_status < 0 && errno == EINTR);
2218 
2219         if (select_status < 0)
2220         {
2221             ap_log_rerror(FCGI_LOG_ERR_ERRNO, r, "FastCGI: comm with server "
2222                 "\"%s\" aborted: select() failed: \"%s\"", fr->fs_path, strerror(errno));
2223             state = STATE_ERROR;
2224             break;
2225         }
2226 
2227         if (select_status == 0)
2228         {
2229             /* select() timeout */
2230 
2231             if (BufferLength(fr->clientOutputBuffer))
2232             {
2233                 if (fr->role == FCGI_RESPONDER)
2234                 {
2235                     client_send = TRUE;
2236                 }
2237             }
2238             else if (dynamic_first_recv)
2239             {
2240                 struct timeval qwait;
2241 
2242                 fcgi_util_ticks(&fr->queueTime);
2243                 timersub(&fr->queueTime, &fr->startTime, &qwait);
2244 
2245                 send_to_pm(FCGI_REQUEST_TIMEOUT_JOB, fr->fs_path, fr->user, fr->group, 0, 0);
2246 
2247                 dynamic_first_recv = qwait.tv_sec / dynamicPleaseStartDelay + 1;
2248                 continue;
2249             }
2250             else
2251             {
2252                 ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r, "FastCGI: comm with "
2253                     "server \"%s\" aborted: idle timeout (%d sec)",
2254                     fr->fs_path, idle_timeout);
2255                 state = STATE_ERROR;
2256             }
2257         }
2258 
2259         if (FD_ISSET(fr->fd, &write_set))
2260         {
2261             /* send to the server */
2262 
2263             rv = fcgi_buf_socket_send(fr->serverOutputBuffer, fr->fd);
2264 
2265             if (rv < 0)
2266             {
2267                 ap_log_rerror(FCGI_LOG_ERR, r, "FastCGI: comm with server "
2268                     "\"%s\" aborted: write failed", fr->fs_path);
2269                 state = STATE_ERROR;
2270                 break;
2271             }
2272         }
2273 
2274         if (FD_ISSET(fr->fd, &read_set))
2275         {
2276             /* recv from the server */
2277 
2278             if (dynamic_first_recv)
2279             {
2280                 dynamic_first_recv = 0;
2281                 fcgi_util_ticks(&fr->queueTime);
2282             }
2283 
2284             rv = fcgi_buf_socket_recv(fr->serverInputBuffer, fr->fd);
2285 
2286             if (rv < 0)
2287             {
2288             	if (errno == EAGAIN)
2289             	{
2290                     /* this reportedly occurs on AIX 5.2 sporadically */
2291                     struct timeval tv;
2292                     tv.tv_sec = 1;
2293                     tv.tv_usec = 0;
2294 
2295             		ap_log_rerror(FCGI_LOG_INFO, r, "FastCGI: comm with server "
2296             				"\"%s\" interrupted: read will be retried in 1 second",
2297             				fr->fs_path);
2298 
2299                     /* avoid sleep/alarm interactions */
2300                     ap_select(0, NULL, NULL, NULL, &tv);
2301             	}
2302             	else
2303             	{
2304                 ap_log_rerror(FCGI_LOG_ERR, r, "FastCGI: comm with server "
2305                     "\"%s\" aborted: read failed: \"%s\"", fr->fs_path, strerror(errno));
2306                 state = STATE_ERROR;
2307                 break;
2308             }
2309             }
2310             else if (rv == 0)
2311             {
2312                 fr->keepReadingFromFcgiApp = FALSE;
2313                 state = STATE_CLIENT_SEND;
2314                 break;
2315             }
2316         }
2317 
2318         if (fcgi_protocol_dequeue(rp, fr))
2319         {
2320             state = STATE_ERROR;
2321             break;
2322         }
2323 
2324         if (fr->parseHeader == SCAN_CGI_READING_HEADERS)
2325         {
2326             const char * err = process_headers(r, fr);
2327             if (err)
2328             {
2329                 ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
2330                     "FastCGI: comm with server \"%s\" aborted: "
2331                     "error parsing headers: %s", fr->fs_path, err);
2332                 state = STATE_ERROR;
2333                 break;
2334             }
2335         }
2336 
2337         if (fr->exitStatusSet)
2338         {
2339             fr->keepReadingFromFcgiApp = FALSE;
2340             state = STATE_CLIENT_SEND;
2341             break;
2342         }
2343     }
2344 
2345     return (state == STATE_ERROR);
2346 }
2347 
2348 
2349 /*----------------------------------------------------------------------
2350  * This is the core routine for moving data between the FastCGI
2351  * application and the Web server's client.
2352  */
2353 static int do_work(request_rec * const r, fcgi_request * const fr)
2354 {
2355     int rv;
2356     pool *rp = r->pool;
2357 
2358     fcgi_protocol_queue_begin_request(fr);
2359 
2360     if (fr->role == FCGI_RESPONDER)
2361     {
2362         rv = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
2363         if (rv != OK)
2364         {
2365             ap_kill_timeout(r);
2366             return rv;
2367         }
2368 
2369         fr->expectingClientContent = ap_should_client_block(r);
2370     }
2371 
2372     ap_block_alarms();
2373     ap_register_cleanup(rp, (void *)fr, cleanup, ap_null_cleanup);
2374     ap_unblock_alarms();
2375 
2376 #ifdef WIN32
2377     if (fr->using_npipe_io)
2378     {
2379         rv = npipe_io(fr);
2380     }
2381     else
2382 #endif
2383     {
2384         rv = socket_io(fr);
2385     }
2386 
2387     /* comm with the server is done */
2388     close_connection_to_fs(fr);
2389 
2390     if (fr->role == FCGI_RESPONDER)
2391     {
2392         sink_client_data(fr);
2393     }
2394 
2395     while (rv == 0 && (BufferLength(fr->serverInputBuffer) || BufferLength(fr->clientOutputBuffer)))
2396     {
2397         if (fcgi_protocol_dequeue(rp, fr))
2398         {
2399             rv = HTTP_INTERNAL_SERVER_ERROR;
2400         }
2401 
2402         if (fr->parseHeader == SCAN_CGI_READING_HEADERS)
2403         {
2404             const char * err = process_headers(r, fr);
2405             if (err)
2406             {
2407                 ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
2408                     "FastCGI: comm with server \"%s\" aborted: "
2409                     "error parsing headers: %s", fr->fs_path, err);
2410                 rv = HTTP_INTERNAL_SERVER_ERROR;
2411             }
2412         }
2413 
2414         if (fr->role == FCGI_RESPONDER)
2415         {
2416             if (write_to_client(fr))
2417             {
2418                 break;
2419             }
2420         }
2421         else
2422         {
2423             fcgi_buf_reset(fr->clientOutputBuffer);
2424         }
2425     }
2426 
2427     switch (fr->parseHeader)
2428     {
2429     case SCAN_CGI_FINISHED:
2430 
2431         if (fr->role == FCGI_RESPONDER)
2432         {
2433             /* RUSSIAN_APACHE requires rflush() over bflush() */
2434             ap_rflush(r);
2435 #ifndef APACHE2
2436             ap_bgetopt(r->connection->client, BO_BYTECT, &r->bytes_sent);
2437 #endif
2438         }
2439 
2440         /* fall through */
2441 
2442     case SCAN_CGI_INT_REDIRECT:
2443     case SCAN_CGI_SRV_REDIRECT:
2444 
2445         break;
2446 
2447     case SCAN_CGI_READING_HEADERS:
2448 
2449         ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r, "FastCGI: incomplete headers "
2450             "(%d bytes) received from server \"%s\"", fr->header->nelts, fr->fs_path);
2451 
2452         /* fall through */
2453 
2454     case SCAN_CGI_BAD_HEADER:
2455 
2456         rv = HTTP_INTERNAL_SERVER_ERROR;
2457         break;
2458 
2459     default:
2460 
2461         ASSERT(0);
2462         rv = HTTP_INTERNAL_SERVER_ERROR;
2463     }
2464 
2465     ap_kill_timeout(r);
2466     return rv;
2467 }
2468 
2469 static int
2470 create_fcgi_request(request_rec * const r,
2471                     const char * const path,
2472                     fcgi_request ** const frP)
2473 {
2474     const char *fs_path;
2475     pool * const p = r->pool;
2476     fcgi_server *fs;
2477     fcgi_request * const fr = (fcgi_request *)ap_pcalloc(p, sizeof(fcgi_request));
2478     uid_t uid;
2479     gid_t gid;
2480 
2481     fs_path = path ? path : r->filename;
2482 
2483     get_request_identity(r, &uid, &gid);
2484 
2485     fs = fcgi_util_fs_get_by_id(fs_path, uid, gid);
2486 
2487     if (fs == NULL)
2488     {
2489         const char * err;
2490         struct stat *my_finfo;
2491 
2492         /* dynamic? */
2493 
2494 #ifndef APACHE2
2495         if (path == NULL)
2496         {
2497             /* AP2: its bogus that we don't make use of r->finfo, but
2498              * its an apr_finfo_t and there is no apr_os_finfo_get() */
2499 
2500             my_finfo = &r->finfo;
2501         }
2502         else
2503 #endif
2504         {
2505             my_finfo = (struct stat *) ap_palloc(p, sizeof(struct stat));
2506 
2507             if (stat(fs_path, my_finfo) < 0)
2508             {
2509                 ap_log_rerror(FCGI_LOG_ERR_ERRNO, r,
2510                     "FastCGI: stat() of \"%s\" failed", fs_path);
2511                 return HTTP_NOT_FOUND;
2512             }
2513         }
2514 
2515         err = fcgi_util_fs_is_path_ok(p, fs_path, my_finfo);
2516         if (err)
2517         {
2518             ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
2519                 "FastCGI: invalid (dynamic) server \"%s\": %s", fs_path, err);
2520             return HTTP_FORBIDDEN;
2521         }
2522     }
2523 
2524     fr->nph = (strncmp(strrchr(fs_path, '/'), "/nph-", 5) == 0)
2525 		|| (fs && fs->nph);
2526 
2527     fr->serverInputBuffer = fcgi_buf_new(p, SERVER_BUFSIZE);
2528     fr->serverOutputBuffer = fcgi_buf_new(p, SERVER_BUFSIZE);
2529     fr->clientInputBuffer = fcgi_buf_new(p, SERVER_BUFSIZE);
2530     fr->clientOutputBuffer = fcgi_buf_new(p, SERVER_BUFSIZE);
2531     fr->erBufPtr = fcgi_buf_new(p, sizeof(FCGI_EndRequestBody) + 1);
2532     fr->gotHeader = FALSE;
2533     fr->parseHeader = SCAN_CGI_READING_HEADERS;
2534     fr->header = ap_make_array(p, 1, 1);
2535     fr->fs_stderr = NULL;
2536     fr->r = r;
2537     fr->readingEndRequestBody = FALSE;
2538     fr->exitStatus = 0;
2539     fr->exitStatusSet = FALSE;
2540     fr->requestId = 1; /* anything but zero is OK here */
2541     fr->eofSent = FALSE;
2542     fr->role = FCGI_RESPONDER;
2543     fr->expectingClientContent = FALSE;
2544     fr->keepReadingFromFcgiApp = TRUE;
2545     fr->fs = fs;
2546     fr->fs_path = fs_path;
2547     fr->authHeaders = ap_make_table(p, 10);
2548 #ifdef WIN32
2549     fr->fd = INVALID_SOCKET;
2550     fr->dynamic = ((fs == NULL) || (fs->directive == APP_CLASS_DYNAMIC)) ? TRUE : FALSE;
2551     fr->using_npipe_io = (! fr->dynamic && (fs->dest_addr || fs->socket_addr)) ? 0 : 1;
2552 #else
2553     fr->dynamic = (fs == NULL) ? TRUE : FALSE;
2554     fr->fd = -1;
2555 #endif
2556 
2557     if (fr->nph) {
2558 #ifdef APACHE2
2559 	struct ap_filter_t *cur;
2560 
2561 	fr->parseHeader = SCAN_CGI_FINISHED;
2562 
2563 		/* remove the filters up through protocol - since the headers
2564 		 * haven't been parsed, there is no way they can work */
2565 
2566 	cur = r->proto_output_filters;
2567 	while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) {
2568 	    cur = cur->next;
2569 	}
2570 	r->output_filters = r->proto_output_filters = cur;
2571 #else
2572 	    ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
2573 	        "FastCGI: invalid request \"%s\": non parsed header support is "
2574 	    		"not available in Apache13 (patch welcome)", fs_path);
2575 	    return HTTP_FORBIDDEN;
2576 #endif
2577     }
2578 
2579     set_uid_n_gid(r, &fr->user, &fr->group);
2580 
2581     *frP = fr;
2582 
2583     return OK;
2584 }
2585 
2586 /*
2587  *----------------------------------------------------------------------
2588  *
2589  * handler --
2590  *
2591  *      This routine gets called for a request that corresponds to
2592  *      a FastCGI connection.  It performs the request synchronously.
2593  *
2594  * Results:
2595  *      Final status of request: OK or NOT_FOUND or HTTP_INTERNAL_SERVER_ERROR.
2596  *
2597  * Side effects:
2598  *      Request performed.
2599  *
2600  *----------------------------------------------------------------------
2601  */
2602 
2603 /* Stolen from mod_cgi.c..
2604  * KLUDGE --- for back-combatibility, we don't have to check ExecCGI
2605  * in ScriptAliased directories, which means we need to know if this
2606  * request came through ScriptAlias or not... so the Alias module
2607  * leaves a note for us.
2608  */
2609 static int apache_is_scriptaliased(request_rec *r)
2610 {
2611     const char *t = ap_table_get(r->notes, "alias-forced-type");
2612     return t && (!strcasecmp(t, "cgi-script"));
2613 }
2614 
2615 /* If a script wants to produce its own Redirect body, it now
2616  * has to explicitly *say* "Status: 302".  If it wants to use
2617  * Apache redirects say "Status: 200".  See process_headers().
2618  */
2619 static int post_process_for_redirects(request_rec * const r,
2620     const fcgi_request * const fr)
2621 {
2622     switch(fr->parseHeader) {
2623         case SCAN_CGI_INT_REDIRECT:
2624 
2625             /* @@@ There are still differences between the handling in
2626              * mod_cgi and mod_fastcgi.  This needs to be revisited.
2627              */
2628             /* We already read the message body (if any), so don't allow
2629              * the redirected request to think it has one.  We can ignore
2630              * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
2631              */
2632             r->method = "GET";
2633             r->method_number = M_GET;
2634             ap_table_unset(r->headers_in, "Content-length");
2635 
2636             ap_internal_redirect_handler(ap_table_get(r->headers_out, "Location"), r);
2637             return OK;
2638 
2639         case SCAN_CGI_SRV_REDIRECT:
2640             return HTTP_MOVED_TEMPORARILY;
2641 
2642         default:
2643 #ifdef APACHE2
2644 	        {
2645 	        	apr_bucket_brigade *brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2646 	        	apr_bucket* bucket = apr_bucket_eos_create(r->connection->bucket_alloc);
2647 	        	APR_BRIGADE_INSERT_HEAD(brigade, bucket);
2648 	        	return ap_pass_brigade(r->output_filters, brigade);
2649 	        }
2650 #else
2651             return OK;
2652 #endif
2653     }
2654 }
2655 
2656 /******************************************************************************
2657  * Process fastcgi-script requests.  Based on mod_cgi::cgi_handler().
2658  */
2659 static int content_handler(request_rec *r)
2660 {
2661     fcgi_request *fr = NULL;
2662     int ret;
2663 
2664 #ifdef APACHE2
2665     if (strcmp(r->handler, FASTCGI_HANDLER_NAME))
2666         return DECLINED;
2667 #endif
2668 
2669     /* Setup a new FastCGI request */
2670     ret = create_fcgi_request(r, NULL, &fr);
2671     if (ret)
2672     {
2673         return ret;
2674     }
2675 
2676     /* If its a dynamic invocation, make sure scripts are OK here */
2677     if (fr->dynamic && ! (ap_allow_options(r) & OPT_EXECCGI)
2678         && ! apache_is_scriptaliased(r))
2679     {
2680         ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
2681             "FastCGI: \"ExecCGI Option\" is off in this directory: %s", r->uri);
2682         return HTTP_FORBIDDEN;
2683     }
2684 
2685     /* Process the fastcgi-script request */
2686     if ((ret = do_work(r, fr)) != OK)
2687         return ret;
2688 
2689     /* Special case redirects */
2690     ret = post_process_for_redirects(r, fr);
2691 
2692     return ret;
2693 }
2694 
2695 
2696 static int post_process_auth_passed_header(table *t, const char *key, const char * const val)
2697 {
2698     if (strncasecmp(key, "Variable-", 9) == 0)
2699         key += 9;
2700 
2701     ap_table_setn(t, key, val);
2702     return 1;
2703 }
2704 
2705 static int post_process_auth_passed_compat_header(table *t, const char *key, const char * const val)
2706 {
2707     if (strncasecmp(key, "Variable-", 9) == 0)
2708         ap_table_setn(t, key + 9, val);
2709 
2710     return 1;
2711 }
2712 
2713 static int post_process_auth_failed_header(table * const t, const char * const key, const char * const val)
2714 {
2715     ap_table_setn(t, key, val);
2716     return 1;
2717 }
2718 
2719 static void post_process_auth(fcgi_request * const fr, const int passed)
2720 {
2721     request_rec * const r = fr->r;
2722 
2723     /* Restore the saved subprocess_env because we muddied ours up */
2724     r->subprocess_env = fr->saved_subprocess_env;
2725 
2726     if (passed) {
2727         if (fr->auth_compat) {
2728             ap_table_do((int (*)(void *, const char *, const char *))post_process_auth_passed_compat_header,
2729                  (void *)r->subprocess_env, fr->authHeaders, NULL);
2730         }
2731         else {
2732             ap_table_do((int (*)(void *, const char *, const char *))post_process_auth_passed_header,
2733                  (void *)r->subprocess_env, fr->authHeaders, NULL);
2734         }
2735     }
2736     else {
2737         ap_table_do((int (*)(void *, const char *, const char *))post_process_auth_failed_header,
2738              (void *)r->err_headers_out, fr->authHeaders, NULL);
2739     }
2740 
2741     /* @@@ Restore these.. its a hack until I rewrite the header handling */
2742     r->status = HTTP_OK;
2743     r->status_line = NULL;
2744 }
2745 
2746 static int check_user_authentication(request_rec *r)
2747 {
2748     int res, authenticated = 0;
2749     const char *password;
2750     fcgi_request *fr;
2751     const fcgi_dir_config * const dir_config =
2752         (const fcgi_dir_config *)ap_get_module_config(r->per_dir_config, &fastcgi_module);
2753 
2754     if (dir_config->authenticator == NULL)
2755         return DECLINED;
2756 
2757     /* Get the user password */
2758     if ((res = ap_get_basic_auth_pw(r, &password)) != OK)
2759         return res;
2760 
2761     res = create_fcgi_request(r, dir_config->authenticator, &fr);
2762     if (res)
2763     {
2764         return res;
2765     }
2766 
2767     /* Save the existing subprocess_env, because we're gonna muddy it up */
2768     fr->saved_subprocess_env = ap_copy_table(r->pool, r->subprocess_env);
2769 
2770     ap_table_setn(r->subprocess_env, "REMOTE_PASSWD", password);
2771     ap_table_setn(r->subprocess_env, "FCGI_APACHE_ROLE", "AUTHENTICATOR");
2772 
2773     /* The FastCGI Protocol doesn't differentiate authentication */
2774     fr->role = FCGI_AUTHORIZER;
2775 
2776     /* Do we need compatibility mode? */
2777     fr->auth_compat = (dir_config->authenticator_options & FCGI_COMPAT);
2778 
2779     if ((res = do_work(r, fr)) != OK)
2780         goto AuthenticationFailed;
2781 
2782     authenticated = (r->status == 200);
2783     post_process_auth(fr, authenticated);
2784 
2785     /* A redirect shouldn't be allowed during the authentication phase */
2786     if (ap_table_get(r->headers_out, "Location") != NULL) {
2787         ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
2788             "FastCGI: FastCgiAuthenticator \"%s\" redirected (not allowed)",
2789             dir_config->authenticator);
2790         goto AuthenticationFailed;
2791     }
2792 
2793     if (authenticated)
2794         return OK;
2795 
2796 AuthenticationFailed:
2797     if (!(dir_config->authenticator_options & FCGI_AUTHORITATIVE))
2798         return DECLINED;
2799 
2800     /* @@@ Probably should support custom_responses */
2801     ap_note_basic_auth_failure(r);
2802     ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
2803         "FastCGI: authentication failed for user \"%s\": %s",
2804 #ifdef APACHE2
2805         r->user, r->uri);
2806 #else
2807         r->connection->user, r->uri);
2808 #endif
2809 
2810         return (res == OK) ? HTTP_UNAUTHORIZED : res;
2811 }
2812 
2813 static int check_user_authorization(request_rec *r)
2814 {
2815     int res, authorized = 0;
2816     fcgi_request *fr;
2817     const fcgi_dir_config * const dir_config =
2818         (const fcgi_dir_config *)ap_get_module_config(r->per_dir_config, &fastcgi_module);
2819 
2820     if (dir_config->authorizer == NULL)
2821         return DECLINED;
2822 
2823     /* @@@ We should probably honor the existing parameters to the require directive
2824      * as well as allow the definition of new ones (or use the basename of the
2825      * FastCGI server and pass the rest of the directive line), but for now keep
2826      * it simple. */
2827 
2828     res = create_fcgi_request(r, dir_config->authorizer, &fr);
2829     if (res)
2830     {
2831         return res;
2832     }
2833 
2834     /* Save the existing subprocess_env, because we're gonna muddy it up */
2835     fr->saved_subprocess_env = ap_copy_table(r->pool, r->subprocess_env);
2836 
2837     ap_table_setn(r->subprocess_env, "FCGI_APACHE_ROLE", "AUTHORIZER");
2838 
2839     fr->role = FCGI_AUTHORIZER;
2840 
2841     /* Do we need compatibility mode? */
2842     fr->auth_compat = (dir_config->authorizer_options & FCGI_COMPAT);
2843 
2844     if ((res = do_work(r, fr)) != OK)
2845         goto AuthorizationFailed;
2846 
2847     authorized = (r->status == 200);
2848     post_process_auth(fr, authorized);
2849 
2850     /* A redirect shouldn't be allowed during the authorization phase */
2851     if (ap_table_get(r->headers_out, "Location") != NULL) {
2852         ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
2853             "FastCGI: FastCgiAuthorizer \"%s\" redirected (not allowed)",
2854             dir_config->authorizer);
2855         goto AuthorizationFailed;
2856     }
2857 
2858     if (authorized)
2859         return OK;
2860 
2861 AuthorizationFailed:
2862     if (!(dir_config->authorizer_options & FCGI_AUTHORITATIVE))
2863         return DECLINED;
2864 
2865     /* @@@ Probably should support custom_responses */
2866     ap_note_basic_auth_failure(r);
2867     ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
2868         "FastCGI: authorization failed for user \"%s\": %s",
2869 #ifdef APACHE2
2870         r->user, r->uri);
2871 #else
2872         r->connection->user, r->uri);
2873 #endif
2874 
2875     return (res == OK) ? HTTP_UNAUTHORIZED : res;
2876 }
2877 
2878 static int check_access(request_rec *r)
2879 {
2880     int res, access_allowed = 0;
2881     fcgi_request *fr;
2882     const fcgi_dir_config * const dir_config =
2883         (fcgi_dir_config *)ap_get_module_config(r->per_dir_config, &fastcgi_module);
2884 
2885     if (dir_config == NULL || dir_config->access_checker == NULL)
2886         return DECLINED;
2887 
2888     res = create_fcgi_request(r, dir_config->access_checker, &fr);
2889     if (res)
2890     {
2891         return res;
2892     }
2893 
2894     /* Save the existing subprocess_env, because we're gonna muddy it up */
2895     fr->saved_subprocess_env = ap_copy_table(r->pool, r->subprocess_env);
2896 
2897     ap_table_setn(r->subprocess_env, "FCGI_APACHE_ROLE", "ACCESS_CHECKER");
2898 
2899     /* The FastCGI Protocol doesn't differentiate access control */
2900     fr->role = FCGI_AUTHORIZER;
2901 
2902     /* Do we need compatibility mode? */
2903     fr->auth_compat = (dir_config->access_checker_options & FCGI_COMPAT);
2904 
2905     if ((res = do_work(r, fr)) != OK)
2906         goto AccessFailed;
2907 
2908     access_allowed = (r->status == 200);
2909     post_process_auth(fr, access_allowed);
2910 
2911     /* A redirect shouldn't be allowed during the access check phase */
2912     if (ap_table_get(r->headers_out, "Location") != NULL) {
2913         ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r,
2914             "FastCGI: FastCgiAccessChecker \"%s\" redirected (not allowed)",
2915             dir_config->access_checker);
2916         goto AccessFailed;
2917     }
2918 
2919     if (access_allowed)
2920         return OK;
2921 
2922 AccessFailed:
2923     if (!(dir_config->access_checker_options & FCGI_AUTHORITATIVE))
2924         return DECLINED;
2925 
2926     /* @@@ Probably should support custom_responses */
2927     ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r, "FastCGI: access denied: %s", r->uri);
2928     return (res == OK) ? HTTP_FORBIDDEN : res;
2929 }
2930 
2931 static int
2932 fixups(request_rec * r)
2933 {
2934     if (r->filename) {
2935     uid_t uid;
2936     gid_t gid;
2937 
2938     get_request_identity(r, &uid, &gid);
2939 
2940     if (fcgi_util_fs_get_by_id(r->filename, uid, gid))
2941     {
2942         r->handler = FASTCGI_HANDLER_NAME;
2943         return OK;
2944     }
2945     }
2946 
2947     return DECLINED;
2948 }
2949 
2950 #ifndef APACHE2
2951 
2952 # define AP_INIT_RAW_ARGS(directive, func, mconfig, where, help) \
2953     { directive, func, mconfig, where, RAW_ARGS, help }
2954 # define AP_INIT_TAKE1(directive, func, mconfig, where, help) \
2955     { directive, func, mconfig, where, TAKE1, help }
2956 # define AP_INIT_TAKE12(directive, func, mconfig, where, help) \
2957     { directive, func, mconfig, where, TAKE12, help }
2958 # define AP_INIT_FLAG(directive, func, mconfig, where, help) \
2959     { directive, func, mconfig, where, FLAG, help }
2960 
2961 #endif
2962 
2963 static const command_rec fastcgi_cmds[] =
2964 {
2965     AP_INIT_RAW_ARGS("AppClass",      fcgi_config_new_static_server, NULL, RSRC_CONF, NULL),
2966     AP_INIT_RAW_ARGS("FastCgiServer", fcgi_config_new_static_server, NULL, RSRC_CONF, NULL),
2967 
2968     AP_INIT_RAW_ARGS("ExternalAppClass",      fcgi_config_new_external_server, NULL, RSRC_CONF, NULL),
2969     AP_INIT_RAW_ARGS("FastCgiExternalServer", fcgi_config_new_external_server, NULL, RSRC_CONF, NULL),
2970 
2971     AP_INIT_TAKE1("FastCgiIpcDir", fcgi_config_set_socket_dir, NULL, RSRC_CONF, NULL),
2972 
2973     AP_INIT_TAKE1("FastCgiSuexec",  fcgi_config_set_wrapper, NULL, RSRC_CONF, NULL),
2974     AP_INIT_TAKE1("FastCgiWrapper", fcgi_config_set_wrapper, NULL, RSRC_CONF, NULL),
2975 
2976     AP_INIT_RAW_ARGS("FCGIConfig",    fcgi_config_set_config, NULL, RSRC_CONF, NULL),
2977     AP_INIT_RAW_ARGS("FastCgiConfig", fcgi_config_set_config, NULL, RSRC_CONF, NULL),
2978 
2979     AP_INIT_TAKE12("FastCgiAuthenticator", fcgi_config_new_auth_server,
2980         (void *)FCGI_AUTH_TYPE_AUTHENTICATOR, ACCESS_CONF,
2981         "a fastcgi-script path (absolute or relative to ServerRoot) followed by an optional -compat"),
2982     AP_INIT_FLAG("FastCgiAuthenticatorAuthoritative", fcgi_config_set_authoritative_slot,
2983         (void *)XtOffsetOf(fcgi_dir_config, authenticator_options), ACCESS_CONF,
2984         "Set to 'off' to allow authentication to be passed along to lower modules upon failure"),
2985 
2986     AP_INIT_TAKE12("FastCgiAuthorizer", fcgi_config_new_auth_server,
2987         (void *)FCGI_AUTH_TYPE_AUTHORIZER, ACCESS_CONF,
2988         "a fastcgi-script path (absolute or relative to ServerRoot) followed by an optional -compat"),
2989     AP_INIT_FLAG("FastCgiAuthorizerAuthoritative", fcgi_config_set_authoritative_slot,
2990         (void *)XtOffsetOf(fcgi_dir_config, authorizer_options), ACCESS_CONF,
2991         "Set to 'off' to allow authorization to be passed along to lower modules upon failure"),
2992 
2993     AP_INIT_TAKE12("FastCgiAccessChecker", fcgi_config_new_auth_server,
2994         (void *)FCGI_AUTH_TYPE_ACCESS_CHECKER, ACCESS_CONF,
2995         "a fastcgi-script path (absolute or relative to ServerRoot) followed by an optional -compat"),
2996     AP_INIT_FLAG("FastCgiAccessCheckerAuthoritative", fcgi_config_set_authoritative_slot,
2997         (void *)XtOffsetOf(fcgi_dir_config, access_checker_options), ACCESS_CONF,
2998         "Set to 'off' to allow access control to be passed along to lower modules upon failure"),
2999     { NULL }
3000 };
3001 
3002 #ifdef APACHE2
3003 
3004 static void register_hooks(apr_pool_t * p)
3005 {
3006     /* ap_hook_pre_config(x_pre_config, NULL, NULL, APR_HOOK_MIDDLE); */
3007     ap_hook_post_config(init_module, NULL, NULL, APR_HOOK_MIDDLE);
3008     ap_hook_child_init(fcgi_child_init, NULL, NULL, APR_HOOK_MIDDLE);
3009     ap_hook_handler(content_handler, NULL, NULL, APR_HOOK_MIDDLE);
3010     ap_hook_check_user_id(check_user_authentication, NULL, NULL, APR_HOOK_MIDDLE);
3011     ap_hook_access_checker(check_access, NULL, NULL, APR_HOOK_MIDDLE);
3012     ap_hook_auth_checker(check_user_authorization, NULL, NULL, APR_HOOK_MIDDLE);
3013     ap_hook_fixups(fixups, NULL, NULL, APR_HOOK_MIDDLE);
3014 }
3015 
3016 module AP_MODULE_DECLARE_DATA fastcgi_module =
3017 {
3018     STANDARD20_MODULE_STUFF,
3019     fcgi_config_create_dir_config,  /* per-directory config creator */
3020     NULL,                           /* dir config merger */
3021     NULL,                           /* server config creator */
3022     NULL,                           /* server config merger */
3023     fastcgi_cmds,                   /* command table */
3024     register_hooks,                 /* set up other request processing hooks */
3025 };
3026 
3027 #else /* !APACHE2 */
3028 
3029 handler_rec fastcgi_handlers[] = {
3030     { FCGI_MAGIC_TYPE, content_handler },
3031     { FASTCGI_HANDLER_NAME, content_handler },
3032     { NULL }
3033 };
3034 
3035 module MODULE_VAR_EXPORT fastcgi_module = {
3036     STANDARD_MODULE_STUFF,
3037     init_module,              /* initializer */
3038     fcgi_config_create_dir_config,    /* per-dir config creator */
3039     NULL,                      /* per-dir config merger (default: override) */
3040     NULL,                      /* per-server config creator */
3041     NULL,                      /* per-server config merger (default: override) */
3042     fastcgi_cmds,              /* command table */
3043     fastcgi_handlers,          /* [9] content handlers */
3044     NULL,                      /* [2] URI-to-filename translation */
3045     check_user_authentication, /* [5] authenticate user_id */
3046     check_user_authorization,  /* [6] authorize user_id */
3047     check_access,              /* [4] check access (based on src & http headers) */
3048     NULL,                      /* [7] check/set MIME type */
3049     fixups,                    /* [8] fixups */
3050     NULL,                      /* [10] logger */
3051     NULL,                      /* [3] header-parser */
3052     fcgi_child_init,           /* process initialization */
3053 #ifdef WIN32
3054     fcgi_child_exit,           /* process exit/cleanup */
3055 #else
3056     NULL,
3057 #endif
3058     NULL                       /* [1] post read-request handling */
3059 };
3060 
3061 #endif /* !APACHE2 */
3062