xref: /PHP-7.4/sapi/fpm/fpm/fpm_main.c (revision a054ef2a)
1d77d6153SAntony Dovgal /*
2d77d6153SAntony Dovgal    +----------------------------------------------------------------------+
3d0cb7153SJohannes Schlüter    | PHP Version 7                                                        |
4d77d6153SAntony Dovgal    +----------------------------------------------------------------------+
50cf7de1cSZeev Suraski    | Copyright (c) The PHP Group                                          |
6d77d6153SAntony Dovgal    +----------------------------------------------------------------------+
7d77d6153SAntony Dovgal    | This source file is subject to version 3.01 of the PHP license,      |
8d77d6153SAntony Dovgal    | that is bundled with this package in the file LICENSE, and is        |
9d77d6153SAntony Dovgal    | available through the world-wide-web at the following url:           |
10d77d6153SAntony Dovgal    | http://www.php.net/license/3_01.txt                                  |
11d77d6153SAntony Dovgal    | If you did not receive a copy of the PHP license and are unable to   |
12d77d6153SAntony Dovgal    | obtain it through the world-wide-web, please send a note to          |
13d77d6153SAntony Dovgal    | license@php.net so we can mail you a copy immediately.               |
14d77d6153SAntony Dovgal    +----------------------------------------------------------------------+
15d77d6153SAntony Dovgal    | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca>                       |
16d77d6153SAntony Dovgal    |          Stig Bakken <ssb@php.net>                                   |
1767e0138cSZeev Suraski    |          Zeev Suraski <zeev@php.net>                                 |
18d77d6153SAntony Dovgal    | FastCGI: Ben Mansell <php@slimyhorror.com>                           |
19d77d6153SAntony Dovgal    |          Shane Caraveo <shane@caraveo.com>                           |
2067e0138cSZeev Suraski    |          Dmitry Stogov <dmitry@php.net>                              |
21d77d6153SAntony Dovgal    +----------------------------------------------------------------------+
22d77d6153SAntony Dovgal */
23d77d6153SAntony Dovgal 
24d77d6153SAntony Dovgal #include "php.h"
25d77d6153SAntony Dovgal #include "php_globals.h"
26d77d6153SAntony Dovgal #include "php_variables.h"
27d77d6153SAntony Dovgal #include "zend_modules.h"
2834ba9e39SJérôme Loyet #include "php.h"
2934ba9e39SJérôme Loyet #include "zend_ini_scanner.h"
3034ba9e39SJérôme Loyet #include "zend_globals.h"
3134ba9e39SJérôme Loyet #include "zend_stream.h"
32d77d6153SAntony Dovgal 
33d77d6153SAntony Dovgal #include "SAPI.h"
34d77d6153SAntony Dovgal 
35d77d6153SAntony Dovgal #include <stdio.h>
36d77d6153SAntony Dovgal #include "php.h"
37d77d6153SAntony Dovgal 
38d77d6153SAntony Dovgal #if HAVE_SYS_TIME_H
39d77d6153SAntony Dovgal # include <sys/time.h>
40d77d6153SAntony Dovgal #endif
41d77d6153SAntony Dovgal 
42d77d6153SAntony Dovgal #if HAVE_UNISTD_H
43d77d6153SAntony Dovgal # include <unistd.h>
44d77d6153SAntony Dovgal #endif
45d77d6153SAntony Dovgal 
465f891578SPeter Kokot #include <signal.h>
47d77d6153SAntony Dovgal 
48e06836a1SPeter Kokot #include <locale.h>
49d77d6153SAntony Dovgal 
50d77d6153SAntony Dovgal #if HAVE_SYS_TYPES_H
51d77d6153SAntony Dovgal # include <sys/types.h>
52d77d6153SAntony Dovgal #endif
53d77d6153SAntony Dovgal 
54d77d6153SAntony Dovgal #if HAVE_SYS_WAIT_H
55d77d6153SAntony Dovgal # include <sys/wait.h>
56d77d6153SAntony Dovgal #endif
57d77d6153SAntony Dovgal 
58d77d6153SAntony Dovgal #if HAVE_FCNTL_H
59d77d6153SAntony Dovgal # include <fcntl.h>
60d77d6153SAntony Dovgal #endif
61d77d6153SAntony Dovgal 
62d77d6153SAntony Dovgal #include "zend.h"
63d77d6153SAntony Dovgal #include "zend_extensions.h"
64d77d6153SAntony Dovgal #include "php_ini.h"
65d77d6153SAntony Dovgal #include "php_globals.h"
66d77d6153SAntony Dovgal #include "php_main.h"
67d77d6153SAntony Dovgal #include "fopen_wrappers.h"
68d77d6153SAntony Dovgal #include "ext/standard/php_standard.h"
69d77d6153SAntony Dovgal 
70d77d6153SAntony Dovgal #ifdef __riscos__
71d77d6153SAntony Dovgal # include <unixlib/local.h>
72d77d6153SAntony Dovgal int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS;
73d77d6153SAntony Dovgal #endif
74d77d6153SAntony Dovgal 
75d77d6153SAntony Dovgal #include "zend_compile.h"
76d77d6153SAntony Dovgal #include "zend_execute.h"
77d77d6153SAntony Dovgal #include "zend_highlight.h"
78d77d6153SAntony Dovgal 
79d77d6153SAntony Dovgal #include "php_getopt.h"
80d77d6153SAntony Dovgal 
81e20cbdbeSAndrea Faulds #include "http_status_codes.h"
82e20cbdbeSAndrea Faulds 
83d77d6153SAntony Dovgal #include "fastcgi.h"
84d77d6153SAntony Dovgal 
85d77d6153SAntony Dovgal #include <php_config.h>
863afe7724SJérôme Loyet #include "fpm.h"
873afe7724SJérôme Loyet #include "fpm_request.h"
883afe7724SJérôme Loyet #include "fpm_status.h"
89ae5154c6SMaksim Nikulin #include "fpm_signals.h"
900bc6a66aSJakub Zelenka #include "fpm_stdio.h"
913afe7724SJérôme Loyet #include "fpm_conf.h"
923afe7724SJérôme Loyet #include "fpm_php.h"
933afe7724SJérôme Loyet #include "fpm_log.h"
943afe7724SJérôme Loyet #include "zlog.h"
95d77d6153SAntony Dovgal 
96d77d6153SAntony Dovgal /* XXX this will need to change later when threaded fastcgi is implemented.  shane */
97d77d6153SAntony Dovgal struct sigaction act, old_term, old_quit, old_int;
98d77d6153SAntony Dovgal 
99bdeb220fSAnatol Belski static void (*php_php_import_environment_variables)(zval *array_ptr);
100d77d6153SAntony Dovgal 
101d77d6153SAntony Dovgal /* these globals used for forking children on unix systems */
102d77d6153SAntony Dovgal 
103d77d6153SAntony Dovgal /**
104d77d6153SAntony Dovgal  * Set to non-zero if we are the parent process
105d77d6153SAntony Dovgal  */
106d77d6153SAntony Dovgal static int parent = 1;
107d77d6153SAntony Dovgal 
108d77d6153SAntony Dovgal static int request_body_fd;
109eb180ac3SJérôme Loyet static int fpm_is_running = 0;
110d77d6153SAntony Dovgal 
111bdeb220fSAnatol Belski static char *sapi_cgibin_getenv(char *name, size_t name_len);
112bdeb220fSAnatol Belski static void fastcgi_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg);
113d77d6153SAntony Dovgal 
114d77d6153SAntony Dovgal #define PHP_MODE_STANDARD	1
115d77d6153SAntony Dovgal #define PHP_MODE_HIGHLIGHT	2
116d77d6153SAntony Dovgal #define PHP_MODE_INDENT		3
117d77d6153SAntony Dovgal #define PHP_MODE_LINT		4
118d77d6153SAntony Dovgal #define PHP_MODE_STRIP		5
119d77d6153SAntony Dovgal 
120d77d6153SAntony Dovgal static char *php_optarg = NULL;
121d77d6153SAntony Dovgal static int php_optind = 1;
122d77d6153SAntony Dovgal static zend_module_entry cgi_module_entry;
123d77d6153SAntony Dovgal 
124d77d6153SAntony Dovgal static const opt_struct OPTIONS[] = {
125d77d6153SAntony Dovgal 	{'c', 1, "php-ini"},
126d77d6153SAntony Dovgal 	{'d', 1, "define"},
127d77d6153SAntony Dovgal 	{'e', 0, "profile-info"},
128d77d6153SAntony Dovgal 	{'h', 0, "help"},
129d77d6153SAntony Dovgal 	{'i', 0, "info"},
130d77d6153SAntony Dovgal 	{'m', 0, "modules"},
131d77d6153SAntony Dovgal 	{'n', 0, "no-php-ini"},
132d77d6153SAntony Dovgal 	{'?', 0, "usage"},/* help alias (both '?' and 'usage') */
133d77d6153SAntony Dovgal 	{'v', 0, "version"},
134d77d6153SAntony Dovgal 	{'y', 1, "fpm-config"},
135b772fae9SJérôme Loyet 	{'t', 0, "test"},
136ae01a576SJérôme Loyet 	{'p', 1, "prefix"},
137b7e5a7f2SJérôme Loyet 	{'g', 1, "pid"},
13806c7c367SJerome Loyet 	{'R', 0, "allow-to-run-as-root"},
139851a04bbSJerome Loyet 	{'D', 0, "daemonize"},
140851a04bbSJerome Loyet 	{'F', 0, "nodaemonize"},
141a053e699SAntony Dovgal 	{'O', 0, "force-stderr"},
142d77d6153SAntony Dovgal 	{'-', 0, NULL} /* end of args */
143d77d6153SAntony Dovgal };
144d77d6153SAntony Dovgal 
145d77d6153SAntony Dovgal typedef struct _php_cgi_globals_struct {
146d77d6153SAntony Dovgal 	zend_bool rfc2616_headers;
147d77d6153SAntony Dovgal 	zend_bool nph;
148d77d6153SAntony Dovgal 	zend_bool fix_pathinfo;
149d77d6153SAntony Dovgal 	zend_bool force_redirect;
150d77d6153SAntony Dovgal 	zend_bool discard_path;
151d77d6153SAntony Dovgal 	zend_bool fcgi_logging;
152d77d6153SAntony Dovgal 	char *redirect_status_env;
153d77d6153SAntony Dovgal 	HashTable user_config_cache;
154d77d6153SAntony Dovgal 	char *error_header;
155d77d6153SAntony Dovgal 	char *fpm_config;
156d77d6153SAntony Dovgal } php_cgi_globals_struct;
157d77d6153SAntony Dovgal 
158d77d6153SAntony Dovgal /* {{{ user_config_cache
159d77d6153SAntony Dovgal  *
160d77d6153SAntony Dovgal  * Key for each cache entry is dirname(PATH_TRANSLATED).
161d77d6153SAntony Dovgal  *
162d77d6153SAntony Dovgal  * NOTE: Each cache entry config_hash contains the combination from all user ini files found in
16384b195d9SGabriel Caruso  *       the path starting from doc_root through to dirname(PATH_TRANSLATED).  There is no point
164d77d6153SAntony Dovgal  *       storing per-file entries as it would not be possible to detect added / deleted entries
165d77d6153SAntony Dovgal  *       between separate files.
166d77d6153SAntony Dovgal  */
167d77d6153SAntony Dovgal typedef struct _user_config_cache_entry {
168d77d6153SAntony Dovgal 	time_t expires;
169d77d6153SAntony Dovgal 	HashTable *user_config;
170d77d6153SAntony Dovgal } user_config_cache_entry;
171d77d6153SAntony Dovgal 
user_config_cache_entry_dtor(zval * el)172c242518bSXinchen Hui static void user_config_cache_entry_dtor(zval *el)
173d77d6153SAntony Dovgal {
174c242518bSXinchen Hui 	user_config_cache_entry *entry = (user_config_cache_entry *)Z_PTR_P(el);
175d77d6153SAntony Dovgal 	zend_hash_destroy(entry->user_config);
176d77d6153SAntony Dovgal 	free(entry->user_config);
177c242518bSXinchen Hui 	free(entry);
178d77d6153SAntony Dovgal }
179d77d6153SAntony Dovgal /* }}} */
180d77d6153SAntony Dovgal 
181d77d6153SAntony Dovgal #ifdef ZTS
182d77d6153SAntony Dovgal static int php_cgi_globals_id;
183cf4ee57dSDmitry Stogov #define CGIG(v) ZEND_TSRMG(php_cgi_globals_id, php_cgi_globals_struct *, v)
184d77d6153SAntony Dovgal #else
185d77d6153SAntony Dovgal static php_cgi_globals_struct php_cgi_globals;
186d77d6153SAntony Dovgal #define CGIG(v) (php_cgi_globals.v)
187d77d6153SAntony Dovgal #endif
188d77d6153SAntony Dovgal 
module_name_cmp(const void * a,const void * b)18918cf4e0aSXinchen Hui static int module_name_cmp(const void *a, const void *b) /* {{{ */
190d77d6153SAntony Dovgal {
191f4cfaf36SDmitry Stogov 	Bucket *f = (Bucket *) a;
192f4cfaf36SDmitry Stogov 	Bucket *s = (Bucket *) b;
193d77d6153SAntony Dovgal 
194404cc45eSNikita Popov 	return strcasecmp(	((zend_module_entry *) Z_PTR(f->val))->name,
195404cc45eSNikita Popov 						((zend_module_entry *) Z_PTR(s->val))->name);
196d77d6153SAntony Dovgal }
19718cf4e0aSXinchen Hui /* }}} */
198d77d6153SAntony Dovgal 
print_modules(void)19918cf4e0aSXinchen Hui static void print_modules(void) /* {{{ */
200d77d6153SAntony Dovgal {
201d77d6153SAntony Dovgal 	HashTable sorted_registry;
202cec09117SDmitry Stogov 	zend_module_entry *module;
203d77d6153SAntony Dovgal 
204d77d6153SAntony Dovgal 	zend_hash_init(&sorted_registry, 50, NULL, NULL, 1);
205404cc45eSNikita Popov 	zend_hash_copy(&sorted_registry, &module_registry, NULL);
2062193de0dSXinchen Hui 	zend_hash_sort(&sorted_registry, module_name_cmp, 0);
207cec09117SDmitry Stogov 	ZEND_HASH_FOREACH_PTR(&sorted_registry, module) {
208cec09117SDmitry Stogov 		php_printf("%s\n", module->name);
209cec09117SDmitry Stogov 	} ZEND_HASH_FOREACH_END();
210d77d6153SAntony Dovgal 	zend_hash_destroy(&sorted_registry);
211d77d6153SAntony Dovgal }
21218cf4e0aSXinchen Hui /* }}} */
213d77d6153SAntony Dovgal 
print_extension_info(zend_extension * ext,void * arg)21418cf4e0aSXinchen Hui static int print_extension_info(zend_extension *ext, void *arg) /* {{{ */
215d77d6153SAntony Dovgal {
216d77d6153SAntony Dovgal 	php_printf("%s\n", ext->name);
217d77d6153SAntony Dovgal 	return 0;
218d77d6153SAntony Dovgal }
21918cf4e0aSXinchen Hui /* }}} */
220d77d6153SAntony Dovgal 
extension_name_cmp(const zend_llist_element ** f,const zend_llist_element ** s)22118cf4e0aSXinchen Hui static int extension_name_cmp(const zend_llist_element **f, const zend_llist_element **s) /* {{{ */
222d77d6153SAntony Dovgal {
2230cfb4765SDmitry Stogov 	zend_extension *fe = (zend_extension*)(*f)->data;
2240cfb4765SDmitry Stogov 	zend_extension *se = (zend_extension*)(*s)->data;
2250cfb4765SDmitry Stogov 	return strcmp(fe->name, se->name);
226d77d6153SAntony Dovgal }
22718cf4e0aSXinchen Hui /* }}} */
228d77d6153SAntony Dovgal 
print_extensions(void)22918cf4e0aSXinchen Hui static void print_extensions(void) /* {{{ */
230d77d6153SAntony Dovgal {
231d77d6153SAntony Dovgal 	zend_llist sorted_exts;
232d77d6153SAntony Dovgal 
233d77d6153SAntony Dovgal 	zend_llist_copy(&sorted_exts, &zend_extensions);
234d77d6153SAntony Dovgal 	sorted_exts.dtor = NULL;
235bdeb220fSAnatol Belski 	zend_llist_sort(&sorted_exts, extension_name_cmp);
236bdeb220fSAnatol Belski 	zend_llist_apply_with_argument(&sorted_exts, (llist_apply_with_arg_func_t) print_extension_info, NULL);
237d77d6153SAntony Dovgal 	zend_llist_destroy(&sorted_exts);
238d77d6153SAntony Dovgal }
23918cf4e0aSXinchen Hui /* }}} */
240d77d6153SAntony Dovgal 
241b7a7b1a6SStanislav Malyshev #ifndef STDOUT_FILENO
242b7a7b1a6SStanislav Malyshev #define STDOUT_FILENO 1
243eb180ac3SJérôme Loyet #endif
244eb180ac3SJérôme Loyet 
sapi_cgibin_single_write(const char * str,uint32_t str_length)245afb6ca25SAnatol Belski static inline size_t sapi_cgibin_single_write(const char *str, uint32_t str_length) /* {{{ */
246d77d6153SAntony Dovgal {
247e7472221SJérôme Loyet 	ssize_t ret;
248d77d6153SAntony Dovgal 
249eb180ac3SJérôme Loyet 	/* sapi has started which means everyhting must be send through fcgi */
250eb180ac3SJérôme Loyet 	if (fpm_is_running) {
251eb180ac3SJérôme Loyet 		fcgi_request *request = (fcgi_request*) SG(server_context);
252eb180ac3SJérôme Loyet 		ret = fcgi_write(request, FCGI_STDOUT, str, str_length);
253eb180ac3SJérôme Loyet 		if (ret <= 0) {
254eb180ac3SJérôme Loyet 			return 0;
255eb180ac3SJérôme Loyet 		}
256e7472221SJérôme Loyet 		return (size_t)ret;
257eb180ac3SJérôme Loyet 	}
258eb180ac3SJérôme Loyet 
259eb180ac3SJérôme Loyet 	/* sapi has not started, output to stdout instead of fcgi */
260b7a7b1a6SStanislav Malyshev #ifdef PHP_WRITE_STDOUT
261b7a7b1a6SStanislav Malyshev 	ret = write(STDOUT_FILENO, str, str_length);
2620b71f4f5SJérôme Loyet 	if (ret <= 0) {
2630b71f4f5SJérôme Loyet 		return 0;
264d77d6153SAntony Dovgal 	}
265e7472221SJérôme Loyet 	return (size_t)ret;
266eb180ac3SJérôme Loyet #else
267eb180ac3SJérôme Loyet 	return fwrite(str, 1, MIN(str_length, 16384), stdout);
268eb180ac3SJérôme Loyet #endif
269d77d6153SAntony Dovgal }
27018cf4e0aSXinchen Hui /* }}} */
271d77d6153SAntony Dovgal 
sapi_cgibin_ub_write(const char * str,size_t str_length)27218cf4e0aSXinchen Hui static size_t sapi_cgibin_ub_write(const char *str, size_t str_length) /* {{{ */
273d77d6153SAntony Dovgal {
274d77d6153SAntony Dovgal 	const char *ptr = str;
275afb6ca25SAnatol Belski 	uint32_t remaining = str_length;
276d77d6153SAntony Dovgal 	size_t ret;
277d77d6153SAntony Dovgal 
278d77d6153SAntony Dovgal 	while (remaining > 0) {
279bdeb220fSAnatol Belski 		ret = sapi_cgibin_single_write(ptr, remaining);
280d77d6153SAntony Dovgal 		if (!ret) {
281d77d6153SAntony Dovgal 			php_handle_aborted_connection();
282d77d6153SAntony Dovgal 			return str_length - remaining;
283d77d6153SAntony Dovgal 		}
284d77d6153SAntony Dovgal 		ptr += ret;
285d77d6153SAntony Dovgal 		remaining -= ret;
286d77d6153SAntony Dovgal 	}
287d77d6153SAntony Dovgal 
288d77d6153SAntony Dovgal 	return str_length;
289d77d6153SAntony Dovgal }
29018cf4e0aSXinchen Hui /* }}} */
291d77d6153SAntony Dovgal 
sapi_cgibin_flush(void * server_context)29218cf4e0aSXinchen Hui static void sapi_cgibin_flush(void *server_context) /* {{{ */
293d77d6153SAntony Dovgal {
294eb180ac3SJérôme Loyet 	/* fpm has started, let use fcgi instead of stdout */
295eb180ac3SJérôme Loyet 	if (fpm_is_running) {
296eb180ac3SJérôme Loyet 		fcgi_request *request = (fcgi_request*) server_context;
29708f10ef4SKalle Sommer Nielsen 		if (!parent && request && !fcgi_flush(request, 0)) {
298eb180ac3SJérôme Loyet 			php_handle_aborted_connection();
299eb180ac3SJérôme Loyet 		}
300eb180ac3SJérôme Loyet 		return;
301eb180ac3SJérôme Loyet 	}
302eb180ac3SJérôme Loyet 
303eb180ac3SJérôme Loyet 	/* fpm has not started yet, let use stdout instead of fcgi */
304eb180ac3SJérôme Loyet 	if (fflush(stdout) == EOF) {
305d77d6153SAntony Dovgal 		php_handle_aborted_connection();
306d77d6153SAntony Dovgal 	}
307d77d6153SAntony Dovgal }
30818cf4e0aSXinchen Hui /* }}} */
309d77d6153SAntony Dovgal 
310d77d6153SAntony Dovgal #define SAPI_CGI_MAX_HEADER_LENGTH 1024
311d77d6153SAntony Dovgal 
sapi_cgi_send_headers(sapi_headers_struct * sapi_headers)31218cf4e0aSXinchen Hui static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers) /* {{{ */
313d77d6153SAntony Dovgal {
314d77d6153SAntony Dovgal 	char buf[SAPI_CGI_MAX_HEADER_LENGTH];
315d77d6153SAntony Dovgal 	sapi_header_struct *h;
316d77d6153SAntony Dovgal 	zend_llist_position pos;
317d77d6153SAntony Dovgal 	zend_bool ignore_status = 0;
318d77d6153SAntony Dovgal 	int response_status = SG(sapi_headers).http_response_code;
319d77d6153SAntony Dovgal 
320d77d6153SAntony Dovgal 	if (SG(request_info).no_headers == 1) {
321d77d6153SAntony Dovgal 		return  SAPI_HEADER_SENT_SUCCESSFULLY;
322d77d6153SAntony Dovgal 	}
323d77d6153SAntony Dovgal 
324d77d6153SAntony Dovgal 	if (CGIG(nph) || SG(sapi_headers).http_response_code != 200)
325d77d6153SAntony Dovgal 	{
326d77d6153SAntony Dovgal 		int len;
327d77d6153SAntony Dovgal 		zend_bool has_status = 0;
328d77d6153SAntony Dovgal 
329d77d6153SAntony Dovgal 		if (CGIG(rfc2616_headers) && SG(sapi_headers).http_status_line) {
330d77d6153SAntony Dovgal 			char *s;
331*a054ef2aSChristoph M. Becker 			len = slprintf(buf, SAPI_CGI_MAX_HEADER_LENGTH, "%s", SG(sapi_headers).http_status_line);
332d77d6153SAntony Dovgal 			if ((s = strchr(SG(sapi_headers).http_status_line, ' '))) {
333d77d6153SAntony Dovgal 				response_status = atoi((s + 1));
334d77d6153SAntony Dovgal 			}
335d77d6153SAntony Dovgal 
336d77d6153SAntony Dovgal 			if (len > SAPI_CGI_MAX_HEADER_LENGTH) {
337d77d6153SAntony Dovgal 				len = SAPI_CGI_MAX_HEADER_LENGTH;
338d77d6153SAntony Dovgal 			}
339d77d6153SAntony Dovgal 
340d77d6153SAntony Dovgal 		} else {
341d77d6153SAntony Dovgal 			char *s;
342d77d6153SAntony Dovgal 
343d77d6153SAntony Dovgal 			if (SG(sapi_headers).http_status_line &&
344d77d6153SAntony Dovgal 				(s = strchr(SG(sapi_headers).http_status_line, ' ')) != 0 &&
345d77d6153SAntony Dovgal 				(s - SG(sapi_headers).http_status_line) >= 5 &&
346d77d6153SAntony Dovgal 				strncasecmp(SG(sapi_headers).http_status_line, "HTTP/", 5) == 0
347d77d6153SAntony Dovgal 			) {
348*a054ef2aSChristoph M. Becker 				len = slprintf(buf, sizeof(buf), "Status:%s", s);
349d77d6153SAntony Dovgal 				response_status = atoi((s + 1));
350d77d6153SAntony Dovgal 			} else {
351d77d6153SAntony Dovgal 				h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
352d77d6153SAntony Dovgal 				while (h) {
3530494615bSJérôme Loyet 					if (h->header_len > sizeof("Status:") - 1 &&
3540494615bSJérôme Loyet 						strncasecmp(h->header, "Status:", sizeof("Status:") - 1) == 0
355d77d6153SAntony Dovgal 					) {
356d77d6153SAntony Dovgal 						has_status = 1;
357d77d6153SAntony Dovgal 						break;
358d77d6153SAntony Dovgal 					}
359d77d6153SAntony Dovgal 					h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
360d77d6153SAntony Dovgal 				}
361d77d6153SAntony Dovgal 				if (!has_status) {
362e20cbdbeSAndrea Faulds 					http_response_status_code_pair *err = (http_response_status_code_pair*)http_status_map;
363d77d6153SAntony Dovgal 
364d77d6153SAntony Dovgal 					while (err->code != 0) {
365d77d6153SAntony Dovgal 						if (err->code == SG(sapi_headers).http_response_code) {
366d77d6153SAntony Dovgal 							break;
367d77d6153SAntony Dovgal 						}
368d77d6153SAntony Dovgal 						err++;
369d77d6153SAntony Dovgal 					}
370e20cbdbeSAndrea Faulds 					if (err->str) {
371*a054ef2aSChristoph M. Becker 						len = slprintf(buf, sizeof(buf), "Status: %d %s", SG(sapi_headers).http_response_code, err->str);
372d77d6153SAntony Dovgal 					} else {
373*a054ef2aSChristoph M. Becker 						len = slprintf(buf, sizeof(buf), "Status: %d", SG(sapi_headers).http_response_code);
374d77d6153SAntony Dovgal 					}
375d77d6153SAntony Dovgal 				}
376d77d6153SAntony Dovgal 			}
377d77d6153SAntony Dovgal 		}
378d77d6153SAntony Dovgal 
379d77d6153SAntony Dovgal 		if (!has_status) {
380d77d6153SAntony Dovgal 			PHPWRITE_H(buf, len);
381*a054ef2aSChristoph M. Becker 			PHPWRITE_H("\r\n", 2);
382d77d6153SAntony Dovgal 			ignore_status = 1;
383d77d6153SAntony Dovgal 		}
384d77d6153SAntony Dovgal 	}
385d77d6153SAntony Dovgal 
386d77d6153SAntony Dovgal 	h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
387d77d6153SAntony Dovgal 	while (h) {
388d77d6153SAntony Dovgal 		/* prevent CRLFCRLF */
389d77d6153SAntony Dovgal 		if (h->header_len) {
390b7a7b1a6SStanislav Malyshev 			if (h->header_len > sizeof("Status:") - 1 &&
3910494615bSJérôme Loyet 				strncasecmp(h->header, "Status:", sizeof("Status:") - 1) == 0
392d77d6153SAntony Dovgal 			) {
393d77d6153SAntony Dovgal 				if (!ignore_status) {
394d77d6153SAntony Dovgal 					ignore_status = 1;
395d77d6153SAntony Dovgal 					PHPWRITE_H(h->header, h->header_len);
396d77d6153SAntony Dovgal 					PHPWRITE_H("\r\n", 2);
397d77d6153SAntony Dovgal 				}
3980494615bSJérôme Loyet 			} else if (response_status == 304 && h->header_len > sizeof("Content-Type:") - 1 &&
3990494615bSJérôme Loyet 				strncasecmp(h->header, "Content-Type:", sizeof("Content-Type:") - 1) == 0
400d77d6153SAntony Dovgal 			) {
401d77d6153SAntony Dovgal 				h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
402d77d6153SAntony Dovgal 				continue;
403d77d6153SAntony Dovgal 			} else {
404d77d6153SAntony Dovgal 				PHPWRITE_H(h->header, h->header_len);
405d77d6153SAntony Dovgal 				PHPWRITE_H("\r\n", 2);
406d77d6153SAntony Dovgal 			}
407d77d6153SAntony Dovgal 		}
408d77d6153SAntony Dovgal 		h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
409d77d6153SAntony Dovgal 	}
410d77d6153SAntony Dovgal 	PHPWRITE_H("\r\n", 2);
411d77d6153SAntony Dovgal 
412d77d6153SAntony Dovgal 	return SAPI_HEADER_SENT_SUCCESSFULLY;
413d77d6153SAntony Dovgal }
41418cf4e0aSXinchen Hui /* }}} */
415d77d6153SAntony Dovgal 
416d77d6153SAntony Dovgal #ifndef STDIN_FILENO
417d77d6153SAntony Dovgal # define STDIN_FILENO 0
418d77d6153SAntony Dovgal #endif
419d77d6153SAntony Dovgal 
42086de98caSXinchen Hui #ifndef HAVE_ATTRIBUTE_WEAK
fpm_fcgi_log(int type,const char * fmt,...)42118cf4e0aSXinchen Hui static void fpm_fcgi_log(int type, const char *fmt, ...) /* {{{ */
42286de98caSXinchen Hui #else
42386de98caSXinchen Hui void fcgi_log(int type, const char *fmt, ...)
42486de98caSXinchen Hui #endif
42518cf4e0aSXinchen Hui {
42618cf4e0aSXinchen Hui 	va_list args;
42718cf4e0aSXinchen Hui 	va_start(args, fmt);
42818cf4e0aSXinchen Hui 	vzlog("", 0, type, fmt, args);
42918cf4e0aSXinchen Hui 	va_end(args);
43018cf4e0aSXinchen Hui }
43118cf4e0aSXinchen Hui /* }}} */
43218cf4e0aSXinchen Hui 
sapi_cgi_read_post(char * buffer,size_t count_bytes)43318cf4e0aSXinchen Hui static size_t sapi_cgi_read_post(char *buffer, size_t count_bytes) /* {{{ */
434d77d6153SAntony Dovgal {
435afb6ca25SAnatol Belski 	uint32_t read_bytes = 0;
436d77d6153SAntony Dovgal 	int tmp_read_bytes;
4378962f3ffSMichael Wallner 	size_t remaining = SG(request_info).content_length - SG(read_post_bytes);
438d77d6153SAntony Dovgal 
4398962f3ffSMichael Wallner 	if (remaining < count_bytes) {
4408962f3ffSMichael Wallner 		count_bytes = remaining;
4418962f3ffSMichael Wallner 	}
442d77d6153SAntony Dovgal 	while (read_bytes < count_bytes) {
4430b71f4f5SJérôme Loyet 		fcgi_request *request = (fcgi_request*) SG(server_context);
4440b71f4f5SJérôme Loyet 		if (request_body_fd == -1) {
445abb616aeSDmitry Stogov 			char *request_body_filename = FCGI_GETENV(request, "REQUEST_BODY_FILE");
4460b71f4f5SJérôme Loyet 
4470b71f4f5SJérôme Loyet 			if (request_body_filename && *request_body_filename) {
4480b71f4f5SJérôme Loyet 				request_body_fd = open(request_body_filename, O_RDONLY);
4490b71f4f5SJérôme Loyet 
4500b71f4f5SJérôme Loyet 				if (0 > request_body_fd) {
4510b71f4f5SJérôme Loyet 					php_error(E_WARNING, "REQUEST_BODY_FILE: open('%s') failed: %s (%d)",
4520b71f4f5SJérôme Loyet 							request_body_filename, strerror(errno), errno);
4530b71f4f5SJérôme Loyet 					return 0;
454d77d6153SAntony Dovgal 				}
455d77d6153SAntony Dovgal 			}
4560b71f4f5SJérôme Loyet 		}
457d77d6153SAntony Dovgal 
4580b71f4f5SJérôme Loyet 		/* If REQUEST_BODY_FILE variable not available - read post body from fastcgi stream */
4590b71f4f5SJérôme Loyet 		if (request_body_fd < 0) {
4600b71f4f5SJérôme Loyet 			tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes);
461d77d6153SAntony Dovgal 		} else {
4620b71f4f5SJérôme Loyet 			tmp_read_bytes = read(request_body_fd, buffer + read_bytes, count_bytes - read_bytes);
463d77d6153SAntony Dovgal 		}
464d77d6153SAntony Dovgal 		if (tmp_read_bytes <= 0) {
465d77d6153SAntony Dovgal 			break;
466d77d6153SAntony Dovgal 		}
467d77d6153SAntony Dovgal 		read_bytes += tmp_read_bytes;
468d77d6153SAntony Dovgal 	}
469d77d6153SAntony Dovgal 	return read_bytes;
470d77d6153SAntony Dovgal }
47118cf4e0aSXinchen Hui /* }}} */
472d77d6153SAntony Dovgal 
sapi_cgibin_getenv(char * name,size_t name_len)47318cf4e0aSXinchen Hui static char *sapi_cgibin_getenv(char *name, size_t name_len) /* {{{ */
474d77d6153SAntony Dovgal {
475eb180ac3SJérôme Loyet 	/* if fpm has started, use fcgi env */
476eb180ac3SJérôme Loyet 	if (fpm_is_running) {
477eb180ac3SJérôme Loyet 		fcgi_request *request = (fcgi_request*) SG(server_context);
478eb180ac3SJérôme Loyet 		return fcgi_getenv(request, name, name_len);
479eb180ac3SJérôme Loyet 	}
480eb180ac3SJérôme Loyet 
481eb180ac3SJérôme Loyet 	/* if fpm has not started yet, use std env */
482eb180ac3SJérôme Loyet 	return getenv(name);
483d77d6153SAntony Dovgal }
48418cf4e0aSXinchen Hui /* }}} */
485d77d6153SAntony Dovgal 
4862b41c041SXinchen Hui #if 0
48718cf4e0aSXinchen Hui static char *_sapi_cgibin_putenv(char *name, char *value) /* {{{ */
488d77d6153SAntony Dovgal {
489d77d6153SAntony Dovgal 	int name_len;
490d77d6153SAntony Dovgal 
491d77d6153SAntony Dovgal 	if (!name) {
492d77d6153SAntony Dovgal 		return NULL;
493d77d6153SAntony Dovgal 	}
494d77d6153SAntony Dovgal 	name_len = strlen(name);
495d77d6153SAntony Dovgal 
4960b71f4f5SJérôme Loyet 	fcgi_request *request = (fcgi_request*) SG(server_context);
4970b71f4f5SJérôme Loyet 	return fcgi_putenv(request, name, name_len, value);
498d77d6153SAntony Dovgal }
49918cf4e0aSXinchen Hui /* }}} */
5002b41c041SXinchen Hui #endif
501d77d6153SAntony Dovgal 
sapi_cgi_read_cookies(void)50218cf4e0aSXinchen Hui static char *sapi_cgi_read_cookies(void) /* {{{ */
503d77d6153SAntony Dovgal {
504abb616aeSDmitry Stogov 	fcgi_request *request = (fcgi_request*) SG(server_context);
505abb616aeSDmitry Stogov 
506abb616aeSDmitry Stogov 	return FCGI_GETENV(request, "HTTP_COOKIE");
507abb616aeSDmitry Stogov }
50818cf4e0aSXinchen Hui /* }}} */
509abb616aeSDmitry Stogov 
cgi_php_load_env_var(char * var,unsigned int var_len,char * val,unsigned int val_len,void * arg)51018cf4e0aSXinchen Hui static void cgi_php_load_env_var(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg) /* {{{ */
511abb616aeSDmitry Stogov {
512abb616aeSDmitry Stogov 	zval *array_ptr = (zval*)arg;
513abb616aeSDmitry Stogov 	int filter_arg = (Z_ARR_P(array_ptr) == Z_ARR(PG(http_globals)[TRACK_VARS_ENV]))?PARSE_ENV:PARSE_SERVER;
514abb616aeSDmitry Stogov 	size_t new_val_len;
515abb616aeSDmitry Stogov 
516abb616aeSDmitry Stogov 	if (sapi_module.input_filter(filter_arg, var, &val, strlen(val), &new_val_len)) {
517abb616aeSDmitry Stogov 		php_register_variable_safe(var, val, new_val_len, array_ptr);
518abb616aeSDmitry Stogov 	}
519d77d6153SAntony Dovgal }
52018cf4e0aSXinchen Hui /* }}} */
521d77d6153SAntony Dovgal 
cgi_php_import_environment_variables(zval * array_ptr)52218cf4e0aSXinchen Hui void cgi_php_import_environment_variables(zval *array_ptr) /* {{{ */
523d77d6153SAntony Dovgal {
524f0d2a0e5SDmitry Stogov 	fcgi_request *request = NULL;
5250b71f4f5SJérôme Loyet 
526404cc45eSNikita Popov 	if (Z_TYPE(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY &&
527404cc45eSNikita Popov 		Z_ARR_P(array_ptr) != Z_ARR(PG(http_globals)[TRACK_VARS_ENV]) &&
528404cc45eSNikita Popov 		zend_hash_num_elements(Z_ARRVAL(PG(http_globals)[TRACK_VARS_ENV])) > 0
529d77d6153SAntony Dovgal 	) {
530c890d469SDmitry Stogov 		zend_array_destroy(Z_ARR_P(array_ptr));
531c890d469SDmitry Stogov 		Z_ARR_P(array_ptr) = zend_array_dup(Z_ARR(PG(http_globals)[TRACK_VARS_ENV]));
532d77d6153SAntony Dovgal 		return;
533404cc45eSNikita Popov 	} else if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY &&
534404cc45eSNikita Popov 		Z_ARR_P(array_ptr) != Z_ARR(PG(http_globals)[TRACK_VARS_SERVER]) &&
535404cc45eSNikita Popov 		zend_hash_num_elements(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER])) > 0
536d77d6153SAntony Dovgal 	) {
537c890d469SDmitry Stogov 		zend_array_destroy(Z_ARR_P(array_ptr));
538c890d469SDmitry Stogov 		Z_ARR_P(array_ptr) = zend_array_dup(Z_ARR(PG(http_globals)[TRACK_VARS_SERVER]));
539d77d6153SAntony Dovgal 		return;
540d77d6153SAntony Dovgal 	}
541d77d6153SAntony Dovgal 
542d77d6153SAntony Dovgal 	/* call php's original import as a catch-all */
543bdeb220fSAnatol Belski 	php_php_import_environment_variables(array_ptr);
544d77d6153SAntony Dovgal 
5450b71f4f5SJérôme Loyet 	request = (fcgi_request*) SG(server_context);
546abb616aeSDmitry Stogov 	fcgi_loadenv(request, cgi_php_load_env_var, array_ptr);
547d77d6153SAntony Dovgal }
54818cf4e0aSXinchen Hui /* }}} */
549d77d6153SAntony Dovgal 
sapi_cgi_register_variables(zval * track_vars_array)55018cf4e0aSXinchen Hui static void sapi_cgi_register_variables(zval *track_vars_array) /* {{{ */
551d77d6153SAntony Dovgal {
552df7b6779SXinchen Hui 	size_t php_self_len;
553d77d6153SAntony Dovgal 	char *php_self;
554d77d6153SAntony Dovgal 
555d77d6153SAntony Dovgal 	/* In CGI mode, we consider the environment to be a part of the server
556d77d6153SAntony Dovgal 	 * variables
557d77d6153SAntony Dovgal 	 */
558bdeb220fSAnatol Belski 	php_import_environment_variables(track_vars_array);
559d77d6153SAntony Dovgal 
560d77d6153SAntony Dovgal 	if (CGIG(fix_pathinfo)) {
561d77d6153SAntony Dovgal 		char *script_name = SG(request_info).request_uri;
562d77d6153SAntony Dovgal 		unsigned int script_name_len = script_name ? strlen(script_name) : 0;
56385eece9cSXinchen Hui 		char *path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO") - 1);
564d77d6153SAntony Dovgal 		unsigned int path_info_len = path_info ? strlen(path_info) : 0;
565d77d6153SAntony Dovgal 
566d77d6153SAntony Dovgal 		php_self_len = script_name_len + path_info_len;
567d77d6153SAntony Dovgal 		php_self = emalloc(php_self_len + 1);
568d77d6153SAntony Dovgal 
5690494615bSJérôme Loyet 		/* Concat script_name and path_info into php_self */
570d77d6153SAntony Dovgal 		if (script_name) {
571d77d6153SAntony Dovgal 			memcpy(php_self, script_name, script_name_len + 1);
572d77d6153SAntony Dovgal 		}
573d77d6153SAntony Dovgal 		if (path_info) {
574d77d6153SAntony Dovgal 			memcpy(php_self + script_name_len, path_info, path_info_len + 1);
575d77d6153SAntony Dovgal 		}
576d77d6153SAntony Dovgal 
577d77d6153SAntony Dovgal 		/* Build the special-case PHP_SELF variable for the CGI version */
578bdeb220fSAnatol Belski 		if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len)) {
579bdeb220fSAnatol Belski 			php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array);
580d77d6153SAntony Dovgal 		}
581d77d6153SAntony Dovgal 		efree(php_self);
582d77d6153SAntony Dovgal 	} else {
583d77d6153SAntony Dovgal 		php_self = SG(request_info).request_uri ? SG(request_info).request_uri : "";
584d77d6153SAntony Dovgal 		php_self_len = strlen(php_self);
585bdeb220fSAnatol Belski 		if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len)) {
586bdeb220fSAnatol Belski 			php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array);
587d77d6153SAntony Dovgal 		}
588d77d6153SAntony Dovgal 	}
589d77d6153SAntony Dovgal }
59018cf4e0aSXinchen Hui /* }}} */
591d77d6153SAntony Dovgal 
592dce25909SJerome Loyet /* {{{ sapi_cgi_log_fastcgi
593dce25909SJerome Loyet  *
594dce25909SJerome Loyet  * Ignore level, we want to send all messages through fastcgi
595dce25909SJerome Loyet  */
sapi_cgi_log_fastcgi(int level,char * message,size_t len)596dce25909SJerome Loyet void sapi_cgi_log_fastcgi(int level, char *message, size_t len)
597d77d6153SAntony Dovgal {
598dce25909SJerome Loyet 
599dce25909SJerome Loyet 	fcgi_request *request = (fcgi_request*) SG(server_context);
600dce25909SJerome Loyet 
6013e5afbf0SJakub Zelenka 	/* message is written to FCGI_STDERR if following conditions are met:
6023e5afbf0SJakub Zelenka 	 * - logging is enabled (fastcgi.logging in php.ini)
603dce25909SJerome Loyet 	 * - we are currently dealing with a request
604dce25909SJerome Loyet 	 * - the message is not empty
6053e5afbf0SJakub Zelenka 	 * - the fcgi_write did not fail
606dce25909SJerome Loyet 	 */
6073e5afbf0SJakub Zelenka 	if (CGIG(fcgi_logging) && request && message && len > 0
6083e5afbf0SJakub Zelenka 			&& fcgi_write(request, FCGI_STDERR, message, len) < 0) {
6093e5afbf0SJakub Zelenka 		php_handle_aborted_connection();
610d77d6153SAntony Dovgal 	}
611d77d6153SAntony Dovgal }
612dce25909SJerome Loyet /* }}} */
613dce25909SJerome Loyet 
614dce25909SJerome Loyet /* {{{ sapi_cgi_log_message
615dce25909SJerome Loyet  */
sapi_cgi_log_message(char * message,int syslog_type_int)6162809a676SMartin Vobruba static void sapi_cgi_log_message(char *message, int syslog_type_int)
617dce25909SJerome Loyet {
6183e5afbf0SJakub Zelenka 	zlog_msg(ZLOG_NOTICE, "PHP message: ", message);
619dce25909SJerome Loyet }
620dce25909SJerome Loyet /* }}} */
621d77d6153SAntony Dovgal 
622d77d6153SAntony Dovgal /* {{{ php_cgi_ini_activate_user_config
623d77d6153SAntony Dovgal  */
php_cgi_ini_activate_user_config(char * path,int path_len,const char * doc_root,int doc_root_len)624f62571c1SNikita Popov static void php_cgi_ini_activate_user_config(char *path, int path_len, const char *doc_root, int doc_root_len)
625d77d6153SAntony Dovgal {
626d77d6153SAntony Dovgal 	char *ptr;
627bdeb220fSAnatol Belski 	time_t request_time = sapi_get_request_time();
628404cc45eSNikita Popov 	user_config_cache_entry *entry = zend_hash_str_find_ptr(&CGIG(user_config_cache), path, path_len);
629d77d6153SAntony Dovgal 
630d77d6153SAntony Dovgal 	/* Find cached config entry: If not found, create one */
631404cc45eSNikita Popov 	if (!entry) {
632404cc45eSNikita Popov 		entry = pemalloc(sizeof(user_config_cache_entry), 1);
633404cc45eSNikita Popov 		entry->expires = 0;
634404cc45eSNikita Popov 		entry->user_config = (HashTable *) pemalloc(sizeof(HashTable), 1);
635c242518bSXinchen Hui 		zend_hash_init(entry->user_config, 0, NULL, config_zval_dtor, 1);
636404cc45eSNikita Popov 		zend_hash_str_update_ptr(&CGIG(user_config_cache), path, path_len, entry);
637d77d6153SAntony Dovgal 	}
638d77d6153SAntony Dovgal 
639d77d6153SAntony Dovgal 	/* Check whether cache entry has expired and rescan if it is */
640d77d6153SAntony Dovgal 	if (request_time > entry->expires) {
641d77d6153SAntony Dovgal 		char * real_path;
642d77d6153SAntony Dovgal 		int real_path_len;
643d77d6153SAntony Dovgal 		char *s1, *s2;
644d77d6153SAntony Dovgal 		int s_len;
645d77d6153SAntony Dovgal 
646d77d6153SAntony Dovgal 		/* Clear the expired config */
647d77d6153SAntony Dovgal 		zend_hash_clean(entry->user_config);
648d77d6153SAntony Dovgal 
649d77d6153SAntony Dovgal 		if (!IS_ABSOLUTE_PATH(path, path_len)) {
650bdeb220fSAnatol Belski 			real_path = tsrm_realpath(path, NULL);
65147aa194aSAntony Dovgal 			if (real_path == NULL) {
65247aa194aSAntony Dovgal 				return;
65347aa194aSAntony Dovgal 			}
654d77d6153SAntony Dovgal 			real_path_len = strlen(real_path);
655d77d6153SAntony Dovgal 			path = real_path;
656d77d6153SAntony Dovgal 			path_len = real_path_len;
657d77d6153SAntony Dovgal 		}
658d77d6153SAntony Dovgal 
659d77d6153SAntony Dovgal 		if (path_len > doc_root_len) {
660d77d6153SAntony Dovgal 			s1 = (char *) doc_root;
661d77d6153SAntony Dovgal 			s2 = path;
662d77d6153SAntony Dovgal 			s_len = doc_root_len;
663d77d6153SAntony Dovgal 		} else {
664d77d6153SAntony Dovgal 			s1 = path;
665d77d6153SAntony Dovgal 			s2 = (char *) doc_root;
666d77d6153SAntony Dovgal 			s_len = path_len;
667d77d6153SAntony Dovgal 		}
668d77d6153SAntony Dovgal 
669d77d6153SAntony Dovgal 		/* we have to test if path is part of DOCUMENT_ROOT.
670b7a7b1a6SStanislav Malyshev 		  if it is inside the docroot, we scan the tree up to the docroot
671d77d6153SAntony Dovgal 			to find more user.ini, if not we only scan the current path.
672d77d6153SAntony Dovgal 		  */
673d77d6153SAntony Dovgal 		if (strncmp(s1, s2, s_len) == 0) {
674f62571c1SNikita Popov 			ptr = s2 + doc_root_len;
675d77d6153SAntony Dovgal 			while ((ptr = strchr(ptr, DEFAULT_SLASH)) != NULL) {
676d77d6153SAntony Dovgal 				*ptr = 0;
677bdeb220fSAnatol Belski 				php_parse_user_ini_file(path, PG(user_ini_filename), entry->user_config);
678d77d6153SAntony Dovgal 				*ptr = '/';
679d77d6153SAntony Dovgal 				ptr++;
680d77d6153SAntony Dovgal 			}
681d77d6153SAntony Dovgal 		} else {
682bdeb220fSAnatol Belski 			php_parse_user_ini_file(path, PG(user_ini_filename), entry->user_config);
683d77d6153SAntony Dovgal 		}
684d77d6153SAntony Dovgal 
685d77d6153SAntony Dovgal 		entry->expires = request_time + PG(user_ini_cache_ttl);
686d77d6153SAntony Dovgal 	}
687d77d6153SAntony Dovgal 
688d77d6153SAntony Dovgal 	/* Activate ini entries with values from the user config hash */
689bdeb220fSAnatol Belski 	php_ini_activate_config(entry->user_config, PHP_INI_PERDIR, PHP_INI_STAGE_HTACCESS);
690d77d6153SAntony Dovgal }
691d77d6153SAntony Dovgal /* }}} */
692d77d6153SAntony Dovgal 
sapi_cgi_activate(void)69318cf4e0aSXinchen Hui static int sapi_cgi_activate(void) /* {{{ */
694d77d6153SAntony Dovgal {
695abb616aeSDmitry Stogov 	fcgi_request *request = (fcgi_request*) SG(server_context);
696d77d6153SAntony Dovgal 	char *path, *doc_root, *server_name;
697afb6ca25SAnatol Belski 	uint32_t path_len, doc_root_len, server_name_len;
698d77d6153SAntony Dovgal 
699d77d6153SAntony Dovgal 	/* PATH_TRANSLATED should be defined at this stage but better safe than sorry :) */
700d77d6153SAntony Dovgal 	if (!SG(request_info).path_translated) {
701d77d6153SAntony Dovgal 		return FAILURE;
702d77d6153SAntony Dovgal 	}
703d77d6153SAntony Dovgal 
704d77d6153SAntony Dovgal 	if (php_ini_has_per_host_config()) {
705d77d6153SAntony Dovgal 		/* Activate per-host-system-configuration defined in php.ini and stored into configuration_hash during startup */
706abb616aeSDmitry Stogov 		server_name = FCGI_GETENV(request, "SERVER_NAME");
707d77d6153SAntony Dovgal 		/* SERVER_NAME should also be defined at this stage..but better check it anyway */
708d77d6153SAntony Dovgal 		if (server_name) {
709d77d6153SAntony Dovgal 			server_name_len = strlen(server_name);
710d77d6153SAntony Dovgal 			server_name = estrndup(server_name, server_name_len);
711d77d6153SAntony Dovgal 			zend_str_tolower(server_name, server_name_len);
712bdeb220fSAnatol Belski 			php_ini_activate_per_host_config(server_name, server_name_len);
713d77d6153SAntony Dovgal 			efree(server_name);
714d77d6153SAntony Dovgal 		}
715d77d6153SAntony Dovgal 	}
716d77d6153SAntony Dovgal 
717d77d6153SAntony Dovgal 	if (php_ini_has_per_dir_config() ||
718d77d6153SAntony Dovgal 		(PG(user_ini_filename) && *PG(user_ini_filename))
719d77d6153SAntony Dovgal 	) {
720d77d6153SAntony Dovgal 		/* Prepare search path */
721d77d6153SAntony Dovgal 		path_len = strlen(SG(request_info).path_translated);
722d77d6153SAntony Dovgal 
723d77d6153SAntony Dovgal 		/* Make sure we have trailing slash! */
724d77d6153SAntony Dovgal 		if (!IS_SLASH(SG(request_info).path_translated[path_len])) {
725d77d6153SAntony Dovgal 			path = emalloc(path_len + 2);
726d77d6153SAntony Dovgal 			memcpy(path, SG(request_info).path_translated, path_len + 1);
727d77d6153SAntony Dovgal 			path_len = zend_dirname(path, path_len);
728d77d6153SAntony Dovgal 			path[path_len++] = DEFAULT_SLASH;
729d77d6153SAntony Dovgal 		} else {
730d77d6153SAntony Dovgal 			path = estrndup(SG(request_info).path_translated, path_len);
731d77d6153SAntony Dovgal 			path_len = zend_dirname(path, path_len);
732d77d6153SAntony Dovgal 		}
733d77d6153SAntony Dovgal 		path[path_len] = 0;
734d77d6153SAntony Dovgal 
735d77d6153SAntony Dovgal 		/* Activate per-dir-system-configuration defined in php.ini and stored into configuration_hash during startup */
736bdeb220fSAnatol Belski 		php_ini_activate_per_dir_config(path, path_len); /* Note: for global settings sake we check from root to path */
737d77d6153SAntony Dovgal 
738d77d6153SAntony Dovgal 		/* Load and activate user ini files in path starting from DOCUMENT_ROOT */
739d77d6153SAntony Dovgal 		if (PG(user_ini_filename) && *PG(user_ini_filename)) {
740abb616aeSDmitry Stogov 			doc_root = FCGI_GETENV(request, "DOCUMENT_ROOT");
741d77d6153SAntony Dovgal 			/* DOCUMENT_ROOT should also be defined at this stage..but better check it anyway */
742d77d6153SAntony Dovgal 			if (doc_root) {
743d77d6153SAntony Dovgal 				doc_root_len = strlen(doc_root);
744d77d6153SAntony Dovgal 				if (doc_root_len > 0 && IS_SLASH(doc_root[doc_root_len - 1])) {
745d77d6153SAntony Dovgal 					--doc_root_len;
746d77d6153SAntony Dovgal 				}
74708f10ef4SKalle Sommer Nielsen 
748f62571c1SNikita Popov 				php_cgi_ini_activate_user_config(path, path_len, doc_root, doc_root_len);
749d77d6153SAntony Dovgal 			}
750d77d6153SAntony Dovgal 		}
751d77d6153SAntony Dovgal 
752d77d6153SAntony Dovgal 		efree(path);
753d77d6153SAntony Dovgal 	}
754d77d6153SAntony Dovgal 
755d77d6153SAntony Dovgal 	return SUCCESS;
756d77d6153SAntony Dovgal }
75718cf4e0aSXinchen Hui /* }}} */
758d77d6153SAntony Dovgal 
sapi_cgi_deactivate(void)75918cf4e0aSXinchen Hui static int sapi_cgi_deactivate(void) /* {{{ */
760d77d6153SAntony Dovgal {
761d77d6153SAntony Dovgal 	/* flush only when SAPI was started. The reasons are:
762d77d6153SAntony Dovgal 		1. SAPI Deactivate is called from two places: module init and request shutdown
763d77d6153SAntony Dovgal 		2. When the first call occurs and the request is not set up, flush fails on FastCGI.
764d77d6153SAntony Dovgal 	*/
765d77d6153SAntony Dovgal 	if (SG(sapi_started)) {
76608f10ef4SKalle Sommer Nielsen 		if (!parent && !fcgi_finish_request((fcgi_request*)SG(server_context), 0)) {
7670b71f4f5SJérôme Loyet 			php_handle_aborted_connection();
768d77d6153SAntony Dovgal 		}
769d77d6153SAntony Dovgal 	}
770d77d6153SAntony Dovgal 	return SUCCESS;
771d77d6153SAntony Dovgal }
77218cf4e0aSXinchen Hui /* }}} */
773d77d6153SAntony Dovgal 
php_cgi_startup(sapi_module_struct * sapi_module)77418cf4e0aSXinchen Hui static int php_cgi_startup(sapi_module_struct *sapi_module) /* {{{ */
775d77d6153SAntony Dovgal {
776d77d6153SAntony Dovgal 	if (php_module_startup(sapi_module, &cgi_module_entry, 1) == FAILURE) {
777d77d6153SAntony Dovgal 		return FAILURE;
778d77d6153SAntony Dovgal 	}
779d77d6153SAntony Dovgal 	return SUCCESS;
780d77d6153SAntony Dovgal }
78118cf4e0aSXinchen Hui /* }}} */
782d77d6153SAntony Dovgal 
783d77d6153SAntony Dovgal /* {{{ sapi_module_struct cgi_sapi_module
784d77d6153SAntony Dovgal  */
785d77d6153SAntony Dovgal static sapi_module_struct cgi_sapi_module = {
786d77d6153SAntony Dovgal 	"fpm-fcgi",						/* name */
787d77d6153SAntony Dovgal 	"FPM/FastCGI",					/* pretty name */
788d77d6153SAntony Dovgal 
789d77d6153SAntony Dovgal 	php_cgi_startup,				/* startup */
790d77d6153SAntony Dovgal 	php_module_shutdown_wrapper,	/* shutdown */
791d77d6153SAntony Dovgal 
792d77d6153SAntony Dovgal 	sapi_cgi_activate,				/* activate */
793d77d6153SAntony Dovgal 	sapi_cgi_deactivate,			/* deactivate */
794d77d6153SAntony Dovgal 
795d77d6153SAntony Dovgal 	sapi_cgibin_ub_write,			/* unbuffered write */
796d77d6153SAntony Dovgal 	sapi_cgibin_flush,				/* flush */
797d77d6153SAntony Dovgal 	NULL,							/* get uid */
798d77d6153SAntony Dovgal 	sapi_cgibin_getenv,				/* getenv */
799d77d6153SAntony Dovgal 
800d77d6153SAntony Dovgal 	php_error,						/* error handler */
801d77d6153SAntony Dovgal 
802d77d6153SAntony Dovgal 	NULL,							/* header handler */
803d77d6153SAntony Dovgal 	sapi_cgi_send_headers,			/* send headers handler */
804d77d6153SAntony Dovgal 	NULL,							/* send header handler */
805d77d6153SAntony Dovgal 
806d77d6153SAntony Dovgal 	sapi_cgi_read_post,				/* read POST data */
807d77d6153SAntony Dovgal 	sapi_cgi_read_cookies,			/* read Cookies */
808d77d6153SAntony Dovgal 
809d77d6153SAntony Dovgal 	sapi_cgi_register_variables,	/* register server variables */
810d77d6153SAntony Dovgal 	sapi_cgi_log_message,			/* Log message */
811d77d6153SAntony Dovgal 	NULL,							/* Get request time */
812d77d6153SAntony Dovgal 	NULL,							/* Child terminate */
813d77d6153SAntony Dovgal 
814d77d6153SAntony Dovgal 	STANDARD_SAPI_MODULE_PROPERTIES
815d77d6153SAntony Dovgal };
816d77d6153SAntony Dovgal /* }}} */
817d77d6153SAntony Dovgal 
818d77d6153SAntony Dovgal /* {{{ php_cgi_usage
819d77d6153SAntony Dovgal  */
php_cgi_usage(char * argv0)820d77d6153SAntony Dovgal static void php_cgi_usage(char *argv0)
821d77d6153SAntony Dovgal {
822d77d6153SAntony Dovgal 	char *prog;
823d77d6153SAntony Dovgal 
824d77d6153SAntony Dovgal 	prog = strrchr(argv0, '/');
825d77d6153SAntony Dovgal 	if (prog) {
826d77d6153SAntony Dovgal 		prog++;
827d77d6153SAntony Dovgal 	} else {
828d77d6153SAntony Dovgal 		prog = "php";
829d77d6153SAntony Dovgal 	}
830d77d6153SAntony Dovgal 
83132d9409aSGernot Vormayr 	php_printf(	"Usage: %s [-n] [-e] [-h] [-i] [-m] [-v] [-t] [-p <prefix>] [-g <pid>] [-c <file>] [-d foo[=bar]] [-y <file>] [-D] [-F [-O]]\n"
832d77d6153SAntony Dovgal 				"  -c <path>|<file> Look for php.ini file in this directory\n"
833d77d6153SAntony Dovgal 				"  -n               No php.ini file will be used\n"
834d77d6153SAntony Dovgal 				"  -d foo[=bar]     Define INI entry foo with value 'bar'\n"
835d77d6153SAntony Dovgal 				"  -e               Generate extended information for debugger/profiler\n"
836d77d6153SAntony Dovgal 				"  -h               This help\n"
837d77d6153SAntony Dovgal 				"  -i               PHP information\n"
838d77d6153SAntony Dovgal 				"  -m               Show compiled in modules\n"
839d77d6153SAntony Dovgal 				"  -v               Version number\n"
840ae01a576SJérôme Loyet 				"  -p, --prefix <dir>\n"
841ae01a576SJérôme Loyet 				"                   Specify alternative prefix path to FastCGI process manager (default: %s).\n"
842b7e5a7f2SJérôme Loyet 				"  -g, --pid <file>\n"
843b7e5a7f2SJérôme Loyet 				"                   Specify the PID file location.\n"
844d77d6153SAntony Dovgal 				"  -y, --fpm-config <file>\n"
845b772fae9SJérôme Loyet 				"                   Specify alternative path to FastCGI process manager config file.\n"
846757e3fc3SJerome Loyet 				"  -t, --test       Test FPM configuration and exit\n"
847851a04bbSJerome Loyet 				"  -D, --daemonize  force to run in background, and ignore daemonize option from config file\n"
848851a04bbSJerome Loyet 				"  -F, --nodaemonize\n"
849851a04bbSJerome Loyet 				"                   force to stay in foreground, and ignore daemonize option from config file\n"
85032d9409aSGernot Vormayr                                 "  -O, --force-stderr\n"
85132d9409aSGernot Vormayr                                 "                   force output to stderr in nodaemonize even if stderr is not a TTY\n"
852757e3fc3SJerome Loyet 				"  -R, --allow-to-run-as-root\n"
85306c7c367SJerome Loyet 				"                   Allow pool to run as root (disabled by default)\n",
854ae01a576SJérôme Loyet 				prog, PHP_PREFIX);
855d77d6153SAntony Dovgal }
856d77d6153SAntony Dovgal /* }}} */
857d77d6153SAntony Dovgal 
858d77d6153SAntony Dovgal /* {{{ is_valid_path
859d77d6153SAntony Dovgal  *
860d77d6153SAntony Dovgal  * some server configurations allow '..' to slip through in the
861d77d6153SAntony Dovgal  * translated path.   We'll just refuse to handle such a path.
862d77d6153SAntony Dovgal  */
is_valid_path(const char * path)863d77d6153SAntony Dovgal static int is_valid_path(const char *path)
864d77d6153SAntony Dovgal {
865d77d6153SAntony Dovgal 	const char *p;
866d77d6153SAntony Dovgal 
867d77d6153SAntony Dovgal 	if (!path) {
868d77d6153SAntony Dovgal 		return 0;
869d77d6153SAntony Dovgal 	}
870d77d6153SAntony Dovgal 	p = strstr(path, "..");
871d77d6153SAntony Dovgal 	if (p) {
872d77d6153SAntony Dovgal 		if ((p == path || IS_SLASH(*(p-1))) &&
873d77d6153SAntony Dovgal 			(*(p+2) == 0 || IS_SLASH(*(p+2)))
874d77d6153SAntony Dovgal 		) {
875d77d6153SAntony Dovgal 			return 0;
876d77d6153SAntony Dovgal 		}
877d77d6153SAntony Dovgal 		while (1) {
878d77d6153SAntony Dovgal 			p = strstr(p+1, "..");
879d77d6153SAntony Dovgal 			if (!p) {
880d77d6153SAntony Dovgal 				break;
881d77d6153SAntony Dovgal 			}
882d77d6153SAntony Dovgal 			if (IS_SLASH(*(p-1)) &&
883d77d6153SAntony Dovgal 				(*(p+2) == 0 || IS_SLASH(*(p+2)))
884d77d6153SAntony Dovgal 			) {
885d77d6153SAntony Dovgal 					return 0;
886d77d6153SAntony Dovgal 			}
887d77d6153SAntony Dovgal 		}
888d77d6153SAntony Dovgal 	}
889d77d6153SAntony Dovgal 	return 1;
890d77d6153SAntony Dovgal }
891d77d6153SAntony Dovgal /* }}} */
892d77d6153SAntony Dovgal 
893d77d6153SAntony Dovgal /* {{{ init_request_info
894d77d6153SAntony Dovgal 
895d77d6153SAntony Dovgal   initializes request_info structure
896d77d6153SAntony Dovgal 
897d77d6153SAntony Dovgal   specificly in this section we handle proper translations
898d77d6153SAntony Dovgal   for:
899d77d6153SAntony Dovgal 
900d77d6153SAntony Dovgal   PATH_INFO
901d77d6153SAntony Dovgal 	derived from the portion of the URI path following
902d77d6153SAntony Dovgal 	the script name but preceding any query data
903d77d6153SAntony Dovgal 	may be empty
904d77d6153SAntony Dovgal 
905d77d6153SAntony Dovgal   PATH_TRANSLATED
906d77d6153SAntony Dovgal     derived by taking any path-info component of the
907d77d6153SAntony Dovgal 	request URI and performing any virtual-to-physical
908d77d6153SAntony Dovgal 	translation appropriate to map it onto the server's
909d77d6153SAntony Dovgal 	document repository structure
910d77d6153SAntony Dovgal 
911d77d6153SAntony Dovgal 	empty if PATH_INFO is empty
912d77d6153SAntony Dovgal 
913d77d6153SAntony Dovgal 	The env var PATH_TRANSLATED **IS DIFFERENT** than the
914d77d6153SAntony Dovgal 	request_info.path_translated variable, the latter should
915d77d6153SAntony Dovgal 	match SCRIPT_FILENAME instead.
916d77d6153SAntony Dovgal 
917d77d6153SAntony Dovgal   SCRIPT_NAME
918d77d6153SAntony Dovgal     set to a URL path that could identify the CGI script
919d77d6153SAntony Dovgal 	rather than the interpreter.  PHP_SELF is set to this
920d77d6153SAntony Dovgal 
921d77d6153SAntony Dovgal   REQUEST_URI
922d77d6153SAntony Dovgal     uri section following the domain:port part of a URI
923d77d6153SAntony Dovgal 
924d77d6153SAntony Dovgal   SCRIPT_FILENAME
925d77d6153SAntony Dovgal     The virtual-to-physical translation of SCRIPT_NAME (as per
926d77d6153SAntony Dovgal 	PATH_TRANSLATED)
927d77d6153SAntony Dovgal 
928d77d6153SAntony Dovgal   These settings are documented at
929d77d6153SAntony Dovgal   http://cgi-spec.golux.com/
930d77d6153SAntony Dovgal 
931d77d6153SAntony Dovgal 
932d77d6153SAntony Dovgal   Based on the following URL request:
933d77d6153SAntony Dovgal 
934d77d6153SAntony Dovgal   http://localhost/info.php/test?a=b
935d77d6153SAntony Dovgal 
936d77d6153SAntony Dovgal   should produce, which btw is the same as if
937d77d6153SAntony Dovgal   we were running under mod_cgi on apache (ie. not
938d77d6153SAntony Dovgal   using ScriptAlias directives):
939d77d6153SAntony Dovgal 
940d77d6153SAntony Dovgal   PATH_INFO=/test
941d77d6153SAntony Dovgal   PATH_TRANSLATED=/docroot/test
942d77d6153SAntony Dovgal   SCRIPT_NAME=/info.php
943d77d6153SAntony Dovgal   REQUEST_URI=/info.php/test?a=b
944d77d6153SAntony Dovgal   SCRIPT_FILENAME=/docroot/info.php
945d77d6153SAntony Dovgal   QUERY_STRING=a=b
946d77d6153SAntony Dovgal 
947d77d6153SAntony Dovgal   but what we get is (cgi/mod_fastcgi under apache):
948d77d6153SAntony Dovgal 
949d77d6153SAntony Dovgal   PATH_INFO=/info.php/test
950d77d6153SAntony Dovgal   PATH_TRANSLATED=/docroot/info.php/test
951d77d6153SAntony Dovgal   SCRIPT_NAME=/php/php-cgi  (from the Action setting I suppose)
952d77d6153SAntony Dovgal   REQUEST_URI=/info.php/test?a=b
953d77d6153SAntony Dovgal   SCRIPT_FILENAME=/path/to/php/bin/php-cgi  (Action setting translated)
954d77d6153SAntony Dovgal   QUERY_STRING=a=b
955d77d6153SAntony Dovgal 
956d77d6153SAntony Dovgal   Comments in the code below refer to using the above URL in a request
957d77d6153SAntony Dovgal 
958d77d6153SAntony Dovgal  */
init_request_info(void)959bdeb220fSAnatol Belski static void init_request_info(void)
960d77d6153SAntony Dovgal {
961abb616aeSDmitry Stogov 	fcgi_request *request = (fcgi_request*) SG(server_context);
962abb616aeSDmitry Stogov 	char *env_script_filename = FCGI_GETENV(request, "SCRIPT_FILENAME");
963abb616aeSDmitry Stogov 	char *env_path_translated = FCGI_GETENV(request, "PATH_TRANSLATED");
964d77d6153SAntony Dovgal 	char *script_path_translated = env_script_filename;
96534ba9e39SJérôme Loyet 	char *ini;
96624126fa2SJim Jagielski 	int apache_was_here = 0;
967d77d6153SAntony Dovgal 
968d77d6153SAntony Dovgal 	/* some broken servers do not have script_filename or argv0
969d77d6153SAntony Dovgal 	 * an example, IIS configured in some ways.  then they do more
970d77d6153SAntony Dovgal 	 * broken stuff and set path_translated to the cgi script location */
971d77d6153SAntony Dovgal 	if (!script_path_translated && env_path_translated) {
972d77d6153SAntony Dovgal 		script_path_translated = env_path_translated;
973d77d6153SAntony Dovgal 	}
974d77d6153SAntony Dovgal 
975d77d6153SAntony Dovgal 	/* initialize the defaults */
976d77d6153SAntony Dovgal 	SG(request_info).path_translated = NULL;
977a221e17bSJakub Zelenka 	SG(request_info).request_method = FCGI_GETENV(request, "REQUEST_METHOD");
978d77d6153SAntony Dovgal 	SG(request_info).proto_num = 1000;
979d77d6153SAntony Dovgal 	SG(request_info).query_string = NULL;
980d77d6153SAntony Dovgal 	SG(request_info).request_uri = NULL;
981d77d6153SAntony Dovgal 	SG(request_info).content_type = NULL;
982d77d6153SAntony Dovgal 	SG(request_info).content_length = 0;
983d77d6153SAntony Dovgal 	SG(sapi_headers).http_response_code = 200;
984d77d6153SAntony Dovgal 
985a221e17bSJakub Zelenka 	/* if script_path_translated is not set, then there is no point to carry on
986a221e17bSJakub Zelenka 	 * as the response is 404 and there is no further processing. */
987d77d6153SAntony Dovgal 	if (script_path_translated) {
988d77d6153SAntony Dovgal 		const char *auth;
989abb616aeSDmitry Stogov 		char *content_length = FCGI_GETENV(request, "CONTENT_LENGTH");
990abb616aeSDmitry Stogov 		char *content_type = FCGI_GETENV(request, "CONTENT_TYPE");
991abb616aeSDmitry Stogov 		char *env_path_info = FCGI_GETENV(request, "PATH_INFO");
992abb616aeSDmitry Stogov 		char *env_script_name = FCGI_GETENV(request, "SCRIPT_NAME");
993d77d6153SAntony Dovgal 
994d77d6153SAntony Dovgal 		/* Hack for buggy IIS that sets incorrect PATH_INFO */
995abb616aeSDmitry Stogov 		char *env_server_software = FCGI_GETENV(request, "SERVER_SOFTWARE");
996d77d6153SAntony Dovgal 		if (env_server_software &&
997d77d6153SAntony Dovgal 			env_script_name &&
998d77d6153SAntony Dovgal 			env_path_info &&
9990494615bSJérôme Loyet 			strncmp(env_server_software, "Microsoft-IIS", sizeof("Microsoft-IIS") - 1) == 0 &&
1000d77d6153SAntony Dovgal 			strncmp(env_path_info, env_script_name, strlen(env_script_name)) == 0
1001d77d6153SAntony Dovgal 		) {
1002abb616aeSDmitry Stogov 			env_path_info = FCGI_PUTENV(request, "ORIG_PATH_INFO", env_path_info);
1003d77d6153SAntony Dovgal 			env_path_info += strlen(env_script_name);
1004d77d6153SAntony Dovgal 			if (*env_path_info == 0) {
1005d77d6153SAntony Dovgal 				env_path_info = NULL;
1006d77d6153SAntony Dovgal 			}
1007abb616aeSDmitry Stogov 			env_path_info = FCGI_PUTENV(request, "PATH_INFO", env_path_info);
1008d77d6153SAntony Dovgal 		}
1009d77d6153SAntony Dovgal 
101024126fa2SJim Jagielski #define APACHE_PROXY_FCGI_PREFIX "proxy:fcgi://"
101107d2dcdfSRemi Collet #define APACHE_PROXY_BALANCER_PREFIX "proxy:balancer://"
101207d2dcdfSRemi Collet 		/* Fix proxy URLs in SCRIPT_FILENAME generated by Apache mod_proxy_fcgi and mod_proxy_balancer:
10134a92ae34SRemi Collet 		 *     proxy:fcgi://localhost:9000/some-dir/info.php/test?foo=bar
101407d2dcdfSRemi Collet 		 *     proxy:balancer://localhost:9000/some-dir/info.php/test?foo=bar
101524126fa2SJim Jagielski 		 * should be changed to:
101624126fa2SJim Jagielski 		 *     /some-dir/info.php/test
101724126fa2SJim Jagielski 		 * See: http://bugs.php.net/bug.php?id=54152
101807d2dcdfSRemi Collet 		 *      http://bugs.php.net/bug.php?id=62172
101924126fa2SJim Jagielski 		 *      https://issues.apache.org/bugzilla/show_bug.cgi?id=50851
102024126fa2SJim Jagielski 		 */
102124126fa2SJim Jagielski 		if (env_script_filename &&
102224126fa2SJim Jagielski 			strncasecmp(env_script_filename, APACHE_PROXY_FCGI_PREFIX, sizeof(APACHE_PROXY_FCGI_PREFIX) - 1) == 0) {
102324126fa2SJim Jagielski 			/* advance to first character of hostname */
102424126fa2SJim Jagielski 			char *p = env_script_filename + (sizeof(APACHE_PROXY_FCGI_PREFIX) - 1);
102524126fa2SJim Jagielski 			while (*p != '\0' && *p != '/') {
102624126fa2SJim Jagielski 				p++;	/* move past hostname and port */
102724126fa2SJim Jagielski 			}
102824126fa2SJim Jagielski 			if (*p != '\0') {
102924126fa2SJim Jagielski 				/* Copy path portion in place to avoid memory leak.  Note
103024126fa2SJim Jagielski 				 * that this also affects what script_path_translated points
103124126fa2SJim Jagielski 				 * to. */
103224126fa2SJim Jagielski 				memmove(env_script_filename, p, strlen(p) + 1);
103324126fa2SJim Jagielski 				apache_was_here = 1;
103424126fa2SJim Jagielski 			}
10354a92ae34SRemi Collet 			/* ignore query string if sent by Apache (RewriteRule) */
10364a92ae34SRemi Collet 			p = strchr(env_script_filename, '?');
10374a92ae34SRemi Collet 			if (p) {
10384a92ae34SRemi Collet 				*p =0;
10394a92ae34SRemi Collet 			}
104024126fa2SJim Jagielski 		}
104124126fa2SJim Jagielski 
104207d2dcdfSRemi Collet 		if (env_script_filename &&
104307d2dcdfSRemi Collet 			strncasecmp(env_script_filename, APACHE_PROXY_BALANCER_PREFIX, sizeof(APACHE_PROXY_BALANCER_PREFIX) - 1) == 0) {
104407d2dcdfSRemi Collet 			/* advance to first character of hostname */
104507d2dcdfSRemi Collet 			char *p = env_script_filename + (sizeof(APACHE_PROXY_BALANCER_PREFIX) - 1);
104607d2dcdfSRemi Collet 			while (*p != '\0' && *p != '/') {
104707d2dcdfSRemi Collet 				p++;	/* move past hostname and port */
104824126fa2SJim Jagielski 			}
104924126fa2SJim Jagielski 			if (*p != '\0') {
105024126fa2SJim Jagielski 				/* Copy path portion in place to avoid memory leak.  Note
105124126fa2SJim Jagielski 				 * that this also affects what script_path_translated points
105224126fa2SJim Jagielski 				 * to. */
105324126fa2SJim Jagielski 				memmove(env_script_filename, p, strlen(p) + 1);
105424126fa2SJim Jagielski 				apache_was_here = 1;
105524126fa2SJim Jagielski 			}
10564a92ae34SRemi Collet 			/* ignore query string if sent by Apache (RewriteRule) */
10574a92ae34SRemi Collet 			p = strchr(env_script_filename, '?');
10584a92ae34SRemi Collet 			if (p) {
10594a92ae34SRemi Collet 				*p =0;
10604a92ae34SRemi Collet 			}
106124126fa2SJim Jagielski 		}
106224126fa2SJim Jagielski 
1063d77d6153SAntony Dovgal 		if (CGIG(fix_pathinfo)) {
1064d77d6153SAntony Dovgal 			struct stat st;
1065d77d6153SAntony Dovgal 			char *real_path = NULL;
1066abb616aeSDmitry Stogov 			char *env_redirect_url = FCGI_GETENV(request, "REDIRECT_URL");
1067abb616aeSDmitry Stogov 			char *env_document_root = FCGI_GETENV(request, "DOCUMENT_ROOT");
1068d77d6153SAntony Dovgal 			char *orig_path_translated = env_path_translated;
1069d77d6153SAntony Dovgal 			char *orig_path_info = env_path_info;
1070d77d6153SAntony Dovgal 			char *orig_script_name = env_script_name;
1071d77d6153SAntony Dovgal 			char *orig_script_filename = env_script_filename;
1072d77d6153SAntony Dovgal 			int script_path_translated_len;
1073d77d6153SAntony Dovgal 
1074d77d6153SAntony Dovgal 			if (!env_document_root && PG(doc_root)) {
1075abb616aeSDmitry Stogov 				env_document_root = FCGI_PUTENV(request, "DOCUMENT_ROOT", PG(doc_root));
1076d77d6153SAntony Dovgal 			}
1077d77d6153SAntony Dovgal 
1078e6d93a11SDavid Zuelke 			if (!apache_was_here && env_path_translated != NULL && env_redirect_url != NULL &&
1079d73d44c2SDavid Zuelke 			    env_path_translated != script_path_translated &&
1080d73d44c2SDavid Zuelke 			    strcmp(env_path_translated, script_path_translated) != 0) {
1081d73d44c2SDavid Zuelke 				/*
1082d73d44c2SDavid Zuelke 				 * pretty much apache specific.  If we have a redirect_url
1083d73d44c2SDavid Zuelke 				 * then our script_filename and script_name point to the
1084d73d44c2SDavid Zuelke 				 * php executable
1085e6d93a11SDavid Zuelke 				 * we don't want to do this for the new mod_proxy_fcgi approach,
1086e6d93a11SDavid Zuelke 				 * where redirect_url may also exist but the below will break
1087e6d93a11SDavid Zuelke 				 * with rewrites to PATH_INFO, hence the !apache_was_here check
1088d73d44c2SDavid Zuelke 				 */
1089d73d44c2SDavid Zuelke 				script_path_translated = env_path_translated;
1090d73d44c2SDavid Zuelke 				/* we correct SCRIPT_NAME now in case we don't have PATH_INFO */
1091d73d44c2SDavid Zuelke 				env_script_name = env_redirect_url;
1092d73d44c2SDavid Zuelke 			}
1093d73d44c2SDavid Zuelke 
1094d77d6153SAntony Dovgal #ifdef __riscos__
1095d77d6153SAntony Dovgal 			/* Convert path to unix format*/
1096d77d6153SAntony Dovgal 			__riscosify_control |= __RISCOSIFY_DONT_CHECK_DIR;
1097d77d6153SAntony Dovgal 			script_path_translated = __unixify(script_path_translated, 0, NULL, 1, 0);
1098d77d6153SAntony Dovgal #endif
1099d77d6153SAntony Dovgal 
1100d77d6153SAntony Dovgal 			/*
1101d77d6153SAntony Dovgal 			 * if the file doesn't exist, try to extract PATH_INFO out
1102d77d6153SAntony Dovgal 			 * of it by stat'ing back through the '/'
1103d77d6153SAntony Dovgal 			 * this fixes url's like /info.php/test
1104d77d6153SAntony Dovgal 			 */
1105d77d6153SAntony Dovgal 			if (script_path_translated &&
1106d77d6153SAntony Dovgal 				(script_path_translated_len = strlen(script_path_translated)) > 0 &&
1107d77d6153SAntony Dovgal 				(script_path_translated[script_path_translated_len-1] == '/' ||
1108bdeb220fSAnatol Belski 				(real_path = tsrm_realpath(script_path_translated, NULL)) == NULL)
1109d77d6153SAntony Dovgal 			) {
1110d77d6153SAntony Dovgal 				char *pt = estrndup(script_path_translated, script_path_translated_len);
1111d77d6153SAntony Dovgal 				int len = script_path_translated_len;
1112d77d6153SAntony Dovgal 				char *ptr;
1113d77d6153SAntony Dovgal 
1114ab117573SRemi Collet 				if (pt) {
1115ab117573SRemi Collet 					while ((ptr = strrchr(pt, '/')) || (ptr = strrchr(pt, '\\'))) {
1116ab117573SRemi Collet 						*ptr = 0;
1117ab117573SRemi Collet 						if (stat(pt, &st) == 0 && S_ISREG(st.st_mode)) {
1118ab117573SRemi Collet 							/*
1119ab117573SRemi Collet 							 * okay, we found the base script!
1120ab117573SRemi Collet 							 * work out how many chars we had to strip off;
1121ab117573SRemi Collet 							 * then we can modify PATH_INFO
1122ab117573SRemi Collet 							 * accordingly
1123ab117573SRemi Collet 							 *
1124ab117573SRemi Collet 							 * we now have the makings of
1125ab117573SRemi Collet 							 * PATH_INFO=/test
1126ab117573SRemi Collet 							 * SCRIPT_FILENAME=/docroot/info.php
1127ab117573SRemi Collet 							 *
1128ab117573SRemi Collet 							 * we now need to figure out what docroot is.
1129ab117573SRemi Collet 							 * if DOCUMENT_ROOT is set, this is easy, otherwise,
1130ab117573SRemi Collet 							 * we have to play the game of hide and seek to figure
1131ab117573SRemi Collet 							 * out what SCRIPT_NAME should be
1132ab117573SRemi Collet 							 */
1133ab117573SRemi Collet 							int ptlen = strlen(pt);
1134ab117573SRemi Collet 							int slen = len - ptlen;
1135ab117573SRemi Collet 							int pilen = env_path_info ? strlen(env_path_info) : 0;
1136ab117573