diff -wruN mod_fastcgi/CHANGES mod_fastcgi-SNAP-0910052141/CHANGES --- mod_fastcgi/CHANGES 2013-07-12 13:38:04.808874148 +0000 +++ mod_fastcgi-SNAP-0910052141/CHANGES 2009-09-29 00:34:10.000000000 +0000 @@ -1,3 +1,36 @@ +2.4.7 + + *) *nix: On graceful restart, send SIGTERM, then wait 2sec before + removing any unix domain sockets. Based on a patch by Bernd Wurst. + + *) Fix uid_t/gid_t compiler warnings. [Artur Zaprzala ] + + *) A few more EINTR fixes. [Artur Zaprzala ] + + *) Don't let the Content-Length header propagate on errors or across + redirects. [Artur Zaprzala ] + + *) Fix pass-header handling (prefix with HTTP_). Based on a patch by + [Christian Seiler ] + + *) Add an EOS bucket to the output filter chain. Based on a patch by + [Philipp Dunkel ] + + *) Handle EINTR and EAGAIN in places AIX stress testing revealed + issues. Based on a patch by [Rainer Jung ] + + *) Fix process spawning on WIN under Apache 2.2.9 (an incompatible + change was introduced in APR 1.3). Patch by + [Tom Donovan ] + + *) Allow duplicate Status, Location and ContentType headers + (consistent with mod_cgi). Based on a patch by + [Christian Seiler ] + + *) Fix a spurious idle timeout error that occurred under unique + application timing and response size conditions. Based on a + report and patch by [Joe Strout ] + 2.4.6 *) Fix a bug I introduced in 2.4.4 that broke dynamic application diff -wruN mod_fastcgi/docs/mod_fastcgi.html mod_fastcgi-SNAP-0910052141/docs/mod_fastcgi.html --- mod_fastcgi/docs/mod_fastcgi.html 2013-07-12 13:38:04.809873854 +0000 +++ mod_fastcgi-SNAP-0910052141/docs/mod_fastcgi.html 2008-09-22 00:28:56.000000000 +0000 @@ -1,6 +1,6 @@ - + Apache module mod_fastcgi @@ -391,9 +391,9 @@ <CODE><STRONG>-pass-header <EM>header</EM></STRONG> (none)</CODE> </DT> <DD> - The name of an HTTP Request Header to be passed in the <EM>request</EM> environment. This option makes + The name of a Request Header to be passed in the <EM>request</EM> environment. This option makes available the contents of headers which are normally not available (e.g. Authorization) to a CGI - environment. + environment. The passed header names are prefixed with "HTTP_" IAW the CGI specification. </DD> <DT> <CODE><STRONG>-port <EM>n</EM></STRONG> (none)</CODE> @@ -623,9 +623,9 @@ <CODE><STRONG>-pass-header <EM>header</EM></STRONG> (none)</CODE> </DT> <DD> - The name of an HTTP Request Header to be passed in the <EM>request</EM> environment. This option makes + The name of a Request Header to be passed in the <EM>request</EM> environment. This option makes available the contents of headers which are normally not available (e.g. Authorization) to a CGI - environment. + environment. The passed header names are prefixed with "HTTP_" IAW the CGI specification. </DD> <DT> <CODE><STRONG>-priority <EM>n</EM></STRONG> (0)</CODE> @@ -803,9 +803,9 @@ <CODE><STRONG>-pass-header <EM>header</EM></STRONG> (none)</CODE> </DT> <DD> - The name of an HTTP Request Header to be passed in the <EM>request</EM> environment. This option makes + The name of a Request Header to be passed in the <EM>request</EM> environment. This option makes available the contents of headers which are normally not available (e.g. Authorization) to a CGI - environment. + environment. The passed header names are prefixed with "HTTP_" IAW the CGI specification. </DD> <DT> <CODE><STRONG>-socket <EM>filename</EM></STRONG> (none)</CODE> diff -wruN mod_fastcgi/fcgi_config.c mod_fastcgi-SNAP-0910052141/fcgi_config.c --- mod_fastcgi/fcgi_config.c 2013-07-12 13:38:04.810873859 +0000 +++ mod_fastcgi-SNAP-0910052141/fcgi_config.c 2009-09-28 12:33:14.000000000 +0000 @@ -1,5 +1,5 @@ /* - * $Id: fcgi_config.c,v 1.53 2007/10/29 00:22:00 robs Exp $ + * $Id: fcgi_config.c,v 1.54 2009/09/28 12:33:14 robs Exp $ */ #define CORE_PRIVATE @@ -766,12 +766,12 @@ { if (s->group == NULL) { - s->group = ap_psprintf(tp, "#%ld", fcgi_util_get_server_gid(cmd->server)); + s->group = ap_psprintf(tp, "#%ld", (long) fcgi_util_get_server_gid(cmd->server)); } if (s->user == NULL) { - s->user = ap_psprintf(p, "#%ld", fcgi_util_get_server_uid(cmd->server)); + s->user = ap_psprintf(p, "#%ld", (long) fcgi_util_get_server_uid(cmd->server)); } s->uid = ap_uname2id(s->user); @@ -959,12 +959,12 @@ { if (s->group == NULL) { - s->group = ap_psprintf(tp, "#%ld", fcgi_util_get_server_gid(cmd->server)); + s->group = ap_psprintf(tp, "#%ld", (long) fcgi_util_get_server_gid(cmd->server)); } if (s->user == NULL) { - s->user = ap_psprintf(p, "#%ld", fcgi_util_get_server_uid(cmd->server)); + s->user = ap_psprintf(p, "#%ld", (long) fcgi_util_get_server_uid(cmd->server)); } s->uid = ap_uname2id(s->user); diff -wruN mod_fastcgi/fcgi.h mod_fastcgi-SNAP-0910052141/fcgi.h --- mod_fastcgi/fcgi.h 2013-07-12 13:38:04.810873859 +0000 +++ mod_fastcgi-SNAP-0910052141/fcgi.h 2008-09-22 10:36:06.000000000 +0000 @@ -1,5 +1,5 @@ /* - * $Id: fcgi.h,v 1.47 2007/09/23 16:33:29 robs Exp $ + * $Id: fcgi.h,v 1.48 2008/09/22 10:36:06 robs Exp $ */ #ifndef FCGI_H @@ -81,6 +81,7 @@ #define ap_copy_table apr_table_copy #define ap_cpystrn apr_cpystrn #define ap_destroy_pool apr_pool_destroy +#define ap_isalnum apr_isalnum #define ap_isspace apr_isspace #define ap_make_array apr_array_make #define ap_make_table apr_table_make @@ -100,6 +101,7 @@ #define ap_table_set apr_table_set #define ap_table_setn apr_table_setn #define ap_table_unset apr_table_unset +#define ap_toupper apr_toupper #endif /* defined(ap_copy_table) */ diff -wruN mod_fastcgi/fcgi_pm.c mod_fastcgi-SNAP-0910052141/fcgi_pm.c --- mod_fastcgi/fcgi_pm.c 2013-07-12 13:38:04.810873859 +0000 +++ mod_fastcgi-SNAP-0910052141/fcgi_pm.c 2009-09-29 00:34:10.000000000 +0000 @@ -1,5 +1,5 @@ /* - * $Id: fcgi_pm.c,v 1.93 2004/04/15 02:01:26 robs Exp $ + * $Id: fcgi_pm.c,v 1.96 2009/09/29 00:34:10 robs Exp $ */ @@ -32,6 +32,7 @@ #ifdef WIN32 #ifdef APACHE2 #include "mod_cgi.h" +#include "apr_version.h" #endif #pragma warning ( disable : 4100 4102 ) static BOOL bTimeToDie = FALSE; /* process termination flag */ @@ -129,7 +130,34 @@ ? dynamicMaxClassProcs : s->numProcesses; + /* Send TERM to all processes */ + for (i = 0; i < numChildren; i++, proc++) + { + if (proc->state == FCGI_RUNNING_STATE) + { + fcgi_kill(proc, SIGTERM); + } + } + + s = s->next; + } + #ifndef WIN32 + + s = fcgi_servers; + while (s) + { + if (s->socket_path != NULL && s->directive != APP_CLASS_EXTERNAL) + { + struct timeval tv; + + /* sleep two seconds to let the children terminate themselves */ + tv.tv_sec = 2; + tv.tv_usec = 0; + ap_select(0, NULL, NULL, NULL, &tv); + + while (s) + { if (s->socket_path != NULL && s->directive != APP_CLASS_EXTERNAL) { /* Remove the socket file */ @@ -140,20 +168,18 @@ (s->directive == APP_CLASS_DYNAMIC) ? " (dynamic)" : "", s->fs_path); } } -#endif - /* Send TERM to all processes */ - for (i = 0; i < numChildren; i++, proc++) - { - if (proc->state == FCGI_RUNNING_STATE) - { - fcgi_kill(proc, SIGTERM); + s = s->next; } + + break; } s = s->next; } +#endif + #if defined(WIN32) && (WIN32_SHUTDOWN_GRACEFUL_WAIT > 0) /* @@ -559,6 +585,11 @@ if (apr_os_file_put(&file, &listen_handle, 0, tp)) goto CLEANUP; +#if (APR_MAJOR_VERSION >= 1) && (APR_MINOR_VERSION >= 3) + if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_NO_FILE, APR_NO_FILE)) + goto CLEANUP; +#endif + /* procattr is opaque so we have to use this - unfortuantely it dups */ if (apr_procattr_child_in_set(procattr, file, NULL)) goto CLEANUP; diff -wruN mod_fastcgi/fcgi_protocol.c mod_fastcgi-SNAP-0910052141/fcgi_protocol.c --- mod_fastcgi/fcgi_protocol.c 2013-07-12 13:38:04.811873775 +0000 +++ mod_fastcgi-SNAP-0910052141/fcgi_protocol.c 2008-09-23 14:48:13.000000000 +0000 @@ -1,5 +1,5 @@ /* - * $Id: fcgi_protocol.c,v 1.25 2003/02/03 22:59:01 robs Exp $ + * $Id: fcgi_protocol.c,v 1.27 2008/09/23 14:48:13 robs Exp $ */ #include "fcgi.h" @@ -169,6 +169,32 @@ } } +/* copied from util_script.c */ +static char *http2env(pool *a, const char *w) +{ + char *res = (char *) ap_palloc(a, sizeof("HTTP_") + strlen(w)); + char *cp = res; + char c; + + *cp++ = 'H'; + *cp++ = 'T'; + *cp++ = 'T'; + *cp++ = 'P'; + *cp++ = '_'; + + while ((c = *w++) != 0) { + if (!ap_isalnum(c)) { + *cp++ = '_'; + } + else { + *cp++ = (char) ap_toupper(c); + } + } + *cp = 0; + + return res; +} + static void add_pass_header_vars(fcgi_request *fr) { const array_header *ph = fr->dynamic ? dynamic_pass_headers : fr->fs->pass_headers; @@ -180,7 +206,11 @@ for ( ; i; --i, ++elt) { const char *val = ap_table_get(fr->r->headers_in, *elt); if (val) { - ap_table_setn(fr->r->subprocess_env, *elt, val); + const char *key = *elt; +#ifndef USE_BROKEN_PASS_HEADER + key = http2env(fr->r->pool, key); +#endif + ap_table_setn(fr->r->subprocess_env, key, val); } } } diff -wruN mod_fastcgi/mod_fastcgi.c mod_fastcgi-SNAP-0910052141/mod_fastcgi.c --- mod_fastcgi/mod_fastcgi.c 2013-07-12 13:38:04.812873837 +0000 +++ mod_fastcgi-SNAP-0910052141/mod_fastcgi.c 2008-11-09 14:31:03.000000000 +0000 @@ -3,7 +3,7 @@ * * Apache server module for FastCGI. * - * $Id: mod_fastcgi.c,v 1.162 2007/11/12 23:00:10 robs Exp $ + * $Id: mod_fastcgi.c,v 1.169 2008/11/09 14:31:03 robs Exp $ * * Copyright (c) 1995-1996 Open Market, Inc. * @@ -647,7 +647,7 @@ { char *p, *next, *name, *value; int len, flag; - int hasContentType, hasStatus, hasLocation; + int hasLocation = FALSE; ASSERT(fr->parseHeader == SCAN_CGI_READING_HEADERS); @@ -689,7 +689,6 @@ * Parse all the headers. */ fr->parseHeader = SCAN_CGI_FINISHED; - hasContentType = hasStatus = hasLocation = FALSE; next = (char *)fr->header->elts; for(;;) { next = get_header_line(name = next, TRUE); @@ -718,14 +717,10 @@ if (strcasecmp(name, "Status") == 0) { int statusValue = strtol(value, NULL, 10); - if (hasStatus) { - goto DuplicateNotAllowed; - } if (statusValue < 0) { fr->parseHeader = SCAN_CGI_BAD_HEADER; return ap_psprintf(r->pool, "invalid Status '%s'", value); } - hasStatus = TRUE; r->status = statusValue; r->status_line = ap_pstrdup(r->pool, value); continue; @@ -733,10 +728,6 @@ if (fr->role == FCGI_RESPONDER) { if (strcasecmp(name, "Content-type") == 0) { - if (hasContentType) { - goto DuplicateNotAllowed; - } - hasContentType = TRUE; #ifdef APACHE2 ap_set_content_type(r, value); #else @@ -745,12 +736,20 @@ continue; } + /* + * Special case headers that should not persist on error + * or across redirects, i.e. use headers_out rather than + * err_headers_out. + */ + if (strcasecmp(name, "Location") == 0) { - if (hasLocation) { - goto DuplicateNotAllowed; - } hasLocation = TRUE; - ap_table_set(r->headers_out, "Location", value); + ap_table_set(r->headers_out, name, value); + continue; + } + + if (strcasecmp(name, "Content-Length") == 0) { + ap_table_set(r->headers_out, name, value); continue; } @@ -841,10 +840,6 @@ *p = '\0'; fr->parseHeader = SCAN_CGI_BAD_HEADER; return ap_psprintf(r->pool, "malformed header '%s'", name); - -DuplicateNotAllowed: - fr->parseHeader = SCAN_CGI_BAD_HEADER; - return ap_psprintf(r->pool, "duplicate header '%s'", name); } /* @@ -1387,8 +1382,11 @@ } /* Connect */ - if (connect(fr->fd, (struct sockaddr *)socket_addr, socket_addr_len) == 0) + do { + if (connect(fr->fd, (struct sockaddr *) socket_addr, socket_addr_len) == 0) { goto ConnectionComplete; + } + } while (errno == EINTR); #ifdef WIN32 @@ -1432,7 +1430,10 @@ tval.tv_sec = dynamicPleaseStartDelay; tval.tv_usec = 0; - status = ap_select((fr->fd+1), &read_fds, &write_fds, NULL, &tval); + do { + status = ap_select(fr->fd + 1, &read_fds, &write_fds, NULL, &tval); + } while (status < 0 && errno == EINTR); + if (status < 0) break; @@ -1461,7 +1462,9 @@ FD_SET(fr->fd, &write_fds); read_fds = write_fds; - status = ap_select((fr->fd+1), &read_fds, &write_fds, NULL, &tval); + do { + status = ap_select(fr->fd + 1, &read_fds, &write_fds, NULL, &tval); + } while (status < 0 && errno == EINTR); if (status == 0) { ap_log_rerror(FCGI_LOG_ERR_NOERRNO, r, @@ -1762,6 +1765,12 @@ } client_send = 0; + + if (fcgi_protocol_dequeue(rp, fr)) + { + state = STATE_ERROR; + break; + } } break; @@ -2107,6 +2116,12 @@ } client_send = 0; + + if (fcgi_protocol_dequeue(rp, fr)) + { + state = STATE_ERROR; + break; + } } break; @@ -2193,7 +2208,9 @@ } /* wait on the socket */ + do { select_status = ap_select(nfds, &read_set, &write_set, NULL, &timeout); + } while (select_status < 0 && errno == EINTR); if (select_status < 0) { @@ -2264,13 +2281,29 @@ if (rv < 0) { + if (errno == EAGAIN) + { + /* this reportedly occurs on AIX 5.2 sporadically */ + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + + ap_log_rerror(FCGI_LOG_INFO, r, "FastCGI: comm with server " + "\"%s\" interrupted: read will be retried in 1 second", + fr->fs_path); + + /* avoid sleep/alarm interactions */ + ap_select(0, NULL, NULL, NULL, &tv); + } + else + { ap_log_rerror(FCGI_LOG_ERR, r, "FastCGI: comm with server " "\"%s\" aborted: read failed", fr->fs_path); state = STATE_ERROR; break; } - - if (rv == 0) + } + else if (rv == 0) { fr->keepReadingFromFcgiApp = FALSE; state = STATE_CLIENT_SEND; @@ -2603,7 +2636,16 @@ return HTTP_MOVED_TEMPORARILY; default: +#ifdef APACHE2 + { + apr_bucket_brigade *brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc); + apr_bucket* bucket = apr_bucket_eos_create(r->connection->bucket_alloc); + APR_BRIGADE_INSERT_HEAD(brigade, bucket); + return ap_pass_brigade(r->output_filters, brigade); + } +#else return OK; +#endif } } diff -wruN mod_fastcgi/mod_fastcgi.h mod_fastcgi-SNAP-0910052141/mod_fastcgi.h --- mod_fastcgi/mod_fastcgi.h 2013-07-12 13:38:04.812873837 +0000 +++ mod_fastcgi-SNAP-0910052141/mod_fastcgi.h 2013-07-12 13:56:23.086895013 +0000 @@ -1,5 +1,5 @@ /* - * $Id: mod_fastcgi.h,v 1.53 2007/11/13 12:26:35 robs Exp $ + * $Id: mod_fastcgi.h,v 1.55 2009/09/29 00:31:55 robs Exp $ */ #ifndef MOD_FASTCGI_H @@ -28,7 +28,7 @@ * If all of the applications are based on a version of the FastCGI * application library that properly handles the shutdown event * (fcgi2 v2.2.4), this can be set to <= 0 to prevent the use of - * TerminateProcess() entirely. If non of the applications support the + * TerminateProcess() entirely. If none of the applications support the * termination event, this value can be set to 1. It is highly reccomended * that the termination event be supported, as TerminateProcess() is a * brutal way of taking down an application.