"Fossies" - the Fresh Open Source Software Archive

Member "mod_fastcgi-2.4.7-0910052141/mod_fastcgi.c" (10 Apr 2012, 92203 Bytes) of package /linux/www/apache_httpd_modules/old/mod_fastcgi-2.4.7-0910052141.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "mod_fastcgi.c": 2.4.6_vs_2.4.7-0910052141.

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