diff options
author | SVN Migration <svn@php.net> | 2003-02-27 17:43:39 +0000 |
---|---|---|
committer | SVN Migration <svn@php.net> | 2003-02-27 17:43:39 +0000 |
commit | 078bcec0997ad0e07b720c43cc9e6d0e046a75ab (patch) | |
tree | 36cb0f6be2ef078fe3374de8c087b93ecf82f812 /sapi/roxen/roxen.c | |
parent | fd61f69077f6156ca71dde60ecfd9ed9765a02db (diff) | |
download | php-git-PHP-5.tar.gz |
This commit was manufactured by cvs2svn to create branch 'PHP_5'.PHP-5
Diffstat (limited to 'sapi/roxen/roxen.c')
-rw-r--r-- | sapi/roxen/roxen.c | 725 |
1 files changed, 0 insertions, 725 deletions
diff --git a/sapi/roxen/roxen.c b/sapi/roxen/roxen.c deleted file mode 100644 index 9002040959..0000000000 --- a/sapi/roxen/roxen.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 4 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2003 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 2.02 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.php.net/license/2_02.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: David Hedbor <neotron@php.net> | - | Based on aolserver SAPI by Sascha Schumann <sascha@schumann.cx> | - +----------------------------------------------------------------------+ - */ - -/* $Id$ */ - -#include "php.h" -#ifdef HAVE_ROXEN - -#include "php_ini.h" -#include "php_globals.h" -#include "SAPI.h" -#include "php_main.h" -#include "ext/standard/info.h" - -#include "php_version.h" - -#ifndef ZTS -/* Only valid if thread safety is enabled. */ -#undef ROXEN_USE_ZTS -#endif - - -/* Pike Include Files - * - * conflicts with pike avoided by only using long names. Requires a new - * Pike 0.7 since it was implemented for this interface only. - * - */ -#define NO_PIKE_SHORTHAND - -#include <fdlib.h> -#include <program.h> -#include <pike_types.h> -#include <interpret.h> -#include <module_support.h> -#include <error.h> -#include <array.h> -#include <backend.h> -#include <stralloc.h> -#include <mapping.h> -#include <object.h> -#include <threads.h> -#include <builtin_functions.h> -#include <operators.h> - -#undef HIDE_GLOBAL_VARIABLES -#undef REVEAL_GLOBAL_VARIABLES -#define HIDE_GLOBAL_VARIABLES() -#define REVEAL_GLOBAL_VARIABLES() - -/* php_roxen_request is per-request object storage */ - -typedef struct -{ - struct mapping *request_data; - struct object *my_fd_obj; - int my_fd; - char *filename; -} php_roxen_request; - - -/* Defines to get to the data supplied when the script is started. */ - -#ifdef ROXEN_USE_ZTS - -/* ZTS does work now, but it seems like it's faster using the "serialization" - * method I previously used. Thus it's not used unless ROXEN_USE_ZTS is defined. - */ - -/* Per thread storage area id... */ -static int roxen_globals_id; - -# define GET_THIS() php_roxen_request *_request = ts_resource(roxen_globals_id) -# define THIS _request -#else -static php_roxen_request *current_request = NULL; - -# define GET_THIS() current_request = ((php_roxen_request *)Pike_fp->current_storage) -# define THIS current_request -#endif - -/* File descriptor integer. Used to write directly to the FD without - * passing Pike - */ -#define MY_FD (THIS->my_fd) - -/* FD object. Really a PHPScript object from Pike which implements a couple - * of functions to handle headers, writing and buffering. - */ -#define MY_FD_OBJ ((struct object *)(THIS->my_fd_obj)) - -/* Mapping with data supplied from the calling Roxen module. Contains - * a mapping with headers, an FD object etc. - */ -#define REQUEST_DATA ((struct mapping *)(THIS->request_data)) - - -#if defined(_REENTRANT) && !defined(ROXEN_USE_ZTS) -/* Lock used to serialize the PHP execution. If ROXEN_USE_ZTS is defined, we - * are using the PHP thread safe mechanism instead. - */ -static PIKE_MUTEX_T roxen_php_execution_lock; -# define PHP_INIT_LOCK() mt_init(&roxen_php_execution_lock) -# define PHP_LOCK(X) THREADS_ALLOW();mt_lock(&roxen_php_execution_lock);THREADS_DISALLOW() -# define PHP_UNLOCK(X) mt_unlock(&roxen_php_execution_lock); -# define PHP_DESTROY() mt_destroy(&roxen_php_execution_lock) -#else /* !_REENTRANT */ -# define PHP_INIT_LOCK() -# define PHP_LOCK(X) -# define PHP_UNLOCK(X) -# define PHP_DESTROY() -#endif /* _REENTRANT */ - -extern int fd_from_object(struct object *o); -static unsigned char roxen_php_initialized; - -/* This allows calling of pike functions from the PHP callbacks, - * which requires the Pike interpreter to be locked. - */ -#define THREAD_SAFE_RUN(COMMAND, what) do {\ - struct thread_state *state;\ - if((state = thread_state_for_id(th_self()))!=NULL) {\ - if(!state->swapped) {\ - COMMAND;\ - } else {\ - mt_lock(&interpreter_lock);\ - SWAP_IN_THREAD(state);\ - COMMAND;\ - SWAP_OUT_THREAD(state);\ - mt_unlock(&interpreter_lock);\ - }\ - }\ -} while(0) - -struct program *php_program; - - -/* To avoid executing a PHP script from a PHP callback, which would - * create a deadlock, a global thread id is used. If the thread calling the - * php-script is the same as the current thread, it fails. - */ -static int current_thread = -1; - - -/* Low level header lookup. Basically looks for the named header in the mapping - * headers in the supplied options mapping. - */ - -static INLINE struct svalue *lookup_header(char *headername) -{ - struct svalue *headers, *value; - struct pike_string *sind; -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif - sind = make_shared_string("env"); - headers = low_mapping_string_lookup(REQUEST_DATA, sind); - free_string(sind); - if(!headers || headers->type != PIKE_T_MAPPING) return NULL; - sind = make_shared_string(headername); - value = low_mapping_string_lookup(headers->u.mapping, sind); - free_string(sind); - if(!value) return NULL; - return value; -} - -/* Lookup a header in the mapping and return the value as a string, or - * return the default if it's missing - */ -INLINE static char *lookup_string_header(char *headername, char *default_value) -{ - struct svalue *head = NULL; - THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup"); - if(!head || head->type != PIKE_T_STRING) - return default_value; - return head->u.string->str; -} - -/* Lookup a header in the mapping and return the value as if it's an integer - * and otherwise return the default. - */ -INLINE static int lookup_integer_header(char *headername, int default_value) -{ - struct svalue *head = NULL; - THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup"); - if(!head || head->type != PIKE_T_INT) - return default_value; - return head->u.integer; -} - -/* - * php_roxen_low_ub_write() writes data to the client connection. Might be - * rewritten to do more direct IO to save CPU and the need to lock the * - * interpreter for better threading. - */ - -static int -php_roxen_low_ub_write(const char *str, uint str_length TSRMLS_DC) { - int sent_bytes = 0; - struct pike_string *to_write = NULL; -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif - - if(!MY_FD_OBJ->prog) { - PG(connection_status) = PHP_CONNECTION_ABORTED; - zend_bailout(); - return -1; - } - to_write = make_shared_binary_string(str, str_length); - push_string(to_write); - safe_apply(MY_FD_OBJ, "write", 1); - if(Pike_sp[-1].type == PIKE_T_INT) - sent_bytes = Pike_sp[-1].u.integer; - pop_stack(); - if(sent_bytes != str_length) { - /* This means the connection is closed. Dead. Gone. *sniff* */ - php_handle_aborted_connection(); - } - return sent_bytes; -} - -/* - * php_roxen_sapi_ub_write() calls php_roxen_low_ub_write in a Pike thread - * safe manner. - */ - -static int -php_roxen_sapi_ub_write(const char *str, uint str_length TSRMLS_DC) -{ -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif - - int sent_bytes = 0, fd = MY_FD; - if(fd) - { - for(sent_bytes=0;sent_bytes < str_length;) - { - int written; - written = fd_write(fd, str + sent_bytes, str_length - sent_bytes); - if(written < 0) - { - switch(errno) - { - default: - /* This means the connection is closed. Dead. Gone. *sniff* */ - PG(connection_status) = PHP_CONNECTION_ABORTED; - zend_bailout(); - return sent_bytes; - case EINTR: - case EWOULDBLOCK: - continue; - } - - } else { - sent_bytes += written; - } - } - } else { - THREAD_SAFE_RUN(sent_bytes = php_roxen_low_ub_write(str, str_length TSRMLS_CC), - "write"); - } - return sent_bytes; -} - -/* php_roxen_set_header() sets a header in the header mapping. Called in a - * thread safe manner from php_roxen_sapi_header_handler. - */ -static void php_roxen_set_header(char *header_name, char *value, char *p) -{ - struct svalue hsval; - struct pike_string *hval, *ind, *hind; - struct mapping *headermap; - struct svalue *s_headermap; -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif - hval = make_shared_string(value); - ind = make_shared_string(" _headers"); - hind = make_shared_binary_string(header_name, - (int)(p - header_name)); - - s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind); - if(!s_headermap) - { - struct svalue mappie; - mappie.type = PIKE_T_MAPPING; - headermap = allocate_mapping(1); - mappie.u.mapping = headermap; - mapping_string_insert(REQUEST_DATA, ind, &mappie); - free_mapping(headermap); - } else - headermap = s_headermap->u.mapping; - - hsval.type = PIKE_T_STRING; - hsval.u.string = hval; - mapping_string_insert(headermap, hind, &hsval); - - free_string(hval); - free_string(ind); - free_string(hind); -} - -/* - * php_roxen_sapi_header_handler() sets a HTTP reply header to be - * sent to the client. - */ -static int -php_roxen_sapi_header_handler(sapi_header_struct *sapi_header, - sapi_headers_struct *sapi_headers TSRMLS_DC) -{ - char *header_name, *header_content, *p; - header_name = sapi_header->header; - header_content = p = strchr(header_name, ':'); - - if(p) { - do { - header_content++; - } while(*header_content == ' '); - THREAD_SAFE_RUN(php_roxen_set_header(header_name, header_content, p), "header handler"); - } - sapi_free_header(sapi_header); - return 0; -} - -/* - * php_roxen_sapi_send_headers() flushes the headers to the client. - * Called before real content is sent by PHP. - */ - -static int -php_roxen_low_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) -{ - struct pike_string *ind; - struct svalue *s_headermap; -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif - - if(!MY_FD_OBJ->prog) { - PG(connection_status) = PHP_CONNECTION_ABORTED; - zend_bailout(); - return SAPI_HEADER_SEND_FAILED; - } - ind = make_shared_string(" _headers"); - s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind); - free_string(ind); - - push_int(SG(sapi_headers).http_response_code); - if(s_headermap && s_headermap->type == PIKE_T_MAPPING) - ref_push_mapping(s_headermap->u.mapping); - else - push_int(0); - safe_apply(MY_FD_OBJ, "send_headers", 2); - pop_stack(); - - return SAPI_HEADER_SENT_SUCCESSFULLY; -} - -static int -php_roxen_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) -{ - int res = 0; - THREAD_SAFE_RUN(res = php_roxen_low_send_headers(sapi_headers TSRMLS_CC), "send headers"); - return res; -} - -/* - * php_roxen_sapi_read_post() reads a specified number of bytes from - * the client. Used for POST/PUT requests. - */ - -INLINE static int php_roxen_low_read_post(char *buf, uint count_bytes) -{ - uint total_read = 0; -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif - TSRMLS_FETCH(); - - if(!MY_FD_OBJ->prog) - { - PG(connection_status) = PHP_CONNECTION_ABORTED; - zend_bailout(); - return -1; - } - push_int(count_bytes); - safe_apply(MY_FD_OBJ, "read_post", 1); - if(Pike_sp[-1].type == PIKE_T_STRING) { - MEMCPY(buf, Pike_sp[-1].u.string->str, - (total_read = Pike_sp[-1].u.string->len)); - buf[total_read] = '\0'; - } else - total_read = 0; - pop_stack(); - return total_read; -} - -static int -php_roxen_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC) -{ - uint total_read = 0; - THREAD_SAFE_RUN(total_read = php_roxen_low_read_post(buf, count_bytes), "read post"); - return total_read; -} - -/* - * php_roxen_sapi_read_cookies() returns the Cookie header from - * the HTTP request header - */ - -static char * -php_roxen_sapi_read_cookies(TSRMLS_D) -{ - char *cookies; - cookies = lookup_string_header("HTTP_COOKIE", NULL); - return cookies; -} - -static void php_info_roxen(ZEND_MODULE_INFO_FUNC_ARGS) -{ - /* char buf[512]; */ - php_info_print_table_start(); - php_info_print_table_row(2, "SAPI module version", "$Id$"); - /* php_info_print_table_row(2, "Build date", Ns_InfoBuildDate()); - php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile()); - php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog()); - php_info_print_table_row(2, "Installation path", Ns_InfoHomePath()); - php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname()); - php_info_print_table_row(2, "Source code label", Ns_InfoLabel()); - php_info_print_table_row(2, "Server platform", Ns_InfoPlatform()); - snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion()); - php_info_print_table_row(2, "Server version", buf); - snprintf(buf, 511, "%d day(s), %02d:%02d:%02d", - uptime / 86400, - (uptime / 3600) % 24, - (uptime / 60) % 60, - uptime % 60); - php_info_print_table_row(2, "Server uptime", buf); - */ - php_info_print_table_end(); -} - -static zend_module_entry php_roxen_module = { - STANDARD_MODULE_HEADER, - "Roxen", - NULL, - NULL, - NULL, - NULL, - NULL, - php_info_roxen, - NULL, - STANDARD_MODULE_PROPERTIES -}; - -static int php_roxen_startup(sapi_module_struct *sapi_module) -{ - if(php_module_startup(sapi_module, &php_roxen_module, 1) == FAILURE) { - return FAILURE; - } else { - return SUCCESS; - } -} - -/* this structure is static (as in "it does not change") */ - -static sapi_module_struct roxen_sapi_module = { - "roxen", - "Roxen", - php_roxen_startup, /* startup */ - php_module_shutdown_wrapper, /* shutdown */ - NULL, /* activate */ - NULL, /* deactivate */ - php_roxen_sapi_ub_write, /* unbuffered write */ - NULL, /* flush */ - NULL, /* get uid */ - NULL, /* getenv */ - php_error, /* error handler */ - php_roxen_sapi_header_handler, /* header handler */ - php_roxen_sapi_send_headers, /* send headers handler */ - NULL, /* send header handler */ - php_roxen_sapi_read_post, /* read POST data */ - php_roxen_sapi_read_cookies, /* read Cookies */ - NULL, /* register server variables */ - NULL, /* Log message */ - - STANDARD_SAPI_MODULE_PROPERTIES -}; - -/* - * php_roxen_hash_environment() populates the php script environment - * with a number of variables. HTTP_* variables are created for - * the HTTP header data, so that a script can access these. - */ -#define ADD_STRING(name) \ - MAKE_STD_ZVAL(pval); \ - pval->type = IS_STRING; \ - pval->value.str.len = strlen(buf); \ - pval->value.str.val = estrndup(buf, pval->value.str.len); \ - zend_hash_update(&EG(symbol_table), name, sizeof(name), \ - &pval, sizeof(zval *), NULL) - -static void -php_roxen_hash_environment(TSRMLS_D) -{ - int i; - char buf[512]; - zval *pval; - struct svalue *headers; - struct pike_string *sind; - struct array *indices; - struct svalue *ind, *val; -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif - sind = make_shared_string("env"); - headers = low_mapping_string_lookup(REQUEST_DATA, sind); - free_string(sind); - if(headers && headers->type == PIKE_T_MAPPING) { - indices = mapping_indices(headers->u.mapping); - for(i = 0; i < indices->size; i++) { - ind = &indices->item[i]; - val = low_mapping_lookup(headers->u.mapping, ind); - if(ind && ind->type == PIKE_T_STRING && - val && val->type == PIKE_T_STRING) { - int buf_len; - buf_len = MIN(511, ind->u.string->len); - strncpy(buf, ind->u.string->str, buf_len); - buf[buf_len] = '\0'; /* Terminate correctly */ - MAKE_STD_ZVAL(pval); - pval->type = IS_STRING; - pval->value.str.len = val->u.string->len; - pval->value.str.val = estrndup(val->u.string->str, pval->value.str.len); - - zend_hash_update(&EG(symbol_table), buf, buf_len + 1, &pval, sizeof(zval *), NULL); - } - } - free_array(indices); - } - - /* - MAKE_STD_ZVAL(pval); - pval->type = IS_LONG; - pval->value.lval = Ns_InfoBootTime(); - zend_hash_update(&EG(symbol_table), "SERVER_BOOTTIME", sizeof("SERVER_BOOTTIME"), &pval, sizeof(zval *), NULL); - */ -} - -/* - * php_roxen_module_main() is called by the per-request handler and - * "executes" the script - */ - -static int php_roxen_module_main(TSRMLS_D) -{ - int res, len; - char *dir; - zend_file_handle file_handle; -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif - - file_handle.type = ZEND_HANDLE_FILENAME; - file_handle.filename = THIS->filename; - file_handle.free_filename = 0; - file_handle.opened_path = NULL; - - THREADS_ALLOW(); - res = php_request_startup(TSRMLS_C); - THREADS_DISALLOW(); - if(res == FAILURE) { - return 0; - } - php_roxen_hash_environment(TSRMLS_C); - THREADS_ALLOW(); - php_execute_script(&file_handle TSRMLS_CC); - php_request_shutdown(NULL); - THREADS_DISALLOW(); - return 1; -} - -/* - * The php_roxen_request_handler() is called per request and handles - * everything for one request. - */ - -void f_php_roxen_request_handler(INT32 args) -{ - struct object *my_fd_obj; - struct mapping *request_data; - struct svalue *done_callback, *raw_fd; - struct pike_string *script, *ind; - int status = 1; -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif - TSRMLS_FETCH(); - - if(current_thread == th_self()) - php_error(E_WARNING, "PHP4.Interpreter->run: Tried to run a PHP-script from a PHP " - "callback!"); - get_all_args("PHP4.Interpreter->run", args, "%S%m%O%*", &script, - &request_data, &my_fd_obj, &done_callback); - if(done_callback->type != PIKE_T_FUNCTION) - php_error(E_WARNING, "PHP4.Interpreter->run: Bad argument 4, expected function.\n"); - PHP_LOCK(THIS); /* Need to lock here or reusing the same object might cause - * problems in changing stuff in that object */ -#ifndef ROXEN_USE_ZTS - GET_THIS(); -#endif - THIS->request_data = request_data; - THIS->my_fd_obj = my_fd_obj; - THIS->filename = script->str; - current_thread = th_self(); - SG(request_info).query_string = lookup_string_header("QUERY_STRING", 0); - SG(server_context) = (void *)1; /* avoid server_context == NULL */ - - /* path_translated is apparently the absolute path to the file, not - the translated PATH_INFO - */ - SG(request_info).path_translated = - lookup_string_header("SCRIPT_FILENAME", NULL); - SG(request_info).request_uri = lookup_string_header("DOCUMENT_URI", NULL); - if(!SG(request_info).request_uri) - SG(request_info).request_uri = lookup_string_header("SCRIPT_NAME", NULL); - SG(request_info).request_method = lookup_string_header("REQUEST_METHOD", "GET"); - SG(request_info).content_length = lookup_integer_header("HTTP_CONTENT_LENGTH", 0); - SG(request_info).content_type = lookup_string_header("HTTP_CONTENT_TYPE", NULL); - SG(sapi_headers).http_response_code = 200; - - /* FIXME: Check for auth stuff needs to be fixed... */ - SG(request_info).auth_user = NULL; - SG(request_info).auth_password = NULL; - - ind = make_shared_binary_string("my_fd", 5); - raw_fd = low_mapping_string_lookup(THIS->request_data, ind); - if(raw_fd && raw_fd->type == PIKE_T_OBJECT) - { - int fd = fd_from_object(raw_fd->u.object); - if(fd == -1) - php_error(E_WARNING, "PHP4.Interpreter->run: my_fd object not open or not an FD.\n"); - THIS->my_fd = fd; - } else - THIS->my_fd = 0; - - status = php_roxen_module_main(TSRMLS_C); - current_thread = -1; - - apply_svalue(done_callback, 0); - pop_stack(); - pop_n_elems(args); - push_int(status); - PHP_UNLOCK(THIS); -} - - -/* Clear the object global struct */ -static void clear_struct(struct object *o) -{ - MEMSET(Pike_fp->current_storage, 0, sizeof(php_roxen_request)); -} - - -/* - * pike_module_init() is called by Pike once at startup - * - * This functions allocates basic structures - */ - -void pike_module_init( void ) -{ - if (!roxen_php_initialized) { -#ifdef ZTS - tsrm_startup(1, 1, 0, NULL); -#ifdef ROXEN_USE_ZTS - ts_allocate_id(&roxen_globals_id, sizeof(php_roxen_request), NULL, NULL); -#endif -#endif - sapi_startup(&roxen_sapi_module); - /*php_roxen_startup(&roxen_sapi_module); removed - should be called from SAPI activation*/ - roxen_php_initialized = 1; - PHP_INIT_LOCK(); - } - start_new_program(); /* Text */ - ADD_STORAGE(php_roxen_request); - set_init_callback(clear_struct); - pike_add_function("run", f_php_roxen_request_handler, - "function(string, mapping, object, function:int)", 0); - add_program_constant("Interpreter", (php_program = end_program()), 0); -} - -/* - * pike_module_exit() performs the last steps before the - * server exists. Shutdowns basic services and frees memory - */ - -void pike_module_exit(void) -{ - roxen_php_initialized = 0; - roxen_sapi_module.shutdown(&roxen_sapi_module); - if(php_program) free_program(php_program); -#ifdef ZTS - tsrm_shutdown(); -#endif - PHP_DESTROY(); -} -#endif |