Skip to content

Commit b5cd968

Browse files
committed
- Removed source compatibility with libfcgi
- Optimized access to FastCGI environment using HashTable instead of linear search - Allowed PHP_FCGI_MAX_REQUESTS=0 to disable PHP die - Allowed PHP_FCGI_CHILDREN=0 to disable PHP spawn workers
1 parent 7975b4e commit b5cd968

File tree

3 files changed

+152
-227
lines changed

3 files changed

+152
-227
lines changed

sapi/cgi/cgi_main.c

+84-79
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
| Zeev Suraski <zeev@zend.com> |
1818
| FastCGI: Ben Mansell <php@slimyhorror.com> |
1919
| Shane Caraveo <shane@caraveo.com> |
20+
| Dmitry Stogov <dmitry@zend.com> |
2021
+----------------------------------------------------------------------+
2122
*/
2223

@@ -81,9 +82,8 @@ int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS;
8182

8283
#if PHP_FASTCGI
8384
#include "fastcgi.h"
84-
#ifdef PHP_WIN32
85-
extern int OS_SetImpersonate(void);
86-
#else
85+
86+
#ifndef PHP_WIN32
8787
/* XXX this will need to change later when threaded fastcgi is
8888
implemented. shane */
8989
struct sigaction act, old_term, old_quit, old_int;
@@ -234,9 +234,9 @@ static inline size_t sapi_cgibin_single_write(const char *str, uint str_length T
234234
#endif
235235

236236
#if PHP_FASTCGI
237-
if (!FCGX_IsCGI()) {
238-
FCGX_Request *request = (FCGX_Request *) SG(server_context);
239-
long ret = FCGX_PutStr(str, str_length, request->out);
237+
if (fcgi_is_fastcgi()) {
238+
fcgi_request *request = (fcgi_request*) SG(server_context);
239+
long ret = fcgi_write(request, FCGI_STDOUT, str, str_length);
240240
if (ret <= 0) {
241241
return 0;
242242
}
@@ -276,13 +276,13 @@ static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
276276
static void sapi_cgibin_flush(void *server_context)
277277
{
278278
#if PHP_FASTCGI
279-
if (!FCGX_IsCGI()) {
280-
FCGX_Request *request = (FCGX_Request *) server_context;
279+
if (fcgi_is_fastcgi()) {
280+
fcgi_request *request = (fcgi_request*) server_context;
281281
if (
282282
#ifndef PHP_WIN32
283283
!parent &&
284284
#endif
285-
request && FCGX_FFlush(request->out) == -1) {
285+
request && fcgi_flush(request, 0) == -1) {
286286
php_handle_aborted_connection();
287287
}
288288
return;
@@ -349,9 +349,9 @@ static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
349349
count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
350350
while (read_bytes < count_bytes) {
351351
#if PHP_FASTCGI
352-
if (!FCGX_IsCGI()) {
353-
FCGX_Request *request = (FCGX_Request *) SG(server_context);
354-
tmp_read_bytes = FCGX_GetStr(pos, count_bytes - read_bytes, request->in);
352+
if (fcgi_is_fastcgi()) {
353+
fcgi_request *request = (fcgi_request*) SG(server_context);
354+
tmp_read_bytes = fcgi_read(request, pos, count_bytes - read_bytes);
355355
pos += tmp_read_bytes;
356356
} else {
357357
tmp_read_bytes = read(0, buffer + read_bytes, count_bytes - read_bytes);
@@ -375,9 +375,9 @@ static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
375375
is provided to PHP. It is always sent to PHP at the start
376376
of a request. So we have to do our own lookup to get env
377377
vars. This could probably be faster somehow. */
378-
if (!FCGX_IsCGI()) {
379-
FCGX_Request *request = (FCGX_Request *) SG(server_context);
380-
return FCGX_GetParam(name,request->envp);
378+
if (fcgi_is_fastcgi()) {
379+
fcgi_request *request = (fcgi_request*) SG(server_context);
380+
return fcgi_getenv(request, name, name_len);
381381
}
382382
#endif
383383
/* if cgi, or fastcgi and not found in fcgi env
@@ -387,45 +387,47 @@ static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
387387

388388
static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC)
389389
{
390-
int len = 0;
391-
char *buf = NULL;
390+
int name_len;
391+
int len;
392+
char *buf;
393+
392394
if (!name) {
393395
return NULL;
394396
}
395-
len = strlen(name) + (value ? strlen(value) : 0) + sizeof("=") + 2;
396-
buf = (char *) malloc(len);
397-
if (buf == NULL) {
398-
return getenv(name);
399-
}
400-
if (value) {
401-
snprintf(buf, len - 1, "%s=%s", name, value);
402-
} else {
403-
snprintf(buf, len - 1, "%s=", name);
404-
}
397+
name_len = strlen(name);
398+
405399
#if PHP_FASTCGI
406400
/* when php is started by mod_fastcgi, no regular environment
407401
is provided to PHP. It is always sent to PHP at the start
408402
of a request. So we have to do our own lookup to get env
409403
vars. This could probably be faster somehow. */
410-
if (!FCGX_IsCGI()) {
411-
FCGX_Request *request = (FCGX_Request *) SG(server_context);
412-
FCGX_PutEnv(request, buf);
413-
free(buf);
414-
return sapi_cgibin_getenv(name,0 TSRMLS_CC);
404+
if (fcgi_is_fastcgi()) {
405+
fcgi_request *request = (fcgi_request*) SG(server_context);
406+
return fcgi_putenv(request, name, name_len, value);
415407
}
416408
#endif
417409
/* if cgi, or fastcgi and not found in fcgi env
418410
check the regular environment
419411
this leaks, but it's only cgi anyway, we'll fix
420412
it for 5.0
421413
*/
414+
len = name_len + (value ? strlen(value) : 0) + sizeof("=") + 2;
415+
buf = (char *) malloc(len);
416+
if (buf == NULL) {
417+
return getenv(name);
418+
}
419+
if (value) {
420+
len = snprintf(buf, len - 1, "%s=%s", name, value);
421+
} else {
422+
len = snprintf(buf, len - 1, "%s=", name);
423+
}
422424
putenv(buf);
423425
return getenv(name);
424426
}
425427

426428
static char *sapi_cgi_read_cookies(TSRMLS_D)
427429
{
428-
return sapi_cgibin_getenv((char *) "HTTP_COOKIE", 0 TSRMLS_CC);
430+
return sapi_cgibin_getenv((char *) "HTTP_COOKIE", sizeof("HTTP_COOKIE")-1 TSRMLS_CC);
429431
}
430432

431433
#if PHP_FASTCGI
@@ -446,21 +448,21 @@ void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
446448
zval_copy_ctor(array_ptr);
447449
return;
448450
}
449-
if (!FCGX_IsCGI()) {
450-
FCGX_Request *request = (FCGX_Request *) SG(server_context);
451-
char **env, *p;
451+
if (fcgi_is_fastcgi()) {
452+
fcgi_request *request = (fcgi_request*) SG(server_context);
453+
HashPosition pos;
452454
int magic_quotes_gpc = PG(magic_quotes_gpc);
455+
char *var, **val;
456+
uint var_len;
457+
ulong idx;
453458

454459
/* turn off magic_quotes while importing environment variables */
455460
PG(magic_quotes_gpc) = 0;
456-
for (env = request->envp; env != NULL && *env != NULL; env++) {
457-
p = strchr(*env, '=');
458-
if (!p) { /* malformed entry? */
459-
continue;
460-
}
461-
*p = 0;
462-
php_register_variable(*env, p + 1, array_ptr TSRMLS_CC);
463-
*p = '=';
461+
for (zend_hash_internal_pointer_reset_ex(&request->env, &pos);
462+
zend_hash_get_current_key_ex(&request->env, &var, &var_len, &idx, 0, &pos) == HASH_KEY_IS_STRING &&
463+
zend_hash_get_current_data_ex(&request->env, (void **) &val, &pos) == SUCCESS;
464+
zend_hash_move_forward_ex(&request->env, &pos)) {
465+
php_register_variable(var, *val, array_ptr TSRMLS_CC);
464466
}
465467
PG(magic_quotes_gpc) = magic_quotes_gpc;
466468
}
@@ -482,13 +484,21 @@ static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
482484
static void sapi_cgi_log_message(char *message)
483485
{
484486
#if PHP_FASTCGI
485-
if (!FCGX_IsCGI() && fcgi_logging) {
486-
FCGX_Request *request;
487+
if (fcgi_is_fastcgi() && fcgi_logging) {
488+
fcgi_request *request;
487489
TSRMLS_FETCH();
488490

489-
request = (FCGX_Request *) SG(server_context);
490-
if (request) {
491-
FCGX_FPrintF(request->err, "%s\n", message);
491+
request = (fcgi_request*) SG(server_context);
492+
if (request) {
493+
int len = strlen(message);
494+
char *buf = malloc(len+2);
495+
496+
memcpy(buf, message, len);
497+
memcpy(buf + len, "\n", sizeof("\n"));
498+
fcgi_write(request, FCGI_STDERR, buf, len+1);
499+
free(buf);
500+
} else {
501+
fprintf(stderr, "%s\n", message);
492502
}
493503
/* ignore return code */
494504
} else
@@ -663,8 +673,8 @@ static void php_cgi_usage(char *argv0)
663673
*/
664674
static void init_request_info(TSRMLS_D)
665675
{
666-
char *env_script_filename = sapi_cgibin_getenv("SCRIPT_FILENAME", 0 TSRMLS_CC);
667-
char *env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED", 0 TSRMLS_CC);
676+
char *env_script_filename = sapi_cgibin_getenv("SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1 TSRMLS_CC);
677+
char *env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED", sizeof("PATH_TRANSLATED")-1 TSRMLS_CC);
668678
char *script_path_translated = env_script_filename;
669679

670680
#if !DISCARD_PATH
@@ -692,14 +702,14 @@ static void init_request_info(TSRMLS_D)
692702
of the script will be retreived later via argc/argv */
693703
if (script_path_translated) {
694704
const char *auth;
695-
char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH", 0 TSRMLS_CC);
696-
char *content_type = sapi_cgibin_getenv("CONTENT_TYPE", 0 TSRMLS_CC);
697-
char *env_path_info = sapi_cgibin_getenv("PATH_INFO", 0 TSRMLS_CC);
698-
char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME", 0 TSRMLS_CC);
705+
char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1 TSRMLS_CC);
706+
char *content_type = sapi_cgibin_getenv("CONTENT_TYPE", sizeof("CONTENT_TYPE")-1 TSRMLS_CC);
707+
char *env_path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
708+
char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
699709
#if ENABLE_PATHINFO_CHECK
700710
struct stat st;
701-
char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL", 0 TSRMLS_CC);
702-
char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT", 0 TSRMLS_CC);
711+
char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL", sizeof("REDIRECT_URL")-1 TSRMLS_CC);
712+
char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")-1 TSRMLS_CC);
703713

704714
if (fix_pathinfo) {
705715

@@ -849,7 +859,7 @@ static void init_request_info(TSRMLS_D)
849859
_sapi_cgibin_putenv("PATH_INFO", NULL TSRMLS_CC);
850860
_sapi_cgibin_putenv("PATH_TRANSLATED", NULL TSRMLS_CC);
851861
}
852-
SG(request_info).request_uri = sapi_cgibin_getenv("SCRIPT_NAME",0 TSRMLS_CC);
862+
SG(request_info).request_uri = sapi_cgibin_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
853863
} else {
854864
#endif
855865
/* pre 4.3 behaviour, shouldn't be used but provides BC */
@@ -865,9 +875,9 @@ static void init_request_info(TSRMLS_D)
865875
#if ENABLE_PATHINFO_CHECK
866876
}
867877
#endif
868-
SG(request_info).request_method = sapi_cgibin_getenv("REQUEST_METHOD", 0 TSRMLS_CC);
878+
SG(request_info).request_method = sapi_cgibin_getenv("REQUEST_METHOD", sizeof("REQUEST_METHOD")-1 TSRMLS_CC);
869879
/* FIXME - Work out proto_num here */
870-
SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", 0 TSRMLS_CC);
880+
SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", sizeof("QUERY_STRING")-1 TSRMLS_CC);
871881
/* some server configurations allow '..' to slip through in the
872882
translated path. We'll just refuse to handle such a path. */
873883
if (script_path_translated && !strstr(script_path_translated, "..")) {
@@ -877,7 +887,7 @@ static void init_request_info(TSRMLS_D)
877887
SG(request_info).content_length = (content_length ? atoi(content_length) : 0);
878888

879889
/* The CGI RFC allows servers to pass on unvalidated Authorization data */
880-
auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION",0 TSRMLS_CC);
890+
auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION")-1 TSRMLS_CC);
881891
php_handle_auth_data(auth TSRMLS_CC);
882892
}
883893
}
@@ -984,12 +994,12 @@ int main(int argc, char *argv[])
984994
#if PHP_FASTCGI
985995
int max_requests = 500;
986996
int requests = 0;
987-
int fastcgi = !FCGX_IsCGI();
997+
int fastcgi = fcgi_is_fastcgi();
988998
#ifndef PHP_WIN32
989999
char *bindpath = NULL;
9901000
#endif
9911001
int fcgi_fd = 0;
992-
FCGX_Request request;
1002+
fcgi_request request;
9931003
#ifdef PHP_WIN32
9941004
long impersonate = 0;
9951005
#else
@@ -1169,25 +1179,21 @@ consult the installation file that came with this distribution, or visit \n\
11691179
/* for windows, socket listening is broken in the fastcgi library itself
11701180
so dissabling this feature on windows till time is available to fix it */
11711181
if (bindpath) {
1172-
/* this must be done to make FCGX_OpenSocket work correctly
1173-
bug 23664 */
1174-
close(0);
11751182
/* Pass on the arg to the FastCGI library, with one exception.
11761183
* If just a port is specified, then we prepend a ':' onto the
11771184
* path (it's what the fastcgi library expects)
1178-
*/
1179-
1185+
*/
11801186
if (strchr(bindpath, ':') == NULL && is_port_number(bindpath)) {
11811187
char *tmp;
11821188

11831189
tmp = malloc(strlen(bindpath) + 2);
11841190
tmp[0] = ':';
11851191
memcpy(tmp + 1, bindpath, strlen(bindpath) + 1);
11861192

1187-
fcgi_fd = FCGX_OpenSocket(tmp, 128);
1193+
fcgi_fd = fcgi_listen(tmp, 128);
11881194
free(tmp);
11891195
} else {
1190-
fcgi_fd = FCGX_OpenSocket(bindpath, 128);
1196+
fcgi_fd = fcgi_listen(bindpath, 128);
11911197
}
11921198
if (fcgi_fd < 0) {
11931199
fprintf(stderr, "Couldn't create FastCGI listen socket on port %s\n", bindpath);
@@ -1196,14 +1202,14 @@ consult the installation file that came with this distribution, or visit \n\
11961202
#endif
11971203
return FAILURE;
11981204
}
1199-
fastcgi = !FCGX_IsCGI();
1205+
fastcgi = fcgi_is_fastcgi();
12001206
}
12011207
#endif
12021208
if (fastcgi) {
12031209
/* How many times to run PHP scripts before dying */
12041210
if (getenv("PHP_FCGI_MAX_REQUESTS")) {
12051211
max_requests = atoi(getenv("PHP_FCGI_MAX_REQUESTS"));
1206-
if (!max_requests) {
1212+
if (max_requests < 0) {
12071213
fprintf(stderr, "PHP_FCGI_MAX_REQUESTS is not valid\n");
12081214
return FAILURE;
12091215
}
@@ -1214,14 +1220,13 @@ consult the installation file that came with this distribution, or visit \n\
12141220
php_import_environment_variables = cgi_php_import_environment_variables;
12151221

12161222
/* library is already initialized, now init our request */
1217-
FCGX_Init();
1218-
FCGX_InitRequest(&request, fcgi_fd, 0);
1223+
fcgi_init_request(&request, fcgi_fd);
12191224

12201225
#ifndef PHP_WIN32
12211226
/* Pre-fork, if required */
12221227
if (getenv("PHP_FCGI_CHILDREN")) {
12231228
children = atoi(getenv("PHP_FCGI_CHILDREN"));
1224-
if (!children) {
1229+
if (children < 0) {
12251230
fprintf(stderr, "PHP_FCGI_CHILDREN is not valid\n");
12261231
return FAILURE;
12271232
}
@@ -1323,10 +1328,10 @@ consult the installation file that came with this distribution, or visit \n\
13231328
if (cfg_get_long("fastcgi.impersonate", &impersonate) == FAILURE) {
13241329
impersonate = 0;
13251330
}
1326-
if (impersonate) OS_SetImpersonate();
1331+
if (impersonate) fcgi_impersonate();
13271332
}
13281333
#endif
1329-
while (!fastcgi || FCGX_Accept_r(&request) >= 0) {
1334+
while (!fastcgi || fcgi_accept_request(&request) >= 0) {
13301335
#endif
13311336

13321337
#if PHP_FASTCGI
@@ -1540,7 +1545,7 @@ consult the installation file that came with this distribution, or visit \n\
15401545
if (php_request_startup(TSRMLS_C) == FAILURE) {
15411546
#if PHP_FASTCGI
15421547
if (fastcgi) {
1543-
FCGX_Finish_r(&request);
1548+
fcgi_finish_request(&request);
15441549
}
15451550
#endif
15461551
php_module_shutdown(TSRMLS_C);
@@ -1679,7 +1684,7 @@ consult the installation file that came with this distribution, or visit \n\
16791684
/* only fastcgi will get here */
16801685
requests++;
16811686
if (max_requests && (requests == max_requests)) {
1682-
FCGX_Finish_r(&request);
1687+
fcgi_finish_request(&request);
16831688
#ifndef PHP_WIN32
16841689
if (bindpath) {
16851690
free(bindpath);

0 commit comments

Comments
 (0)