summaryrefslogtreecommitdiff
path: root/sapi/cgi/cgi_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'sapi/cgi/cgi_main.c')
-rw-r--r--sapi/cgi/cgi_main.c686
1 files changed, 501 insertions, 185 deletions
diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c
index a7ac26f0d0..7856e0c581 100644
--- a/sapi/cgi/cgi_main.c
+++ b/sapi/cgi/cgi_main.c
@@ -106,6 +106,7 @@ static void (*php_php_import_environment_variables)(zval *array_ptr TSRMLS_DC);
*/
static int children = 0;
+
/**
* Set to non-zero if we are the parent process
*/
@@ -268,41 +269,30 @@ static void print_extensions(TSRMLS_D)
#define STDOUT_FILENO 1
#endif
-static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC)
+static inline size_t sapi_cgi_single_write(const char *str, uint str_length TSRMLS_DC)
{
#ifdef PHP_WRITE_STDOUT
long ret;
-#else
- size_t ret;
-#endif
-
- if (fcgi_is_fastcgi()) {
- fcgi_request *request = (fcgi_request*) SG(server_context);
- long ret = fcgi_write(request, FCGI_STDOUT, str, str_length);
- if (ret <= 0) {
- return 0;
- }
- return ret;
- }
-#ifdef PHP_WRITE_STDOUT
ret = write(STDOUT_FILENO, str, str_length);
if (ret <= 0) return 0;
return ret;
#else
+ size_t ret;
+
ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
return ret;
#endif
}
-static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
+static int sapi_cgi_ub_write(const char *str, uint str_length TSRMLS_DC)
{
const char *ptr = str;
uint remaining = str_length;
size_t ret;
while (remaining > 0) {
- ret = sapi_cgibin_single_write(ptr, remaining TSRMLS_CC);
+ ret = sapi_cgi_single_write(ptr, remaining TSRMLS_CC);
if (!ret) {
php_handle_aborted_connection();
return str_length - remaining;
@@ -314,21 +304,43 @@ static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
return str_length;
}
+static int sapi_fcgi_ub_write(const char *str, uint str_length TSRMLS_DC)
+{
+ const char *ptr = str;
+ uint remaining = str_length;
+ fcgi_request *request = (fcgi_request*) SG(server_context);
+
+ while (remaining > 0) {
+ long ret = fcgi_write(request, FCGI_STDOUT, ptr, remaining);
+
+ if (ret <= 0) {
+ php_handle_aborted_connection();
+ return str_length - remaining;
+ }
+ ptr += ret;
+ remaining -= ret;
+ }
+
+ return str_length;
+}
+
+static void sapi_cgi_flush(void *server_context)
+{
+ if (fflush(stdout) == EOF) {
+ php_handle_aborted_connection();
+ }
+}
-static void sapi_cgibin_flush(void *server_context)
+static void sapi_fcgi_flush(void *server_context)
{
- if (fcgi_is_fastcgi()) {
- fcgi_request *request = (fcgi_request*) server_context;
- if (
+ fcgi_request *request = (fcgi_request*) server_context;
+
+ if (
#ifndef PHP_WIN32
!parent &&
#endif
request && !fcgi_flush(request, 0)) {
- php_handle_aborted_connection();
- }
- return;
- }
- if (fflush(stdout) == EOF) {
+
php_handle_aborted_connection();
}
}
@@ -494,12 +506,24 @@ static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
while (read_bytes < count_bytes) {
- if (fcgi_is_fastcgi()) {
- fcgi_request *request = (fcgi_request*) SG(server_context);
- tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes);
- } else {
- tmp_read_bytes = read(STDIN_FILENO, buffer + read_bytes, count_bytes - read_bytes);
+ tmp_read_bytes = read(STDIN_FILENO, buffer + read_bytes, count_bytes - read_bytes);
+ if (tmp_read_bytes <= 0) {
+ break;
}
+ read_bytes += tmp_read_bytes;
+ }
+ return read_bytes;
+}
+
+static int sapi_fcgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
+{
+ uint read_bytes = 0;
+ int tmp_read_bytes;
+ fcgi_request *request = (fcgi_request*) SG(server_context);
+
+ count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
+ while (read_bytes < count_bytes) {
+ tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes);
if (tmp_read_bytes <= 0) {
break;
}
@@ -508,43 +532,33 @@ static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
return read_bytes;
}
-static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
+static char *sapi_cgi_getenv(char *name, size_t name_len TSRMLS_DC)
+{
+ return getenv(name);
+}
+
+static char *sapi_fcgi_getenv(char *name, size_t name_len TSRMLS_DC)
{
/* when php is started by mod_fastcgi, no regular environment
* is provided to PHP. It is always sent to PHP at the start
* of a request. So we have to do our own lookup to get env
* vars. This could probably be faster somehow. */
- if (fcgi_is_fastcgi()) {
- fcgi_request *request = (fcgi_request*) SG(server_context);
- return fcgi_getenv(request, name, name_len);
- }
+ fcgi_request *request = (fcgi_request*) SG(server_context);
+ char *ret = fcgi_getenv(request, name, name_len);
+
+ if (ret) return ret;
/* if cgi, or fastcgi and not found in fcgi env
check the regular environment */
return getenv(name);
}
-static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC)
+static char *_sapi_cgi_putenv(char *name, int name_len, char *value)
{
- int name_len;
#if !HAVE_SETENV || !HAVE_UNSETENV
int len;
char *buf;
#endif
- if (!name) {
- return NULL;
- }
- name_len = strlen(name);
-
- /* when php is started by mod_fastcgi, no regular environment
- * is provided to PHP. It is always sent to PHP at the start
- * of a request. So we have to do our own lookup to get env
- * vars. This could probably be faster somehow. */
- if (fcgi_is_fastcgi()) {
- fcgi_request *request = (fcgi_request*) SG(server_context);
- return fcgi_putenv(request, name, name_len, value);
- }
-
#if HAVE_SETENV
if (value) {
setenv(name, value, 1);
@@ -585,10 +599,28 @@ static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC)
static char *sapi_cgi_read_cookies(TSRMLS_D)
{
- return sapi_cgibin_getenv((char *) "HTTP_COOKIE", sizeof("HTTP_COOKIE")-1 TSRMLS_CC);
+ return getenv("HTTP_COOKIE");
+}
+
+static char *sapi_fcgi_read_cookies(TSRMLS_D)
+{
+ fcgi_request *request = (fcgi_request*) SG(server_context);
+
+ return FCGI_GETENV(request, "HTTP_COOKIE");
+}
+
+static void cgi_php_load_env_var(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg TSRMLS_DC)
+{
+ zval *array_ptr = (zval*)arg;
+ int filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER;
+ unsigned int new_val_len;
+
+ if (sapi_module.input_filter(filter_arg, var, &val, strlen(val), &new_val_len TSRMLS_CC)) {
+ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC);
+ }
}
-void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
+static void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
{
if (PG(http_globals)[TRACK_VARS_ENV] &&
array_ptr != PG(http_globals)[TRACK_VARS_ENV] &&
@@ -617,31 +649,7 @@ void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
if (fcgi_is_fastcgi()) {
fcgi_request *request = (fcgi_request*) SG(server_context);
- HashPosition pos;
- int magic_quotes_gpc = PG(magic_quotes_gpc);
- char *var, **val;
- uint var_len;
- ulong idx;
- int filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER;
-
- /* turn off magic_quotes while importing environment variables */
- if (magic_quotes_gpc) {
- zend_alter_ini_entry_ex("magic_quotes_gpc", sizeof("magic_quotes_gpc"), "0", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_ACTIVATE, 1 TSRMLS_CC);
- }
- for (zend_hash_internal_pointer_reset_ex(request->env, &pos);
- zend_hash_get_current_key_ex(request->env, &var, &var_len, &idx, 0, &pos) == HASH_KEY_IS_STRING &&
- zend_hash_get_current_data_ex(request->env, (void **) &val, &pos) == SUCCESS;
- zend_hash_move_forward_ex(request->env, &pos)
- ) {
- unsigned int new_val_len;
-
- if (sapi_module.input_filter(filter_arg, var, val, strlen(*val), &new_val_len TSRMLS_CC)) {
- php_register_variable_safe(var, *val, new_val_len, array_ptr TSRMLS_CC);
- }
- }
- if (magic_quotes_gpc) {
- zend_alter_ini_entry_ex("magic_quotes_gpc", sizeof("magic_quotes_gpc"), "1", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_ACTIVATE, 1 TSRMLS_CC);
- }
+ fcgi_loadenv(request, cgi_php_load_env_var, array_ptr TSRMLS_CC);
}
}
@@ -657,25 +665,51 @@ static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
if (CGIG(fix_pathinfo)) {
char *script_name = SG(request_info).request_uri;
- unsigned int script_name_len = script_name ? strlen(script_name) : 0;
- char *path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
- unsigned int path_info_len = path_info ? strlen(path_info) : 0;
+ char *path_info;
+ int free_php_self;
+ ALLOCA_FLAG(use_heap)
- php_self_len = script_name_len + path_info_len;
- php_self = emalloc(php_self_len + 1);
+ if (fcgi_is_fastcgi()) {
+ fcgi_request *request = (fcgi_request*) SG(server_context);
- if (script_name) {
- memcpy(php_self, script_name, script_name_len + 1);
+ path_info = FCGI_GETENV(request, "PATH_INFO");
+ } else {
+ path_info = getenv("PATH_INFO");
}
+
if (path_info) {
- memcpy(php_self + script_name_len, path_info, path_info_len + 1);
+ unsigned int path_info_len = strlen(path_info);
+
+ if (script_name) {
+ unsigned int script_name_len = strlen(script_name);
+
+ php_self_len = script_name_len + path_info_len;
+ php_self = do_alloca(php_self_len + 1, use_heap);
+ memcpy(php_self, script_name, script_name_len + 1);
+ memcpy(php_self + script_name_len, path_info, path_info_len + 1);
+ free_php_self = 1;
+ } else {
+ php_self = path_info;
+ php_self_len = path_info_len;
+ free_php_self = 0;
+ }
+ } else if (script_name) {
+ php_self = script_name;
+ php_self_len = strlen(script_name);
+ free_php_self = 0;
+ } else {
+ php_self = "";
+ php_self_len = 0;
+ free_php_self = 0;
}
/* Build the special-case PHP_SELF variable for the CGI version */
if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) {
php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC);
}
- efree(php_self);
+ if (free_php_self) {
+ free_alloca(php_self, use_heap);
+ }
} else {
php_self = SG(request_info).request_uri ? SG(request_info).request_uri : "";
php_self_len = strlen(php_self);
@@ -685,10 +719,8 @@ static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
}
}
-static void sapi_cgi_log_message(char *message)
+static void sapi_cgi_log_message(char *message TSRMLS_DC)
{
- TSRMLS_FETCH();
-
if (fcgi_is_fastcgi() && CGIG(fcgi_logging)) {
fcgi_request *request;
@@ -740,7 +772,6 @@ static void php_cgi_ini_activate_user_config(char *path, int path_len, const cha
if (!IS_ABSOLUTE_PATH(path, path_len)) {
real_path = tsrm_realpath(path, NULL TSRMLS_CC);
- /* see #51688, looks like we may get invalid path as doc root using cgi with apache */
if (real_path == NULL) {
return;
}
@@ -802,7 +833,13 @@ static int sapi_cgi_activate(TSRMLS_D)
if (php_ini_has_per_host_config()) {
/* Activate per-host-system-configuration defined in php.ini and stored into configuration_hash during startup */
- server_name = sapi_cgibin_getenv("SERVER_NAME", sizeof("SERVER_NAME") - 1 TSRMLS_CC);
+ if (fcgi_is_fastcgi()) {
+ fcgi_request *request = (fcgi_request*) SG(server_context);
+
+ server_name = FCGI_GETENV(request, "SERVER_NAME");
+ } else {
+ server_name = getenv("SERVER_NAME");
+ }
/* SERVER_NAME should also be defined at this stage..but better check it anyway */
if (server_name) {
server_name_len = strlen(server_name);
@@ -836,7 +873,14 @@ static int sapi_cgi_activate(TSRMLS_D)
/* Load and activate user ini files in path starting from DOCUMENT_ROOT */
if (PG(user_ini_filename) && *PG(user_ini_filename)) {
- doc_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT") - 1 TSRMLS_CC);
+ if (fcgi_is_fastcgi()) {
+ fcgi_request *request = (fcgi_request*) SG(server_context);
+
+ doc_root = FCGI_GETENV(request, "DOCUMENT_ROOT");
+ } else {
+ doc_root = getenv("DOCUMENT_ROOT");
+ }
+
/* DOCUMENT_ROOT should also be defined at this stage..but better check it anyway */
if (doc_root) {
doc_root_len = strlen(doc_root);
@@ -878,7 +922,7 @@ static int sapi_cgi_deactivate(TSRMLS_D)
php_handle_aborted_connection();
}
} else {
- sapi_cgibin_flush(SG(server_context));
+ sapi_cgi_flush(SG(server_context));
}
}
return SUCCESS;
@@ -904,10 +948,10 @@ static sapi_module_struct cgi_sapi_module = {
sapi_cgi_activate, /* activate */
sapi_cgi_deactivate, /* deactivate */
- sapi_cgibin_ub_write, /* unbuffered write */
- sapi_cgibin_flush, /* flush */
+ sapi_cgi_ub_write, /* unbuffered write */
+ sapi_cgi_flush, /* flush */
NULL, /* get uid */
- sapi_cgibin_getenv, /* getenv */
+ sapi_cgi_getenv, /* getenv */
php_error, /* error handler */
@@ -982,34 +1026,43 @@ static void php_cgi_usage(char *argv0)
*/
static int is_valid_path(const char *path)
{
- const char *p;
+ const char *p = path;
- if (!path) {
+ if (UNEXPECTED(!p)) {
return 0;
}
- p = strstr(path, "..");
- if (p) {
- if ((p == path || IS_SLASH(*(p-1))) &&
- (*(p+2) == 0 || IS_SLASH(*(p+2)))
- ) {
- return 0;
- }
- while (1) {
- p = strstr(p+1, "..");
- if (!p) {
- break;
- }
- if (IS_SLASH(*(p-1)) &&
- (*(p+2) == 0 || IS_SLASH(*(p+2)))
- ) {
- return 0;
+ if (UNEXPECTED(*p == '.') && *(p+1) == '.' && (!*(p+2) || IS_SLASH(*(p+2)))) {
+ return 0;
+ }
+ while (*p) {
+ if (IS_SLASH(*p)) {
+ p++;
+ if (UNEXPECTED(*p == '.')) {
+ p++;
+ if (UNEXPECTED(*p == '.')) {
+ p++;
+ if (UNEXPECTED(!*p) || UNEXPECTED(IS_SLASH(*p))) {
+ return 0;
+ }
+ }
}
}
+ p++;
}
return 1;
}
/* }}} */
+#define CGI_GETENV(name) \
+ ((request) ? \
+ FCGI_GETENV(request, name) : \
+ getenv(name))
+
+#define CGI_PUTENV(name, value) \
+ ((request) ? \
+ FCGI_PUTENV(request, name, value) : \
+ _sapi_cgi_putenv(name, sizeof(name)-1, value))
+
/* {{{ init_request_info
initializes request_info structure
@@ -1076,10 +1129,10 @@ static int is_valid_path(const char *path)
Comments in the code below refer to using the above URL in a request
*/
-static void init_request_info(TSRMLS_D)
+static void init_request_info(fcgi_request *request TSRMLS_DC)
{
- char *env_script_filename = sapi_cgibin_getenv("SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1 TSRMLS_CC);
- char *env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED", sizeof("PATH_TRANSLATED")-1 TSRMLS_CC);
+ char *env_script_filename = CGI_GETENV("SCRIPT_FILENAME");
+ char *env_path_translated = CGI_GETENV("PATH_TRANSLATED");
char *script_path_translated = env_script_filename;
/* some broken servers do not have script_filename or argv0
@@ -1105,32 +1158,35 @@ static void init_request_info(TSRMLS_D)
* of the script will be retreived later via argc/argv */
if (script_path_translated) {
const char *auth;
- char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1 TSRMLS_CC);
- char *content_type = sapi_cgibin_getenv("CONTENT_TYPE", sizeof("CONTENT_TYPE")-1 TSRMLS_CC);
- char *env_path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
- char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
+ char *content_length = CGI_GETENV("CONTENT_LENGTH");
+ char *content_type = CGI_GETENV("CONTENT_TYPE");
+ char *env_path_info = CGI_GETENV("PATH_INFO");
+ char *env_script_name = CGI_GETENV("SCRIPT_NAME");
+#ifdef PHP_WIN32
/* Hack for buggy IIS that sets incorrect PATH_INFO */
- char *env_server_software = sapi_cgibin_getenv("SERVER_SOFTWARE", sizeof("SERVER_SOFTWARE")-1 TSRMLS_CC);
+ char *env_server_software = CGI_GETENV("SERVER_SOFTWARE");
+
if (env_server_software &&
env_script_name &&
env_path_info &&
strncmp(env_server_software, "Microsoft-IIS", sizeof("Microsoft-IIS")-1) == 0 &&
strncmp(env_path_info, env_script_name, strlen(env_script_name)) == 0
) {
- env_path_info = _sapi_cgibin_putenv("ORIG_PATH_INFO", env_path_info TSRMLS_CC);
+ env_path_info = CGI_PUTENV("ORIG_PATH_INFO", env_path_info);
env_path_info += strlen(env_script_name);
if (*env_path_info == 0) {
env_path_info = NULL;
}
- env_path_info = _sapi_cgibin_putenv("PATH_INFO", env_path_info TSRMLS_CC);
+ env_path_info = CGI_PUTENV("PATH_INFO", env_path_info);
}
+#endif
if (CGIG(fix_pathinfo)) {
struct stat st;
char *real_path = NULL;
- char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL", sizeof("REDIRECT_URL")-1 TSRMLS_CC);
- char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")-1 TSRMLS_CC);
+ char *env_redirect_url = CGI_GETENV("REDIRECT_URL");
+ char *env_document_root = CGI_GETENV("DOCUMENT_ROOT");
char *orig_path_translated = env_path_translated;
char *orig_path_info = env_path_info;
char *orig_script_name = env_script_name;
@@ -1138,7 +1194,7 @@ static void init_request_info(TSRMLS_D)
int script_path_translated_len;
if (!env_document_root && PG(doc_root)) {
- env_document_root = _sapi_cgibin_putenv("DOCUMENT_ROOT", PG(doc_root) TSRMLS_CC);
+ env_document_root = CGI_PUTENV("DOCUMENT_ROOT", PG(doc_root));
/* fix docroot */
TRANSLATE_SLASHES(env_document_root);
}
@@ -1205,28 +1261,28 @@ static void init_request_info(TSRMLS_D)
if (orig_path_info) {
char old;
- _sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
+ CGI_PUTENV("ORIG_PATH_INFO", orig_path_info);
old = path_info[0];
path_info[0] = 0;
if (!orig_script_name ||
strcmp(orig_script_name, env_path_info) != 0) {
if (orig_script_name) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
+ CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name);
}
- SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_path_info TSRMLS_CC);
+ SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_path_info);
} else {
SG(request_info).request_uri = orig_script_name;
}
path_info[0] = old;
}
- env_path_info = _sapi_cgibin_putenv("PATH_INFO", path_info TSRMLS_CC);
+ env_path_info = CGI_PUTENV("PATH_INFO", path_info);
}
if (!orig_script_filename ||
strcmp(orig_script_filename, pt) != 0) {
if (orig_script_filename) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
+ CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename);
}
- script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", pt TSRMLS_CC);
+ script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", pt);
}
TRANSLATE_SLASHES(pt);
@@ -1256,9 +1312,9 @@ static void init_request_info(TSRMLS_D)
}
path_translated[path_translated_len] = '\0';
if (orig_path_translated) {
- _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
+ CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated);
}
- env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
+ env_path_translated = CGI_PUTENV("PATH_TRANSLATED", path_translated);
efree(path_translated);
} else if ( env_script_name &&
strstr(pt, env_script_name)
@@ -1275,9 +1331,9 @@ static void init_request_info(TSRMLS_D)
}
path_translated[path_translated_len] = '\0';
if (orig_path_translated) {
- _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
+ CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated);
}
- env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
+ env_path_translated = CGI_PUTENV("PATH_TRANSLATED", path_translated);
efree(path_translated);
}
break;
@@ -1290,18 +1346,18 @@ static void init_request_info(TSRMLS_D)
* have failed anyway... we output 'no input file' now.
*/
if (orig_script_filename) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
+ CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename);
}
- script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", NULL TSRMLS_CC);
+ script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", NULL);
SG(sapi_headers).http_response_code = 404;
}
if (!SG(request_info).request_uri) {
if (!orig_script_name ||
strcmp(orig_script_name, env_script_name) != 0) {
if (orig_script_name) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
+ CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name);
}
- SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
+ SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_script_name);
} else {
SG(request_info).request_uri = orig_script_name;
}
@@ -1315,25 +1371,25 @@ static void init_request_info(TSRMLS_D)
(script_path_translated != orig_script_filename &&
strcmp(script_path_translated, orig_script_filename) != 0)) {
if (orig_script_filename) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
+ CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename);
}
- script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", script_path_translated TSRMLS_CC);
+ script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", script_path_translated);
}
if (env_redirect_url) {
if (orig_path_info) {
- _sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
- _sapi_cgibin_putenv("PATH_INFO", NULL TSRMLS_CC);
+ CGI_PUTENV("ORIG_PATH_INFO", orig_path_info);
+ CGI_PUTENV("PATH_INFO", NULL);
}
if (orig_path_translated) {
- _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
- _sapi_cgibin_putenv("PATH_TRANSLATED", NULL TSRMLS_CC);
+ CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated);
+ CGI_PUTENV("PATH_TRANSLATED", NULL);
}
}
if (env_script_name != orig_script_name) {
if (orig_script_name) {
- _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
+ CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name);
}
- SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
+ SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_script_name);
} else {
SG(request_info).request_uri = env_script_name;
}
@@ -1355,14 +1411,14 @@ static void init_request_info(TSRMLS_D)
SG(request_info).path_translated = estrdup(script_path_translated);
}
- SG(request_info).request_method = sapi_cgibin_getenv("REQUEST_METHOD", sizeof("REQUEST_METHOD")-1 TSRMLS_CC);
+ SG(request_info).request_method = CGI_GETENV("REQUEST_METHOD");
/* FIXME - Work out proto_num here */
- SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", sizeof("QUERY_STRING")-1 TSRMLS_CC);
+ SG(request_info).query_string = CGI_GETENV("QUERY_STRING");
SG(request_info).content_type = (content_type ? content_type : "" );
SG(request_info).content_length = (content_length ? atol(content_length) : 0);
/* The CGI RFC allows servers to pass on unvalidated Authorization data */
- auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION")-1 TSRMLS_CC);
+ auth = CGI_GETENV("HTTP_AUTHORIZATION");
php_handle_auth_data(auth TSRMLS_CC);
}
}
@@ -1457,10 +1513,205 @@ static PHP_MINFO_FUNCTION(cgi)
}
/* }}} */
+PHP_FUNCTION(apache_child_terminate) /* {{{ */
+{
+ if (ZEND_NUM_ARGS() > 0) {
+ WRONG_PARAM_COUNT;
+ }
+ if (fcgi_is_fastcgi()) {
+ fcgi_terminate();
+ }
+}
+/* }}} */
+
+static void add_request_header(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg TSRMLS_DC) /* {{{ */
+{
+ zval *return_value = (zval*)arg;
+ char *str = NULL;
+ char *p;
+ ALLOCA_FLAG(use_heap)
+
+ if (var_len > 5 &&
+ var[0] == 'H' &&
+ var[1] == 'T' &&
+ var[2] == 'T' &&
+ var[3] == 'P' &&
+ var[4] == '_') {
+
+ var_len -= 5;
+ p = var + 5;
+ var = str = do_alloca(var_len + 1, use_heap);
+ *str++ = *p++;
+ while (*p) {
+ if (*p == '_') {
+ *str++ = '-';
+ p++;
+ if (*p) {
+ *str++ = *p++;
+ }
+ } else if (*p >= 'A' && *p <= 'Z') {
+ *str++ = (*p++ - 'A' + 'a');
+ } else {
+ *str++ = *p++;
+ }
+ }
+ *str = 0;
+ } else if (var_len == sizeof("CONTENT_TYPE")-1 &&
+ memcmp(var, "CONTENT_TYPE", sizeof("CONTENT_TYPE")-1) == 0) {
+ var = "Content-Type";
+ } else if (var_len == sizeof("CONTENT_LENGTH")-1 &&
+ memcmp(var, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1) == 0) {
+ var = "Content-Length";
+ } else {
+ return;
+ }
+ add_assoc_stringl_ex(return_value, var, var_len+1, val, val_len, 1);
+ if (str) {
+ free_alloca(var, use_heap);
+ }
+}
+/* }}} */
+
+PHP_FUNCTION(apache_request_headers) /* {{{ */
+{
+ if (ZEND_NUM_ARGS() > 0) {
+ WRONG_PARAM_COUNT;
+ }
+ array_init(return_value);
+ if (fcgi_is_fastcgi()) {
+ fcgi_request *request = (fcgi_request*) SG(server_context);
+
+ fcgi_loadenv(request, add_request_header, return_value TSRMLS_CC);
+ } else {
+ char buf[128];
+ char **env, *p, *q, *var, *val, *t = buf;
+ size_t alloc_size = sizeof(buf);
+ unsigned long var_len;
+
+ for (env = environ; env != NULL && *env != NULL; env++) {
+ val = strchr(*env, '=');
+ if (!val) { /* malformed entry? */
+ continue;
+ }
+ var_len = val - *env;
+ if (var_len >= alloc_size) {
+ alloc_size = var_len + 64;
+ t = (t == buf ? emalloc(alloc_size): erealloc(t, alloc_size));
+ }
+ var = *env;
+ if (var_len > 5 &&
+ var[0] == 'H' &&
+ var[1] == 'T' &&
+ var[2] == 'T' &&
+ var[3] == 'P' &&
+ var[4] == '_') {
+
+ var_len -= 5;
+
+ if (var_len >= alloc_size) {
+ alloc_size = var_len + 64;
+ t = (t == buf ? emalloc(alloc_size): erealloc(t, alloc_size));
+ }
+ p = var + 5;
+
+ var = q = t;
+ /* First char keep uppercase */
+ *q++ = *p++;
+ while (*p) {
+ if (*p == '=') {
+ /* End of name */
+ break;
+ } else if (*p == '_') {
+ *q++ = '-';
+ p++;
+ /* First char after - keep uppercase */
+ if (*p && *p!='=') {
+ *q++ = *p++;
+ }
+ } else if (*p >= 'A' && *p <= 'Z') {
+ /* lowercase */
+ *q++ = (*p++ - 'A' + 'a');
+ } else {
+ *q++ = *p++;
+ }
+ }
+ *q = 0;
+ } else if (var_len == sizeof("CONTENT_TYPE")-1 &&
+ memcmp(var, "CONTENT_TYPE", sizeof("CONTENT_TYPE")-1) == 0) {
+ var = "Content-Type";
+ } else if (var_len == sizeof("CONTENT_LENGTH")-1 &&
+ memcmp(var, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1) == 0) {
+ var = "Content-Length";
+ } else {
+ continue;
+ }
+ val++;
+ add_assoc_string_ex(return_value, var, var_len+1, val, 1);
+ }
+ if (t != buf && t != NULL) {
+ efree(t);
+ }
+ }
+}
+/* }}} */
+
+static void add_response_header(sapi_header_struct *h, zval *return_value TSRMLS_DC) /* {{{ */
+{
+ char *s, *p;
+ int len;
+ ALLOCA_FLAG(use_heap)
+
+ if (h->header_len > 0) {
+ p = strchr(h->header, ':');
+ len = p - h->header;
+ if (p && (len > 0)) {
+ while (len > 0 && (h->header[len-1] == ' ' || h->header[len-1] == '\t')) {
+ len--;
+ }
+ if (len) {
+ s = do_alloca(len + 1, use_heap);
+ memcpy(s, h->header, len);
+ s[len] = 0;
+ do {
+ p++;
+ } while (*p == ' ' || *p == '\t');
+ add_assoc_stringl_ex(return_value, s, len+1, p, h->header_len - (p - h->header), 1);
+ free_alloca(s, use_heap);
+ }
+ }
+ }
+}
+/* }}} */
+
+PHP_FUNCTION(apache_response_headers) /* {{{ */
+{
+ if (ZEND_NUM_ARGS() > 0) {
+ WRONG_PARAM_COUNT;
+ }
+
+ if (!&SG(sapi_headers).headers) {
+ RETURN_FALSE;
+ }
+ array_init(return_value);
+ zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t)add_response_header, return_value TSRMLS_CC);
+}
+/* }}} */
+
+ZEND_BEGIN_ARG_INFO(arginfo_no_args, 0)
+ZEND_END_ARG_INFO()
+
+const zend_function_entry cgi_functions[] = {
+ PHP_FE(apache_child_terminate, arginfo_no_args)
+ PHP_FE(apache_request_headers, arginfo_no_args)
+ PHP_FE(apache_response_headers, arginfo_no_args)
+ PHP_FALIAS(getallheaders, apache_request_headers, arginfo_no_args)
+ {NULL, NULL, NULL}
+};
+
static zend_module_entry cgi_module_entry = {
STANDARD_MODULE_HEADER,
"cgi-fcgi",
- NULL,
+ cgi_functions,
PHP_MINIT(cgi),
PHP_MSHUTDOWN(cgi),
NULL,
@@ -1495,10 +1746,10 @@ int main(int argc, char *argv[])
int max_requests = 500;
int requests = 0;
- int fastcgi = fcgi_is_fastcgi();
+ int fastcgi;
char *bindpath = NULL;
int fcgi_fd = 0;
- fcgi_request request;
+ fcgi_request *request = NULL;
int repeats = 1;
int benchmark = 0;
#if HAVE_GETTIMEOFDAY
@@ -1540,6 +1791,7 @@ int main(int argc, char *argv[])
#endif
sapi_startup(&cgi_sapi_module);
+ fastcgi = fcgi_is_fastcgi();
cgi_sapi_module.php_ini_path_override = NULL;
#ifdef PHP_WIN32
@@ -1633,6 +1885,15 @@ int main(int argc, char *argv[])
php_optind = orig_optind;
php_optarg = orig_optarg;
+ if (fastcgi || bindpath) {
+ /* Override SAPI callbacks */
+ cgi_sapi_module.ub_write = sapi_fcgi_ub_write;
+ cgi_sapi_module.flush = sapi_fcgi_flush;
+ cgi_sapi_module.read_post = sapi_fcgi_read_post;
+ cgi_sapi_module.getenv = sapi_fcgi_getenv;
+ cgi_sapi_module.read_cookies = sapi_fcgi_read_cookies;
+ }
+
#ifdef ZTS
SG(request_info).path_translated = NULL;
#endif
@@ -1716,7 +1977,7 @@ consult the installation file that came with this distribution, or visit \n\
php_import_environment_variables = cgi_php_import_environment_variables;
/* library is already initialized, now init our request */
- fcgi_init_request(&request, fcgi_fd);
+ request = fcgi_init_request(fcgi_fd);
#ifndef PHP_WIN32
/* Pre-fork, if required */
@@ -1837,13 +2098,14 @@ consult the installation file that came with this distribution, or visit \n\
break;
case 'h':
case '?':
+ if (request) {
+ fcgi_destroy_request(request);
+ }
fcgi_shutdown();
no_headers = 1;
- php_output_startup();
- php_output_activate(TSRMLS_C);
SG(headers_sent) = 1;
php_cgi_usage(argv[0]);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_end_all(TSRMLS_C);
exit_status = 0;
goto out;
}
@@ -1860,9 +2122,9 @@ consult the installation file that came with this distribution, or visit \n\
fcgi_impersonate();
}
#endif
- while (!fastcgi || fcgi_accept_request(&request) >= 0) {
- SG(server_context) = (void *) &request;
- init_request_info(TSRMLS_C);
+ while (!fastcgi || fcgi_accept_request(request) >= 0) {
+ SG(server_context) = fastcgi ? (void *) request : (void *) 1;
+ init_request_info(request TSRMLS_CC);
CG(interactive) = 0;
if (!cgi && !fastcgi) {
@@ -1918,15 +2180,13 @@ consult the installation file that came with this distribution, or visit \n\
if (script_file) {
efree(script_file);
}
- php_output_startup();
- php_output_activate(TSRMLS_C);
SG(headers_sent) = 1;
php_printf("[PHP Modules]\n");
print_modules(TSRMLS_C);
php_printf("\n[Zend Modules]\n");
print_extensions(TSRMLS_C);
php_printf("\n");
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_end_all(TSRMLS_C);
fcgi_shutdown();
exit_status = 0;
goto out;
@@ -2057,7 +2317,7 @@ consult the installation file that came with this distribution, or visit \n\
* get path_translated */
if (php_request_startup(TSRMLS_C) == FAILURE) {
if (fastcgi) {
- fcgi_finish_request(&request, 1);
+ fcgi_finish_request(request, 1);
}
SG(server_context) = NULL;
php_module_shutdown(TSRMLS_C);
@@ -2110,23 +2370,75 @@ consult the installation file that came with this distribution, or visit \n\
}
}
- if (CGIG(check_shebang_line) && file_handle.handle.fp && (file_handle.handle.fp != stdin)) {
+ if (CGIG(check_shebang_line)) {
/* #!php support */
- c = fgetc(file_handle.handle.fp);
- if (c == '#') {
- while (c != '\n' && c != '\r' && c != EOF) {
- c = fgetc(file_handle.handle.fp); /* skip to end of line */
- }
- /* handle situations where line is terminated by \r\n */
- if (c == '\r') {
- if (fgetc(file_handle.handle.fp) != '\n') {
- long pos = ftell(file_handle.handle.fp);
- fseek(file_handle.handle.fp, pos - 1, SEEK_SET);
+ switch (file_handle.type) {
+ case ZEND_HANDLE_FD:
+ if (file_handle.handle.fd < 0) {
+ break;
}
- }
- CG(start_lineno) = 2;
- } else {
- rewind(file_handle.handle.fp);
+ file_handle.type = ZEND_HANDLE_FP;
+ file_handle.handle.fp = fdopen(file_handle.handle.fd, "rb");
+ /* break missing intentionally */
+ case ZEND_HANDLE_FP:
+ if (!file_handle.handle.fp ||
+ (file_handle.handle.fp == stdin)) {
+ break;
+ }
+ c = fgetc(file_handle.handle.fp);
+ if (c == '#') {
+ while (c != '\n' && c != '\r' && c != EOF) {
+ c = fgetc(file_handle.handle.fp); /* skip to end of line */
+ }
+ /* handle situations where line is terminated by \r\n */
+ if (c == '\r') {
+ if (fgetc(file_handle.handle.fp) != '\n') {
+ long pos = ftell(file_handle.handle.fp);
+ fseek(file_handle.handle.fp, pos - 1, SEEK_SET);
+ }
+ }
+ CG(start_lineno) = 2;
+ } else {
+ rewind(file_handle.handle.fp);
+ }
+ break;
+ case ZEND_HANDLE_STREAM:
+ c = php_stream_getc((php_stream*)file_handle.handle.stream.handle);
+ if (c == '#') {
+ while (c != '\n' && c != '\r' && c != EOF) {
+ c = php_stream_getc((php_stream*)file_handle.handle.stream.handle); /* skip to end of line */
+ }
+ /* handle situations where line is terminated by \r\n */
+ if (c == '\r') {
+ if (php_stream_getc((php_stream*)file_handle.handle.stream.handle) != '\n') {
+ long pos = php_stream_tell((php_stream*)file_handle.handle.stream.handle);
+ php_stream_seek((php_stream*)file_handle.handle.stream.handle, pos - 1, SEEK_SET);
+ }
+ }
+ CG(start_lineno) = 2;
+ } else {
+ php_stream_rewind((php_stream*)file_handle.handle.stream.handle);
+ }
+ break;
+ case ZEND_HANDLE_MAPPED:
+ if (file_handle.handle.stream.mmap.buf[0] == '#') {
+ int i = 1;
+
+ c = file_handle.handle.stream.mmap.buf[i++];
+ while (c != '\n' && c != '\r' && c != EOF) {
+ c = file_handle.handle.stream.mmap.buf[i++];
+ }
+ if (c == '\r') {
+ if (file_handle.handle.stream.mmap.buf[i] == '\n') {
+ i++;
+ }
+ }
+ file_handle.handle.stream.mmap.buf += i;
+ file_handle.handle.stream.mmap.len -= i;
+ }
+ break;
+ default:
+ break;
}
}
@@ -2147,7 +2459,7 @@ consult the installation file that came with this distribution, or visit \n\
if (open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
zend_strip(TSRMLS_C);
zend_file_handle_dtor(&file_handle TSRMLS_CC);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
}
return SUCCESS;
break;
@@ -2162,7 +2474,7 @@ consult the installation file that came with this distribution, or visit \n\
goto fastcgi_request_done;
}
zend_file_handle_dtor(&file_handle TSRMLS_CC);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
}
return SUCCESS;
}
@@ -2173,6 +2485,7 @@ consult the installation file that came with this distribution, or visit \n\
open_file_for_scanning(&file_handle TSRMLS_CC);
zend_indent();
zend_file_handle_dtor(&file_handle TSRMLS_CC);
+ php_output_teardown();
return SUCCESS;
break;
#endif
@@ -2210,7 +2523,7 @@ fastcgi_request_done:
/* only fastcgi will get here */
requests++;
if (max_requests && (requests == max_requests)) {
- fcgi_finish_request(&request, 1);
+ fcgi_finish_request(request, 1);
if (bindpath) {
free(bindpath);
}
@@ -2222,6 +2535,9 @@ fastcgi_request_done:
}
/* end of fastcgi loop */
}
+ if (request) {
+ fcgi_destroy_request(request);
+ }
fcgi_shutdown();
if (cgi_sapi_module.php_ini_path_override) {