diff options
Diffstat (limited to 'sapi/roxen')
-rw-r--r-- | sapi/roxen/Makefile.am | 4 | ||||
-rw-r--r-- | sapi/roxen/README | 17 | ||||
-rw-r--r-- | sapi/roxen/config.h.stub | 12 | ||||
-rw-r--r-- | sapi/roxen/config.m4 | 63 | ||||
-rw-r--r-- | sapi/roxen/phpmod.pike | 363 | ||||
-rw-r--r-- | sapi/roxen/roxen.c | 745 |
6 files changed, 0 insertions, 1204 deletions
diff --git a/sapi/roxen/Makefile.am b/sapi/roxen/Makefile.am deleted file mode 100644 index 4c6d5de6b0..0000000000 --- a/sapi/roxen/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -## Process this file with automake to produce Makefile.in - -noinst_LTLIBRARIES=libphpsapi_roxen.la -libphpsapi_roxen_la_SOURCES=roxen.c diff --git a/sapi/roxen/README b/sapi/roxen/README deleted file mode 100644 index b12662f3e3..0000000000 --- a/sapi/roxen/README +++ /dev/null @@ -1,17 +0,0 @@ -Roxen PHP support. Early version. Don't expect to be able to get it to -work. Requires Pike 0.7.79 and Roxen 1.4. Anything less won't work. - -The module is now thread safe, in a couple of different modes. First -mode, the default, uses a process global PHP lock in the Roxen -module. This means that all PHP-requests are serialized (ie only one -script is executed at any one time). The second option is using ZTS -(Zend Thread Safe mode). Unless --enable-roxen-zts is specified, this -won't be used. For now this uses a global lock in the PHP interpreter -so the end result is the same (only one concurrent script). In the -future this might change though, but for now you are better off using -the non-ZendThreadSafe version (which works fine with Roxen and -threads). - -- The Author, David Hedbor <neotron@php.net> - - diff --git a/sapi/roxen/config.h.stub b/sapi/roxen/config.h.stub deleted file mode 100644 index 4128f3170f..0000000000 --- a/sapi/roxen/config.h.stub +++ /dev/null @@ -1,12 +0,0 @@ - -/* Define this if you want to build the Roxen PHP module - * It is currently VERY EXPERIMENTAL and not finished. - */ -#undef HAVE_ROXEN - - -/* Comment to use the Roxen "serializing" instead of PHP's ZTS. - * It seems like the Roxen PHP-global mutex lock works better, - * performance wise. - */ -#undef ROXEN_USE_ZTS diff --git a/sapi/roxen/config.m4 b/sapi/roxen/config.m4 deleted file mode 100644 index b2425b2156..0000000000 --- a/sapi/roxen/config.m4 +++ /dev/null @@ -1,63 +0,0 @@ -dnl ## $Id$ -*- sh -*- - -RESULT=no -AC_MSG_CHECKING(for Roxen/Pike support) -AC_ARG_WITH(roxen, -[ --with-roxen=DIR Build PHP as a Pike module. DIR is the base Roxen - directory, normally /usr/local/roxen/server.], -[ - if test ! -d $withval ; then - AC_MSG_ERROR(You did not specify a directory) - fi - if test -f $withval/bin/roxen; then - PIKE="$withval/bin/roxen" - elif test -f $withval/bin/pike; then - PIKE="$withval/bin/pike" - else - AC_MSG_ERROR(Couldn't find a pike in $withval/bin/) - fi - if $PIKE -e 'float v = __VERSION__ + (__BUILD__/10000.0); if(v < 0.7079) exit(1); exit(0);'; then - PIKE_MODULE_DIR="`$PIKE --show-paths 2>&1| grep lib/modules | sed -e 's/.*: //'`" - PIKE_INCLUDE_DIR="`echo $PIKE_MODULE_DIR | sed -e 's,lib/pike/modules,include/pike,' -e 's,lib/modules,include/pike,'`" - if test -z "$PIKE_INCLUDE_DIR" -o -z "$PIKE_MODULE_DIR"; then - AC_MSG_ERROR(Failed to figure out Pike module and include directories) - fi - else - AC_MSG_ERROR(Roxen/PHP requires Pike 0.7.79 or newer) - fi - AC_ADD_INCLUDE($PIKE_INCLUDE_DIR) - AC_DEFINE(HAVE_ROXEN) - PHP_SAPI=roxen - PHP_BUILD_SHARED - INSTALL_IT="\$(SHELL) \$(srcdir)/install-sh -m 0755 $SAPI_SHARED $PIKE_MODULE_DIR/PHP4.so" - RESULT="yes - Pike binary used: $PIKE - Pike include dir: $PIKE_INCLUDE_DIR - Pike module directory: $PIKE_MODULE_DIR" -]) -AC_MSG_RESULT($RESULT) - -if test "$RESULT" != "no" ; then - RESULT=no - AC_MSG_CHECKING(if Roxen should use ZTS) - AC_ARG_ENABLE(roxen-zts, - [ --enable-roxen-zts Build the Roxen module using Zend Thread Safety. - This is not required to run the module in a threaded - Roxen and it doesn't improve performance. PHP calls - are normally made in a serialized mode.], - [ - PHP_BUILD_THREAD_SAFE - AC_DEFINE(ROXEN_USE_ZTS) - RESULT="yes - *** You have choosen to compile with PHP thread safety - *** enabled. This is not a requirement for the Roxen - *** PHP module, even if Roxen runs in multi-threaded mode. - *** It will as a matter of fact make performance worse." - - ]) - AC_MSG_RESULT($RESULT) -fi -dnl ## Local Variables: -dnl ## tab-width: 4 -dnl ## End: -
\ No newline at end of file diff --git a/sapi/roxen/phpmod.pike b/sapi/roxen/phpmod.pike deleted file mode 100644 index 35db7b4076..0000000000 --- a/sapi/roxen/phpmod.pike +++ /dev/null @@ -1,363 +0,0 @@ -/* Roxen PHP module based of the Roxen CGI module for Roxen 1.4. */ - -#include <roxen.h> -#include <module.h> -inherit "module"; -inherit "roxenlib"; - -constant cvs_version = "$Id$"; -constant thread_safe = 1; - -string trim( string what ) -{ - sscanf(what, "%*[ \t]%s", what); - what = reverse(what); - sscanf(what, "%*[ \t]%s", what); - what = reverse(what); - return what; -} - -//#define PHP_DEBUG -#ifdef PHP_DEBUG -#define DWERROR(X) report_debug("Thr("+getpid()+"): "+X) -#else /* !PHP_DEBUG */ -#define DWERROR(X) -#endif /* PHP_DEBUG */ - -array register_module() -{ - return - ({ - MODULE_FILE_EXTENSION | MODULE_PARSER, - "PHP Script Support", - "This module allows Roxen users to run PHP scripts, optionally in " - "combination with RXML. ", - }); -} - -class PHPScript -{ - object interpretor; - string command; - string buffer=""; - // stderr is handled by run(). - mapping (string:string) environment; - int blocking, written, close_when_done; - object mid; - void done() { - if(strlen(buffer)) { - close_when_done = 1; - if(QUERY(rxml)) { - buffer = parse_rxml(buffer, mid); - write_callback(); - } - } else - destruct(); - } - - void destroy() { - mid->do_not_disconnect = 0; - // destruct(interpretor); - mid->file = ([ "len": written, "raw":1 ]); - // mid->do_log(); - } - void write_callback() - { - DWERROR("PHP:Wrapper::write_callback()\n"); - if(!strlen(buffer)) - return; - // int nelems = tofd->write( buffer ); - int nelems; - array err = catch { nelems = mid->my_fd->write(buffer); }; - DWERROR(sprintf("PHP:Wrapper::write_callback(): write(%O) => %d\n", - buffer, nelems)); - if( err || nelems < 0 ) - // if nelems == 0, network buffer is full. We still want to continue. - { - buffer=""; - close_when_done = -1; - } else { - written += nelems; - buffer = buffer[nelems..]; - DWERROR(sprintf("Done: %d %d...\n", strlen(buffer), close_when_done)); - if(close_when_done && !strlen(buffer)) { - destruct(); - } - } - } - - int write( string what ) - { - DWERROR(sprintf("PHP:Wrapper::write(%O)\n", what)); - if(close_when_done == -1) // Remote closed - return -1; - if(buffer == "" ) - { - buffer = what; - if(!QUERY(rxml)) write_callback(); - } else - buffer += what; - return strlen(what); - } - - void send_headers(int code, mapping headers) - { - DWERROR(sprintf("PHP:PHPWrapper::send_headers(%d,%O)\n", code, headers)); - string result = "", post=""; - string code = mid->errors[code||200]; - int ct_received = 0, sv_received = 0; - if(headers) - foreach(indices(headers), string header) - { - string value = headers[header]; - if(!header || !value) - { - // Heavy DWIM. For persons who forget about headers altogether. - continue; - } - header = trim(header); - value = trim(value); - switch(lower_case( header )) - { - case "status": - code = value; - break; - - case "content-type": - ct_received=1; - result += header+": "+value+"\r\n"; - break; - - case "server": - sv_received=1; - result += header+": "+value+"\r\n"; - break; - - case "location": - code = "302 Redirection"; - result += header+": "+value+"\r\n"; - break; - - default: - result += header+": "+value+"\r\n"; - break; - } - } - if(!sv_received) - result += "Server: "+roxen.version()+"/PHP\r\n"; - if(!ct_received) - result += "Content-Type: text/html\r\n"; - write("HTTP/1.0 "+code+"\r\n"+result+"\r\n"); - } - - PHPScript run() - { - DWERROR("PHP:PHPScript::run()\n"); - // if( QUERY(rxml) ) - // stdout = (wrapper = RXMLWrapper( stdout, mid ))->get_fd(); - mapping options = ([ - "env":environment, - ]); -#if 1 - if(!QUERY(rxml)) { - mid->my_fd->set_blocking(); - options->my_fd = mid->my_fd; - } -#endif - mid->my_fd->set_close_callback(done); - interpretor->run(command, options, this_object(), done); - return this_object(); - } - - - void create( object id ) - { - DWERROR("PHP:PHPScript()\n"); - interpretor = PHP4.Interpretor(); - mid = id; - -#ifndef THREADS - if(id->misc->orig) // An <insert file=...> operation, and we have no threads. - blocking = 1; -#else - if(id->misc->orig && this_thread() == roxen.backend_thread) - blocking = 1; - // An <insert file=...> and we are - // currently in the backend thread. -#endif - if(!id->realfile) - { - id->realfile = id->conf->real_file( id->not_query, id ); - if(!id->realfile) - error("No real file associated with "+id->not_query+ - ", thus it's not possible to run it as a PHP script.\n"); - } - command = id->realfile; - - environment =(QUERY(env)?getenv():([])); - environment |= global_env; - environment |= build_env_vars( id->realfile, id, id->misc->path_info ); - environment |= build_roxen_env_vars(id); - if(id->misc->ssi_env) environment |= id->misc->ssi_env; - if(id->misc->is_redirected) environment["REDIRECT_STATUS"] = "1"; - if(id->rawauth && QUERY(rawauth)) - environment["HTTP_AUTHORIZATION"] = (string)id->rawauth; - else - m_delete(environment, "HTTP_AUTHORIZATION"); - if(QUERY(clearpass) && id->auth && id->realauth ) { - environment["REMOTE_USER"] = (id->realauth/":")[0]; - environment["REMOTE_PASSWORD"] = (id->realauth/":")[1]; - } else { - m_delete(environment, "REMOTE_PASSWORD"); - } - if (id->rawauth) { - environment["AUTH_TYPE"] = (id->rawauth/" ")[0]; - } - // DWERROR(sprintf("%O\n", environment)); - // ffd = id->my_fd; - } -} - -mapping(string:string) global_env = ([]); -void start(int n, object conf) -{ - DWERROR("PHP:start()\n"); - - module_dependencies(conf, ({ "pathinfo" })); - if(conf) - { - string tmp=conf->query("MyWorldLocation"); - sscanf(tmp, "%*s//%s", tmp); - sscanf(tmp, "%s:", tmp); - sscanf(tmp, "%s/", tmp); - global_env["SERVER_NAME"]=tmp; - global_env["SERVER_SOFTWARE"]=roxen.version(); - global_env["GATEWAY_INTERFACE"]="PHP/1.1"; - global_env["SERVER_PROTOCOL"]="HTTP/1.0"; - global_env["SERVER_URL"]=conf->query("MyWorldLocation"); - - array us = ({0,0}); - foreach(query("extra_env")/"\n", tmp) - if(sscanf(tmp, "%s=%s", us[0], us[1])==2) - global_env[us[0]] = us[1]; - } -} -mapping handle_file_extension(object o, string e, object id) -{ - DWERROR("PHP:handle_file_extension()\n"); - id->do_not_disconnect = 1; - PHPScript( id )->run(); - return http_pipe_in_progress(); -} -/* -** Variables et. al. -*/ -array (string) query_file_extensions() -{ - return QUERY(ext); -} - - -void create(object conf) -{ - defvar("env", 0, "Pass environment variables", TYPE_FLAG, - "If this is set, all environment variables roxen has will be " - "passed to PHP scripts, not only those defined in the PHP/1.1 standard. " - "This includes PATH. (For a quick test, try this script with " - "and without this variable set:" - "<pre>" - "#!/bin/sh\n\n" - "echo Content-type: text/plain\n" - "echo ''\n" - "env\n" - "</pre>)"); - - defvar("rxml", 0, "Parse RXML in PHP-scripts", TYPE_FLAG, - "If this is set, the output from PHP-scripts handled by this " - "module will be RXMl parsed. NOTE: No data will be returned to the " - "client until the PHP-script is fully parsed."); - - defvar("extra_env", "", "Extra environment variables", TYPE_TEXT_FIELD, - "Extra variables to be sent to the script, format:<pre>" - "NAME=value\n" - "NAME=value\n" - "</pre>Please note that the standard variables will have higher " - "priority."); - - defvar("ext", - ({"php", "php3", "php4" - }), "PHP-script extensions", TYPE_STRING_LIST, - "All files ending with these extensions, will be parsed as "+ - "PHP-scripts."); - - defvar("rawauth", 0, "Raw user info", TYPE_FLAG|VAR_MORE, - "If set, the raw, unparsed, user info will be sent to the script, " - " in the HTTP_AUTHORIZATION environment variable. This is not " - "recommended, but some scripts need it. Please note that this " - "will give the scripts access to the password used."); - - defvar("clearpass", 0, "Send decoded password", TYPE_FLAG|VAR_MORE, - "If set, the variable REMOTE_PASSWORD will be set to the decoded " - "password value."); - - defvar( "cgi_tag", 1, "Provide the <cgi> tag", TYPE_FLAG, - "If set, the <cgi> tag will be available" ); -} - -int|string tag_cgi( string tag, mapping args, object id ) -{ - DWERROR("PHP:tag_cgi()\n"); - - if(!query("cgi_tag")) - return 0; - - if(args->help) - return ("<b><"+tag+" script=path [cache=seconds] [default-argument=value] " - "[argument=value]>:</b>"); - - if(!args->cache) - NOCACHE(); - else - CACHE( (int)args->cache || 60 ); - - - object fid = id->clone_me(); - string file = args->script; - if(!file) - return "No 'script' argument to the PHP tag"; - fid->not_query = fix_relative( file, id ); - foreach(indices(args), string arg ) - { - if(arg == "script") - continue; - if(arg == "cache") - continue; - if(arg[..7] == "default-") - { - if(!id->variables[arg[8..]]) - fid->variables[arg[8..]] = args[arg]; - } - else - fid->variables[arg] = args[arg]; - } - fid->realfile=0; - fid->method = "GET"; - mixed e = catch - { - string data=handle_file_extension( 0, "cgi", fid )->file->read(); - if(!sscanf(data, "%*s\r\n\r\n%s", data)) - sscanf(data, "%*s\n\n%s", data); - return data; - }; - return ("Failed to run PHP script: <font color=red><pre>"+ - (html_encode_string(describe_backtrace(e))/"\n")[0]+ - "</pre></font>"); -} - - -mapping query_tag_callers() -{ - return ([ - "cgi":tag_cgi, - ]); -} diff --git a/sapi/roxen/roxen.c b/sapi/roxen/roxen.c deleted file mode 100644 index 1ec54f3138..0000000000 --- a/sapi/roxen/roxen.c +++ /dev/null @@ -1,745 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP version 4.0 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997, 1998, 1999 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 2.0 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_0.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 "main.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> - -/* 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 *)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) fprintf(stderr, "*** php lock (thr_id=%d, glob=%d).\n", th_self(), current_thread);THREADS_ALLOW();mt_lock(&roxen_php_execution_lock);fprintf(stderr, "*** php locked.\n");THREADS_DISALLOW() -# define PHP_UNLOCK(X) mt_unlock(&roxen_php_execution_lock);fprintf(stderr, "*** php unlocked (thr_id=%d, glob=%d).\n", th_self(), current_thread); -# define PHP_DESTROY() mt_destroy(&roxen_php_execution_lock) -#else /* !_REENTRANT */ -# define PHP_INIT_LOCK() -# define PHP_LOCK(X) fprintf(stderr, "*** php lock (thr_id=%d).\n", th_self()); -# define PHP_UNLOCK(X) fprintf(stderr, "*** php unlock (thr_id=%d).\n", th_self()); -# 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 interpretor to be locked. - */ -#define THREAD_SAFE_RUN(COMMAND, what) do {\ - struct thread_state *state;\ - fprintf(stderr,"threads: %d disabled: %d id: %d\n",num_threads, threads_disabled, th_self());\ - if((state = thread_state_for_id(th_self()))!=NULL) {\ - if(!state->swapped) {\ - fprintf(stderr, "MT lock (%s).\n", what);\ - COMMAND;\ - fprintf(stderr, "MT locked done (%s).\n", what);\ - } else {\ - fprintf(stderr, "MT nonlock (%s).\n", what); \ - mt_lock(&interpreter_lock);\ - SWAP_IN_THREAD(state);\ - fprintf(stderr, "MT locked.\n", what); \ - COMMAND;\ - fprintf(stderr, "MT locked done.\n", what); \ - SWAP_OUT_THREAD(state);\ - mt_unlock(&interpreter_lock);\ - fprintf(stderr, "MT unlocked.\n", what); \ - }\ - }\ -} while(0) - -/* Toggle debug printouts, for now... */ -/*#define MUCH_DEBUG */ -#ifndef MUCH_DEBUG -void no_fprintf(){} -#define fprintf no_fprintf -#endif - -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) { - fprintf(stderr, "Header lookup for %s: default (%s)\n", headername, - default_value); - return default_value; - } - fprintf(stderr, "Header lookup for %s: %s(%d)\n", headername, - head->u.string->str, head->u.string->len); - 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) { - fprintf(stderr, "Header lookup for %s: default (%d)\n", headername, - default_value); - return default_value; - } - fprintf(stderr, "Header lookup for %s: %d \n", headername, - head->u.integer); - 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 * - * interpretor for better threading. - */ - -static int -php_roxen_low_ub_write(const char *str, uint str_length) { - int sent_bytes = 0; - struct pike_string *to_write = NULL; -#ifdef ZTS - PLS_FETCH(); -#endif -#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(sp[-1].type == PIKE_T_INT) - sent_bytes = sp[-1].u.integer; - pop_stack(); - if(sent_bytes != str_length) { - /* This means the connection is closed. Dead. Gone. *sniff* */ - PG(connection_status) = PHP_CONNECTION_ABORTED; - zend_bailout(); - } - fprintf(stderr, "low_write done.\n"); - 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) -{ - 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), - "write"); - } - fprintf(stderr, "write done.\n"); - 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); - - fprintf(stderr, "Setting header %s to %s\n", hind->str, value); - 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 SLS_DC) -{ - char *header_name, *header_content, *p; - header_name = sapi_header->header; - header_content = p = strchr(header_name, ':'); - - if(!p) return 0; - do { - header_content++; - } while(*header_content == ' '); - THREAD_SAFE_RUN(php_roxen_set_header(header_name, header_content, p), "header handler"); - efree(sapi_header->header); - return 1; -} - -/* - * 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 SLS_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); - fprintf(stderr, "Send Headers (%d)...\n", SG(sapi_headers).http_response_code); - - 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 SLS_DC) -{ - int res = 0; - THREAD_SAFE_RUN(res = php_roxen_low_send_headers(sapi_headers SLS_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 - fprintf(stderr, "read post (%d bytes max)\n", count_bytes); - - 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(sp[-1].type == T_STRING) { - MEMCPY(buf, sp[-1].u.string->str, total_read = sp[-1].u.string->len); - buf[total_read] = '\0'; - } else - total_read = -1; - pop_stack(); - return total_read; -} - -static int -php_roxen_sapi_read_post(char *buf, uint count_bytes SLS_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(SLS_D) -{ - char *cookies; - cookies = lookup_string_header("HTTP_COOKIE", NULL); - return cookies; -} - -static void php_info_roxen(ZEND_MODULE_INFO_FUNC_ARGS) -{ -#if 0 - char buf[512]; - - PUTS("<table border=5 width=600>\n"); - 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); - */ - PUTS("</table>"); -#endif -} - -static zend_module_entry php_roxen_module = { - "Roxen", - NULL, - NULL, - NULL, - NULL, - NULL, - php_info_roxen, - STANDARD_MODULE_PROPERTIES -}; - -static int php_roxen_startup(sapi_module_struct *sapi_module) -{ - if(php_module_startup(sapi_module) == FAILURE - || zend_register_module(&php_roxen_module) == FAILURE) { - return FAILURE; - } else { - return SUCCESS; - } -} - -/* this structure is static (as in "it does not change") */ - -void pike_module_exit(void); - -static sapi_module_struct sapi_module = { - "PHP Language", - - php_module_startup, /* startup */ - pike_module_exit, /* shutdown */ - - php_roxen_sapi_ub_write, /* unbuffered write */ - - 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 */ - - 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(CLS_D ELS_DC PLS_DC SLS_DC) -{ - 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); - /* fprintf(stderr, "Header: %s(%d)=%s\n", buf, buf_len, val->u.string->str);*/ - - 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); - - fprintf(stderr, "Set up header environment.\n"); - */ -} - -/* - * php_roxen_module_main() is called by the per-request handler and - * "executes" the script - */ - -static int php_roxen_module_main(SLS_D) -{ - int res; - zend_file_handle file_handle; -#ifdef ZTS - CLS_FETCH(); - PLS_FETCH(); - ELS_FETCH(); -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif -#endif - file_handle.type = ZEND_HANDLE_FILENAME; - file_handle.filename = THIS->filename; - file_handle.free_filename = 0; - THREADS_ALLOW(); - fprintf(stderr, "Request Startup.\n"); - res = php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC); - THREADS_DISALLOW(); - if(res == FAILURE) { - return 0; - } - php_roxen_hash_environment(CLS_C ELS_CC PLS_CC SLS_CC); - THREADS_ALLOW(); - fprintf(stderr, "Script Execute.\n"); - php_execute_script(&file_handle CLS_CC ELS_CC PLS_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; - SLS_FETCH(); -#ifdef ROXEN_USE_ZTS - GET_THIS(); -#endif - - if(current_thread == th_self()) - error("PHP4.Interpetor->run: Tried to run a PHP-script from a PHP " - "callback!"); - get_all_args("PHP4.Interpretor->run", args, "%S%m%O%*", &script, - &request_data, &my_fd_obj, &done_callback); - if(done_callback->type != PIKE_T_FUNCTION) - error("PHP4.Interpretor->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 the absolute path to the file */ - SG(request_info).path_translated = - lookup_string_header("PATH_TRANSLATED", 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("CONTENT_LENGTH", 0); - SG(request_info).content_type = "text/html"; - 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) - error("PHP4.Interpretor->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(SLS_C); - current_thread = -1; - PHP_UNLOCK(THIS); - - apply_svalue(done_callback, 0); - pop_stack(); - pop_n_elems(args); - push_int(status); - -} - - -/* Clear the object global struct */ -static void clear_struct(struct object *o) -{ - MEMSET(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() -{ - if (!roxen_php_initialized) { -#ifdef ZTS - tsrm_startup(1, 1, 0); -#ifdef ROXEN_USE_ZTS - roxen_globals_id = ts_allocate_id(sizeof(php_roxen_request), NULL, NULL); -#endif -#endif - sapi_startup(&sapi_module); - php_roxen_startup(&sapi_module); - 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("Interpretor", (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; - sapi_module.shutdown(&sapi_module); - if(php_program) free_program(php_program); -#ifdef ZTS - tsrm_shutdown(); -#endif - PHP_DESTROY(); -} -#endif |