Updates to Tomato RAF including NGINX && PHP
[tomato.git] / release / src / router / php / sapi / roxen / roxen.c
blobc897ef62be6f6ce737aa2b532ea78af9aad1e42d
1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: David Hedbor <neotron@php.net> |
16 | Based on aolserver SAPI by Sascha Schumann <sascha@schumann.cx> |
17 +----------------------------------------------------------------------+
20 /* $Id$ */
22 #include "php.h"
23 #ifdef HAVE_ROXEN
25 #include "php_ini.h"
26 #include "php_globals.h"
27 #include "SAPI.h"
28 #include "php_main.h"
29 #include "ext/standard/info.h"
31 #include "php_version.h"
33 #ifndef ZTS
34 /* Only valid if thread safety is enabled. */
35 #undef ROXEN_USE_ZTS
36 #endif
39 /* Pike Include Files
41 * conflicts with pike avoided by only using long names. Requires a new
42 * Pike 0.7 since it was implemented for this interface only.
45 #define NO_PIKE_SHORTHAND
47 #include <fdlib.h>
48 #include <program.h>
49 #include <pike_types.h>
50 #include <interpret.h>
51 #include <module_support.h>
52 #include <error.h>
53 #include <array.h>
54 #include <backend.h>
55 #include <stralloc.h>
56 #include <mapping.h>
57 #include <object.h>
58 #include <threads.h>
59 #include <builtin_functions.h>
60 #include <operators.h>
62 #undef HIDE_GLOBAL_VARIABLES
63 #undef REVEAL_GLOBAL_VARIABLES
64 #define HIDE_GLOBAL_VARIABLES()
65 #define REVEAL_GLOBAL_VARIABLES()
67 /* php_roxen_request is per-request object storage */
69 typedef struct
71 struct mapping *request_data;
72 struct object *my_fd_obj;
73 int my_fd;
74 char *filename;
75 } php_roxen_request;
78 /* Defines to get to the data supplied when the script is started. */
80 #ifdef ROXEN_USE_ZTS
82 /* ZTS does work now, but it seems like it's faster using the "serialization"
83 * method I previously used. Thus it's not used unless ROXEN_USE_ZTS is defined.
86 /* Per thread storage area id... */
87 static int roxen_globals_id;
89 # define GET_THIS() php_roxen_request *_request = ts_resource(roxen_globals_id)
90 # define THIS _request
91 #else
92 static php_roxen_request *current_request = NULL;
94 # define GET_THIS() current_request = ((php_roxen_request *)Pike_fp->current_storage)
95 # define THIS current_request
96 #endif
98 /* File descriptor integer. Used to write directly to the FD without
99 * passing Pike
101 #define MY_FD (THIS->my_fd)
103 /* FD object. Really a PHPScript object from Pike which implements a couple
104 * of functions to handle headers, writing and buffering.
106 #define MY_FD_OBJ ((struct object *)(THIS->my_fd_obj))
108 /* Mapping with data supplied from the calling Roxen module. Contains
109 * a mapping with headers, an FD object etc.
111 #define REQUEST_DATA ((struct mapping *)(THIS->request_data))
114 #if defined(_REENTRANT) && !defined(ROXEN_USE_ZTS)
115 /* Lock used to serialize the PHP execution. If ROXEN_USE_ZTS is defined, we
116 * are using the PHP thread safe mechanism instead.
118 static PIKE_MUTEX_T roxen_php_execution_lock;
119 # define PHP_INIT_LOCK() mt_init(&roxen_php_execution_lock)
120 # define PHP_LOCK(X) THREADS_ALLOW();mt_lock(&roxen_php_execution_lock);THREADS_DISALLOW()
121 # define PHP_UNLOCK(X) mt_unlock(&roxen_php_execution_lock);
122 # define PHP_DESTROY() mt_destroy(&roxen_php_execution_lock)
123 #else /* !_REENTRANT */
124 # define PHP_INIT_LOCK()
125 # define PHP_LOCK(X)
126 # define PHP_UNLOCK(X)
127 # define PHP_DESTROY()
128 #endif /* _REENTRANT */
130 extern int fd_from_object(struct object *o);
131 static unsigned char roxen_php_initialized;
133 /* This allows calling of pike functions from the PHP callbacks,
134 * which requires the Pike interpreter to be locked.
136 #define THREAD_SAFE_RUN(COMMAND, what) do {\
137 struct thread_state *state;\
138 if((state = thread_state_for_id(th_self()))!=NULL) {\
139 if(!state->swapped) {\
140 COMMAND;\
141 } else {\
142 mt_lock(&interpreter_lock);\
143 SWAP_IN_THREAD(state);\
144 COMMAND;\
145 SWAP_OUT_THREAD(state);\
146 mt_unlock(&interpreter_lock);\
149 } while(0)
151 struct program *php_program;
154 /* To avoid executing a PHP script from a PHP callback, which would
155 * create a deadlock, a global thread id is used. If the thread calling the
156 * php-script is the same as the current thread, it fails.
158 static int current_thread = -1;
161 /* Low level header lookup. Basically looks for the named header in the mapping
162 * headers in the supplied options mapping.
165 static INLINE struct svalue *lookup_header(char *headername)
167 struct svalue *headers, *value;
168 struct pike_string *sind;
169 #ifdef ROXEN_USE_ZTS
170 GET_THIS();
171 #endif
172 sind = make_shared_string("env");
173 headers = low_mapping_string_lookup(REQUEST_DATA, sind);
174 free_string(sind);
175 if(!headers || headers->type != PIKE_T_MAPPING) return NULL;
176 sind = make_shared_string(headername);
177 value = low_mapping_string_lookup(headers->u.mapping, sind);
178 free_string(sind);
179 if(!value) return NULL;
180 return value;
183 /* Lookup a header in the mapping and return the value as a string, or
184 * return the default if it's missing
186 INLINE static char *lookup_string_header(char *headername, char *default_value)
188 struct svalue *head = NULL;
189 THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
190 if(!head || head->type != PIKE_T_STRING)
191 return default_value;
192 return head->u.string->str;
195 /* Lookup a header in the mapping and return the value as if it's an integer
196 * and otherwise return the default.
198 INLINE static int lookup_integer_header(char *headername, int default_value)
200 struct svalue *head = NULL;
201 THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
202 if(!head || head->type != PIKE_T_INT)
203 return default_value;
204 return head->u.integer;
208 * php_roxen_low_ub_write() writes data to the client connection. Might be
209 * rewritten to do more direct IO to save CPU and the need to lock the *
210 * interpreter for better threading.
213 static int
214 php_roxen_low_ub_write(const char *str, uint str_length TSRMLS_DC) {
215 int sent_bytes = 0;
216 struct pike_string *to_write = NULL;
217 #ifdef ROXEN_USE_ZTS
218 GET_THIS();
219 #endif
221 if(!MY_FD_OBJ->prog) {
222 PG(connection_status) = PHP_CONNECTION_ABORTED;
223 zend_bailout();
224 return -1;
226 to_write = make_shared_binary_string(str, str_length);
227 push_string(to_write);
228 safe_apply(MY_FD_OBJ, "write", 1);
229 if(Pike_sp[-1].type == PIKE_T_INT)
230 sent_bytes = Pike_sp[-1].u.integer;
231 pop_stack();
232 if(sent_bytes != str_length) {
233 /* This means the connection is closed. Dead. Gone. *sniff* */
234 php_handle_aborted_connection();
236 return sent_bytes;
240 * php_roxen_sapi_ub_write() calls php_roxen_low_ub_write in a Pike thread
241 * safe manner.
244 static int
245 php_roxen_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
247 #ifdef ROXEN_USE_ZTS
248 GET_THIS();
249 #endif
251 int sent_bytes = 0, fd = MY_FD;
252 if(fd)
254 for(sent_bytes=0;sent_bytes < str_length;)
256 int written;
257 written = fd_write(fd, str + sent_bytes, str_length - sent_bytes);
258 if(written < 0)
260 switch(errno)
262 default:
263 /* This means the connection is closed. Dead. Gone. *sniff* */
264 PG(connection_status) = PHP_CONNECTION_ABORTED;
265 zend_bailout();
266 return sent_bytes;
267 case EINTR:
268 case EWOULDBLOCK:
269 continue;
272 } else {
273 sent_bytes += written;
276 } else {
277 THREAD_SAFE_RUN(sent_bytes = php_roxen_low_ub_write(str, str_length TSRMLS_CC),
278 "write");
280 return sent_bytes;
283 /* php_roxen_set_header() sets a header in the header mapping. Called in a
284 * thread safe manner from php_roxen_sapi_header_handler.
286 static void php_roxen_set_header(char *header_name, char *value, char *p)
288 struct svalue hsval;
289 struct pike_string *hval, *ind, *hind;
290 struct mapping *headermap;
291 struct svalue *s_headermap;
292 #ifdef ROXEN_USE_ZTS
293 GET_THIS();
294 #endif
295 hval = make_shared_string(value);
296 ind = make_shared_string(" _headers");
297 hind = make_shared_binary_string(header_name,
298 (int)(p - header_name));
300 s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
301 if(!s_headermap)
303 struct svalue mappie;
304 mappie.type = PIKE_T_MAPPING;
305 headermap = allocate_mapping(1);
306 mappie.u.mapping = headermap;
307 mapping_string_insert(REQUEST_DATA, ind, &mappie);
308 free_mapping(headermap);
309 } else
310 headermap = s_headermap->u.mapping;
312 hsval.type = PIKE_T_STRING;
313 hsval.u.string = hval;
314 mapping_string_insert(headermap, hind, &hsval);
316 free_string(hval);
317 free_string(ind);
318 free_string(hind);
322 * php_roxen_sapi_header_handler() sets a HTTP reply header to be
323 * sent to the client.
325 static int
326 php_roxen_sapi_header_handler(sapi_header_struct *sapi_header,
327 sapi_headers_struct *sapi_headers TSRMLS_DC)
329 char *header_name, *header_content, *p;
330 header_name = sapi_header->header;
331 header_content = p = strchr(header_name, ':');
333 if(p) {
334 do {
335 header_content++;
336 } while(*header_content == ' ');
337 THREAD_SAFE_RUN(php_roxen_set_header(header_name, header_content, p), "header handler");
339 sapi_free_header(sapi_header);
340 return 0;
344 * php_roxen_sapi_send_headers() flushes the headers to the client.
345 * Called before real content is sent by PHP.
348 static int
349 php_roxen_low_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
351 struct pike_string *ind;
352 struct svalue *s_headermap;
353 #ifdef ROXEN_USE_ZTS
354 GET_THIS();
355 #endif
357 if(!MY_FD_OBJ->prog) {
358 PG(connection_status) = PHP_CONNECTION_ABORTED;
359 zend_bailout();
360 return SAPI_HEADER_SEND_FAILED;
362 ind = make_shared_string(" _headers");
363 s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
364 free_string(ind);
366 push_int(SG(sapi_headers).http_response_code);
367 if(s_headermap && s_headermap->type == PIKE_T_MAPPING)
368 ref_push_mapping(s_headermap->u.mapping);
369 else
370 push_int(0);
371 safe_apply(MY_FD_OBJ, "send_headers", 2);
372 pop_stack();
374 return SAPI_HEADER_SENT_SUCCESSFULLY;
377 static int
378 php_roxen_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
380 int res = 0;
381 THREAD_SAFE_RUN(res = php_roxen_low_send_headers(sapi_headers TSRMLS_CC), "send headers");
382 return res;
386 * php_roxen_sapi_read_post() reads a specified number of bytes from
387 * the client. Used for POST/PUT requests.
390 INLINE static int php_roxen_low_read_post(char *buf, uint count_bytes)
392 uint total_read = 0;
393 #ifdef ROXEN_USE_ZTS
394 GET_THIS();
395 #endif
396 TSRMLS_FETCH();
398 if(!MY_FD_OBJ->prog)
400 PG(connection_status) = PHP_CONNECTION_ABORTED;
401 zend_bailout();
402 return -1;
404 push_int(count_bytes);
405 safe_apply(MY_FD_OBJ, "read_post", 1);
406 if(Pike_sp[-1].type == PIKE_T_STRING) {
407 MEMCPY(buf, Pike_sp[-1].u.string->str,
408 (total_read = Pike_sp[-1].u.string->len));
409 buf[total_read] = '\0';
410 } else
411 total_read = 0;
412 pop_stack();
413 return total_read;
416 static int
417 php_roxen_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC)
419 uint total_read = 0;
420 THREAD_SAFE_RUN(total_read = php_roxen_low_read_post(buf, count_bytes), "read post");
421 return total_read;
425 * php_roxen_sapi_read_cookies() returns the Cookie header from
426 * the HTTP request header
429 static char *
430 php_roxen_sapi_read_cookies(TSRMLS_D)
432 char *cookies;
433 cookies = lookup_string_header("HTTP_COOKIE", NULL);
434 return cookies;
437 static void php_info_roxen(ZEND_MODULE_INFO_FUNC_ARGS)
439 /* char buf[512]; */
440 php_info_print_table_start();
441 php_info_print_table_row(2, "SAPI module version", "$Id$");
442 /* php_info_print_table_row(2, "Build date", Ns_InfoBuildDate());
443 php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile());
444 php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog());
445 php_info_print_table_row(2, "Installation path", Ns_InfoHomePath());
446 php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname());
447 php_info_print_table_row(2, "Source code label", Ns_InfoLabel());
448 php_info_print_table_row(2, "Server platform", Ns_InfoPlatform());
449 snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion());
450 php_info_print_table_row(2, "Server version", buf);
451 snprintf(buf, 511, "%d day(s), %02d:%02d:%02d",
452 uptime / 86400,
453 (uptime / 3600) % 24,
454 (uptime / 60) % 60,
455 uptime % 60);
456 php_info_print_table_row(2, "Server uptime", buf);
458 php_info_print_table_end();
461 static zend_module_entry php_roxen_module = {
462 STANDARD_MODULE_HEADER,
463 "Roxen",
464 NULL,
465 NULL,
466 NULL,
467 NULL,
468 NULL,
469 php_info_roxen,
470 NULL,
471 STANDARD_MODULE_PROPERTIES
474 static int php_roxen_startup(sapi_module_struct *sapi_module)
476 if(php_module_startup(sapi_module, &php_roxen_module, 1) == FAILURE) {
477 return FAILURE;
478 } else {
479 return SUCCESS;
483 /* this structure is static (as in "it does not change") */
485 static sapi_module_struct roxen_sapi_module = {
486 "roxen",
487 "Roxen",
488 php_roxen_startup, /* startup */
489 php_module_shutdown_wrapper, /* shutdown */
490 NULL, /* activate */
491 NULL, /* deactivate */
492 php_roxen_sapi_ub_write, /* unbuffered write */
493 NULL, /* flush */
494 NULL, /* get uid */
495 NULL, /* getenv */
496 php_error, /* error handler */
497 php_roxen_sapi_header_handler, /* header handler */
498 php_roxen_sapi_send_headers, /* send headers handler */
499 NULL, /* send header handler */
500 php_roxen_sapi_read_post, /* read POST data */
501 php_roxen_sapi_read_cookies, /* read Cookies */
502 NULL, /* register server variables */
503 NULL, /* Log message */
504 NULL, /* Get request time */
505 NULL, /* Child terminate */
507 STANDARD_SAPI_MODULE_PROPERTIES
511 * php_roxen_hash_environment() populates the php script environment
512 * with a number of variables. HTTP_* variables are created for
513 * the HTTP header data, so that a script can access these.
515 #define ADD_STRING(name) \
516 MAKE_STD_ZVAL(zvalue); \
517 zvalue->type = IS_STRING; \
518 zvalue->value.str.len = strlen(buf); \
519 zvalue->value.str.val = estrndup(buf, zvalue->value.str.len); \
520 zend_hash_update(&EG(symbol_table), name, sizeof(name), \
521 &zvalue, sizeof(zval *), NULL)
523 static void
524 php_roxen_hash_environment(TSRMLS_D)
526 int i;
527 char buf[512];
528 zval *zvalue;
529 struct svalue *headers;
530 struct pike_string *sind;
531 struct array *indices;
532 struct svalue *ind, *val;
533 #ifdef ROXEN_USE_ZTS
534 GET_THIS();
535 #endif
536 sind = make_shared_string("env");
537 headers = low_mapping_string_lookup(REQUEST_DATA, sind);
538 free_string(sind);
539 if(headers && headers->type == PIKE_T_MAPPING) {
540 indices = mapping_indices(headers->u.mapping);
541 for(i = 0; i < indices->size; i++) {
542 ind = &indices->item[i];
543 val = low_mapping_lookup(headers->u.mapping, ind);
544 if(ind && ind->type == PIKE_T_STRING &&
545 val && val->type == PIKE_T_STRING) {
546 int buf_len;
547 buf_len = MIN(511, ind->u.string->len);
548 strncpy(buf, ind->u.string->str, buf_len);
549 buf[buf_len] = '\0'; /* Terminate correctly */
550 MAKE_STD_ZVAL(zvalue);
551 zvalue->type = IS_STRING;
552 zvalue->value.str.len = val->u.string->len;
553 zvalue->value.str.val = estrndup(val->u.string->str, zvalue->value.str.len);
555 zend_hash_update(&EG(symbol_table), buf, buf_len + 1, &zvalue, sizeof(zval *), NULL);
558 free_array(indices);
562 MAKE_STD_ZVAL(zvalue);
563 zvalue->type = IS_LONG;
564 zvalue->value.lval = Ns_InfoBootTime();
565 zend_hash_update(&EG(symbol_table), "SERVER_BOOTTIME", sizeof("SERVER_BOOTTIME"), &zvalue, sizeof(zval *), NULL);
570 * php_roxen_module_main() is called by the per-request handler and
571 * "executes" the script
574 static int php_roxen_module_main(TSRMLS_D)
576 int res, len;
577 char *dir;
578 zend_file_handle file_handle;
579 #ifdef ROXEN_USE_ZTS
580 GET_THIS();
581 #endif
583 file_handle.type = ZEND_HANDLE_FILENAME;
584 file_handle.filename = THIS->filename;
585 file_handle.free_filename = 0;
586 file_handle.opened_path = NULL;
588 THREADS_ALLOW();
589 res = php_request_startup(TSRMLS_C);
590 THREADS_DISALLOW();
591 if(res == FAILURE) {
592 return 0;
594 php_roxen_hash_environment(TSRMLS_C);
595 THREADS_ALLOW();
596 php_execute_script(&file_handle TSRMLS_CC);
597 php_request_shutdown(NULL);
598 THREADS_DISALLOW();
599 return 1;
603 * The php_roxen_request_handler() is called per request and handles
604 * everything for one request.
607 void f_php_roxen_request_handler(INT32 args)
609 struct object *my_fd_obj;
610 struct mapping *request_data;
611 struct svalue *done_callback, *raw_fd;
612 struct pike_string *script, *ind;
613 int status = 1;
614 #ifdef ROXEN_USE_ZTS
615 GET_THIS();
616 #endif
617 TSRMLS_FETCH();
619 if(current_thread == th_self())
620 php_error(E_WARNING, "PHP5.Interpreter->run: Tried to run a PHP-script from a PHP "
621 "callback!");
622 get_all_args("PHP5.Interpreter->run", args, "%S%m%O%*", &script,
623 &request_data, &my_fd_obj, &done_callback);
624 if(done_callback->type != PIKE_T_FUNCTION)
625 php_error(E_WARNING, "PHP5.Interpreter->run: Bad argument 4, expected function.\n");
626 PHP_LOCK(THIS); /* Need to lock here or reusing the same object might cause
627 * problems in changing stuff in that object */
628 #ifndef ROXEN_USE_ZTS
629 GET_THIS();
630 #endif
631 THIS->request_data = request_data;
632 THIS->my_fd_obj = my_fd_obj;
633 THIS->filename = script->str;
634 current_thread = th_self();
635 SG(request_info).query_string = lookup_string_header("QUERY_STRING", 0);
636 SG(server_context) = (void *)1; /* avoid server_context == NULL */
638 /* path_translated is apparently the absolute path to the file, not
639 the translated PATH_INFO
641 SG(request_info).path_translated =
642 lookup_string_header("SCRIPT_FILENAME", NULL);
643 SG(request_info).request_uri = lookup_string_header("DOCUMENT_URI", NULL);
644 if(!SG(request_info).request_uri)
645 SG(request_info).request_uri = lookup_string_header("SCRIPT_NAME", NULL);
646 SG(request_info).request_method = lookup_string_header("REQUEST_METHOD", "GET");
647 SG(request_info).content_length = lookup_integer_header("HTTP_CONTENT_LENGTH", 0);
648 SG(request_info).content_type = lookup_string_header("HTTP_CONTENT_TYPE", NULL);
649 SG(sapi_headers).http_response_code = 200;
651 /* FIXME: Check for auth stuff needs to be fixed... */
652 SG(request_info).auth_user = NULL;
653 SG(request_info).auth_password = NULL;
655 ind = make_shared_binary_string("my_fd", 5);
656 raw_fd = low_mapping_string_lookup(THIS->request_data, ind);
657 if(raw_fd && raw_fd->type == PIKE_T_OBJECT)
659 int fd = fd_from_object(raw_fd->u.object);
660 if(fd == -1)
661 php_error(E_WARNING, "PHP5.Interpreter->run: my_fd object not open or not an FD.\n");
662 THIS->my_fd = fd;
663 } else
664 THIS->my_fd = 0;
666 status = php_roxen_module_main(TSRMLS_C);
667 current_thread = -1;
669 apply_svalue(done_callback, 0);
670 pop_stack();
671 pop_n_elems(args);
672 push_int(status);
673 PHP_UNLOCK(THIS);
677 /* Clear the object global struct */
678 static void clear_struct(struct object *o)
680 MEMSET(Pike_fp->current_storage, 0, sizeof(php_roxen_request));
685 * pike_module_init() is called by Pike once at startup
687 * This functions allocates basic structures
690 void pike_module_init( void )
692 if (!roxen_php_initialized) {
693 #ifdef ZTS
694 tsrm_startup(1, 1, 0, NULL);
695 #ifdef ROXEN_USE_ZTS
696 ts_allocate_id(&roxen_globals_id, sizeof(php_roxen_request), NULL, NULL);
697 #endif
698 #endif
699 sapi_startup(&roxen_sapi_module);
700 /*php_roxen_startup(&roxen_sapi_module); removed - should be called from SAPI activation*/
701 roxen_php_initialized = 1;
702 PHP_INIT_LOCK();
704 start_new_program(); /* Text */
705 ADD_STORAGE(php_roxen_request);
706 set_init_callback(clear_struct);
707 pike_add_function("run", f_php_roxen_request_handler,
708 "function(string, mapping, object, function:int)", 0);
709 add_program_constant("Interpreter", (php_program = end_program()), 0);
713 * pike_module_exit() performs the last steps before the
714 * server exists. Shutdowns basic services and frees memory
717 void pike_module_exit(void)
719 roxen_php_initialized = 0;
720 roxen_sapi_module.shutdown(&roxen_sapi_module);
721 if(php_program) free_program(php_program);
722 #ifdef ZTS
723 tsrm_shutdown();
724 #endif
725 PHP_DESTROY();
727 #endif