Back to index

php5  5.3.10
roxen.c
Go to the documentation of this file.
00001 /* 
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: David Hedbor <neotron@php.net>                               |
00016    | Based on aolserver SAPI by Sascha Schumann <sascha@schumann.cx>      |
00017    +----------------------------------------------------------------------+
00018  */
00019 
00020 /* $Id: roxen.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include "php.h"
00023 #ifdef HAVE_ROXEN
00024 
00025 #include "php_ini.h"
00026 #include "php_globals.h"
00027 #include "SAPI.h"
00028 #include "php_main.h" 
00029 #include "ext/standard/info.h"
00030 
00031 #include "php_version.h"
00032 
00033 #ifndef ZTS
00034 /* Only valid if thread safety is enabled. */
00035 #undef ROXEN_USE_ZTS
00036 #endif
00037 
00038 
00039 /* Pike Include Files 
00040  *
00041  * conflicts with pike avoided by only using long names. Requires a new
00042  * Pike 0.7 since it was implemented for this interface only.
00043  *
00044  */
00045 #define NO_PIKE_SHORTHAND
00046 
00047 #include <fdlib.h>
00048 #include <program.h>
00049 #include <pike_types.h>
00050 #include <interpret.h>
00051 #include <module_support.h>
00052 #include <error.h>
00053 #include <array.h>
00054 #include <backend.h>
00055 #include <stralloc.h>
00056 #include <mapping.h>
00057 #include <object.h>
00058 #include <threads.h>
00059 #include <builtin_functions.h>
00060 #include <operators.h>
00061 
00062 #undef HIDE_GLOBAL_VARIABLES
00063 #undef REVEAL_GLOBAL_VARIABLES
00064 #define HIDE_GLOBAL_VARIABLES()
00065 #define REVEAL_GLOBAL_VARIABLES()
00066 
00067 /* php_roxen_request is per-request object storage */
00068 
00069 typedef struct
00070 {
00071   struct mapping *request_data;
00072   struct object *my_fd_obj;
00073   int my_fd;
00074   char *filename;
00075 } php_roxen_request;
00076 
00077 
00078 /* Defines to get to the data supplied when the script is started. */
00079 
00080 #ifdef ROXEN_USE_ZTS
00081 
00082 /* ZTS does work now, but it seems like it's faster using the "serialization"
00083  * method I previously used. Thus it's not used unless ROXEN_USE_ZTS is defined.
00084  */
00085 
00086 /* Per thread storage area id... */
00087 static int roxen_globals_id;
00088 
00089 # define GET_THIS() php_roxen_request *_request = ts_resource(roxen_globals_id)
00090 # define THIS _request
00091 #else
00092 static php_roxen_request *current_request = NULL;
00093 
00094 # define GET_THIS() current_request = ((php_roxen_request *)Pike_fp->current_storage)
00095 # define THIS current_request
00096 #endif
00097 
00098 /* File descriptor integer. Used to write directly to the FD without 
00099  * passing Pike
00100  */
00101 #define MY_FD    (THIS->my_fd)
00102 
00103 /* FD object. Really a PHPScript object from Pike which implements a couple
00104  * of functions to handle headers, writing and buffering.
00105  */
00106 #define MY_FD_OBJ        ((struct object *)(THIS->my_fd_obj))
00107 
00108 /* Mapping with data supplied from the calling Roxen module. Contains
00109  * a mapping with headers, an FD object etc.
00110  */
00111 #define REQUEST_DATA ((struct mapping *)(THIS->request_data))
00112 
00113 
00114 #if defined(_REENTRANT) && !defined(ROXEN_USE_ZTS)
00115 /* Lock used to serialize the PHP execution. If ROXEN_USE_ZTS is defined, we
00116  * are using the PHP thread safe mechanism instead.
00117  */
00118 static PIKE_MUTEX_T roxen_php_execution_lock;
00119 # define PHP_INIT_LOCK()    mt_init(&roxen_php_execution_lock)
00120 # define PHP_LOCK(X)    THREADS_ALLOW();mt_lock(&roxen_php_execution_lock);THREADS_DISALLOW()
00121 # define PHP_UNLOCK(X)      mt_unlock(&roxen_php_execution_lock);
00122 # define PHP_DESTROY()      mt_destroy(&roxen_php_execution_lock)
00123 #else /* !_REENTRANT */
00124 # define PHP_INIT_LOCK()    
00125 # define PHP_LOCK(X)
00126 # define PHP_UNLOCK(X)
00127 # define PHP_DESTROY()      
00128 #endif /* _REENTRANT */
00129 
00130 extern int fd_from_object(struct object *o);
00131 static unsigned char roxen_php_initialized;
00132 
00133 /* This allows calling of pike functions from the PHP callbacks,
00134  * which requires the Pike interpreter to be locked.
00135  */
00136 #define THREAD_SAFE_RUN(COMMAND, what)  do {\
00137   struct thread_state *state;\
00138  if((state = thread_state_for_id(th_self()))!=NULL) {\
00139     if(!state->swapped) {\
00140       COMMAND;\
00141     } else {\
00142       mt_lock(&interpreter_lock);\
00143       SWAP_IN_THREAD(state);\
00144       COMMAND;\
00145       SWAP_OUT_THREAD(state);\
00146       mt_unlock(&interpreter_lock);\
00147     }\
00148   }\
00149 } while(0)
00150 
00151 struct program *php_program;
00152 
00153 
00154 /* To avoid executing a PHP script from a PHP callback, which would
00155  * create a deadlock, a global thread id is used. If the thread calling the
00156  * php-script is the same as the current thread, it fails. 
00157  */
00158 static int current_thread = -1;
00159 
00160 
00161 /* Low level header lookup. Basically looks for the named header in the mapping
00162  * headers in the supplied options mapping.
00163  */
00164  
00165 static INLINE struct svalue *lookup_header(char *headername)
00166 {
00167   struct svalue *headers, *value;
00168   struct pike_string *sind;
00169 #ifdef ROXEN_USE_ZTS
00170   GET_THIS();
00171 #endif
00172   sind = make_shared_string("env");
00173   headers = low_mapping_string_lookup(REQUEST_DATA, sind);
00174   free_string(sind);
00175   if(!headers || headers->type != PIKE_T_MAPPING) return NULL;
00176   sind = make_shared_string(headername);
00177   value = low_mapping_string_lookup(headers->u.mapping, sind);
00178   free_string(sind);
00179   if(!value) return NULL;
00180   return value;
00181 }
00182 
00183 /* Lookup a header in the mapping and return the value as a string, or
00184  * return the default if it's missing
00185  */
00186 INLINE static char *lookup_string_header(char *headername, char *default_value)
00187 {
00188   struct svalue *head = NULL;
00189   THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
00190   if(!head || head->type != PIKE_T_STRING)
00191     return default_value;
00192   return head->u.string->str;
00193 }
00194 
00195 /* Lookup a header in the mapping and return the value as if it's an integer
00196  * and otherwise return the default.
00197  */
00198 INLINE static int lookup_integer_header(char *headername, int default_value)
00199 {
00200   struct svalue *head = NULL;
00201   THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
00202   if(!head || head->type != PIKE_T_INT)
00203     return default_value;
00204   return head->u.integer;
00205 }
00206 
00207 /*
00208  * php_roxen_low_ub_write() writes data to the client connection. Might be
00209  * rewritten to do more direct IO to save CPU and the need to lock the *
00210  * interpreter for better threading.
00211  */
00212 
00213 static int
00214 php_roxen_low_ub_write(const char *str, uint str_length TSRMLS_DC) {
00215   int sent_bytes = 0;
00216   struct pike_string *to_write = NULL;
00217 #ifdef ROXEN_USE_ZTS
00218   GET_THIS();
00219 #endif
00220 
00221   if(!MY_FD_OBJ->prog) {
00222     PG(connection_status) = PHP_CONNECTION_ABORTED;
00223     zend_bailout();
00224     return -1;
00225   }
00226   to_write = make_shared_binary_string(str, str_length);
00227   push_string(to_write);
00228   safe_apply(MY_FD_OBJ, "write", 1);
00229   if(Pike_sp[-1].type == PIKE_T_INT)
00230     sent_bytes = Pike_sp[-1].u.integer;
00231   pop_stack();
00232   if(sent_bytes != str_length) {
00233     /* This means the connection is closed. Dead. Gone. *sniff*  */
00234     php_handle_aborted_connection();
00235   }
00236   return sent_bytes;
00237 }
00238 
00239 /*
00240  * php_roxen_sapi_ub_write() calls php_roxen_low_ub_write in a Pike thread
00241  * safe manner.
00242  */
00243 
00244 static int
00245 php_roxen_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
00246 {
00247 #ifdef ROXEN_USE_ZTS
00248   GET_THIS();
00249 #endif
00250 
00251   int sent_bytes = 0, fd = MY_FD;
00252   if(fd)
00253   {
00254     for(sent_bytes=0;sent_bytes < str_length;)
00255     {
00256       int written;
00257       written = fd_write(fd, str + sent_bytes, str_length - sent_bytes);
00258       if(written < 0)
00259       {
00260        switch(errno)
00261        {
00262         default:
00263          /* This means the connection is closed. Dead. Gone. *sniff*  */
00264          PG(connection_status) = PHP_CONNECTION_ABORTED;
00265          zend_bailout();
00266          return sent_bytes;
00267         case EINTR: 
00268         case EWOULDBLOCK:
00269          continue;
00270        }
00271 
00272       } else {
00273        sent_bytes += written;
00274       }
00275     }
00276   } else {
00277     THREAD_SAFE_RUN(sent_bytes = php_roxen_low_ub_write(str, str_length TSRMLS_CC),
00278                   "write");
00279   }
00280   return sent_bytes;
00281 }
00282 
00283 /* php_roxen_set_header() sets a header in the header mapping. Called in a
00284  * thread safe manner from php_roxen_sapi_header_handler.
00285  */
00286 static void php_roxen_set_header(char *header_name, char *value, char *p)
00287 {
00288   struct svalue hsval;
00289   struct pike_string *hval, *ind, *hind;
00290   struct mapping *headermap;
00291   struct svalue *s_headermap;
00292 #ifdef ROXEN_USE_ZTS
00293   GET_THIS();
00294 #endif
00295   hval = make_shared_string(value);
00296   ind = make_shared_string(" _headers");
00297   hind = make_shared_binary_string(header_name,
00298                                (int)(p - header_name));
00299 
00300   s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
00301   if(!s_headermap)
00302   {
00303     struct svalue mappie;                                           
00304     mappie.type = PIKE_T_MAPPING;
00305     headermap = allocate_mapping(1);
00306     mappie.u.mapping = headermap;
00307     mapping_string_insert(REQUEST_DATA, ind, &mappie);
00308     free_mapping(headermap);
00309   } else
00310     headermap = s_headermap->u.mapping;
00311 
00312   hsval.type = PIKE_T_STRING;
00313   hsval.u.string = hval;
00314   mapping_string_insert(headermap, hind, &hsval);
00315 
00316   free_string(hval);
00317   free_string(ind);
00318   free_string(hind);
00319 }
00320 
00321 /*
00322  * php_roxen_sapi_header_handler() sets a HTTP reply header to be 
00323  * sent to the client.
00324  */
00325 static int
00326 php_roxen_sapi_header_handler(sapi_header_struct *sapi_header,
00327                            sapi_headers_struct *sapi_headers TSRMLS_DC)
00328 {
00329   char *header_name, *header_content, *p;
00330   header_name = sapi_header->header;
00331   header_content = p = strchr(header_name, ':');
00332   
00333   if(p) {
00334   do {
00335     header_content++;
00336   } while(*header_content == ' ');
00337     THREAD_SAFE_RUN(php_roxen_set_header(header_name, header_content, p), "header handler");
00338   }
00339   sapi_free_header(sapi_header);
00340   return 0;
00341 }
00342 
00343 /*
00344  * php_roxen_sapi_send_headers() flushes the headers to the client.
00345  * Called before real content is sent by PHP.
00346  */
00347 
00348 static int
00349 php_roxen_low_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00350 {
00351   struct pike_string *ind;
00352   struct svalue *s_headermap;
00353 #ifdef ROXEN_USE_ZTS
00354   GET_THIS();
00355 #endif
00356 
00357   if(!MY_FD_OBJ->prog) {
00358     PG(connection_status) = PHP_CONNECTION_ABORTED;
00359     zend_bailout();
00360     return SAPI_HEADER_SEND_FAILED;
00361   }
00362   ind = make_shared_string(" _headers");  
00363   s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
00364   free_string(ind);
00365   
00366   push_int(SG(sapi_headers).http_response_code);
00367   if(s_headermap && s_headermap->type == PIKE_T_MAPPING)
00368     ref_push_mapping(s_headermap->u.mapping);
00369   else
00370     push_int(0);
00371   safe_apply(MY_FD_OBJ, "send_headers", 2);
00372   pop_stack();
00373   
00374   return SAPI_HEADER_SENT_SUCCESSFULLY;
00375 }
00376 
00377 static int
00378 php_roxen_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00379 {
00380   int res = 0;
00381   THREAD_SAFE_RUN(res = php_roxen_low_send_headers(sapi_headers TSRMLS_CC), "send headers");
00382   return res;
00383 }
00384 
00385 /*
00386  * php_roxen_sapi_read_post() reads a specified number of bytes from
00387  * the client. Used for POST/PUT requests.
00388  */
00389 
00390 INLINE static int php_roxen_low_read_post(char *buf, uint count_bytes)
00391 {
00392   uint total_read = 0;
00393 #ifdef ROXEN_USE_ZTS
00394   GET_THIS();
00395 #endif
00396   TSRMLS_FETCH();
00397   
00398   if(!MY_FD_OBJ->prog)
00399   {
00400     PG(connection_status) = PHP_CONNECTION_ABORTED;
00401     zend_bailout();
00402     return -1;
00403   }
00404   push_int(count_bytes);
00405   safe_apply(MY_FD_OBJ, "read_post", 1);
00406   if(Pike_sp[-1].type == PIKE_T_STRING) {
00407     MEMCPY(buf, Pike_sp[-1].u.string->str,
00408            (total_read = Pike_sp[-1].u.string->len));
00409     buf[total_read] = '\0';
00410   } else
00411     total_read = 0;
00412   pop_stack();
00413   return total_read;
00414 }
00415 
00416 static int
00417 php_roxen_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC)
00418 {
00419   uint total_read = 0;
00420   THREAD_SAFE_RUN(total_read = php_roxen_low_read_post(buf, count_bytes), "read post");
00421   return total_read;
00422 }
00423 
00424 /* 
00425  * php_roxen_sapi_read_cookies() returns the Cookie header from
00426  * the HTTP request header
00427  */
00428        
00429 static char *
00430 php_roxen_sapi_read_cookies(TSRMLS_D)
00431 {
00432   char *cookies;
00433   cookies = lookup_string_header("HTTP_COOKIE", NULL);
00434   return cookies;
00435 }
00436 
00437 static void php_info_roxen(ZEND_MODULE_INFO_FUNC_ARGS)
00438 {
00439   /*  char buf[512]; */
00440   php_info_print_table_start();
00441   php_info_print_table_row(2, "SAPI module version", "$Id: roxen.c 321634 2012-01-01 13:15:04Z felipe $");
00442   /*  php_info_print_table_row(2, "Build date", Ns_InfoBuildDate());
00443       php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile());
00444       php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog());
00445       php_info_print_table_row(2, "Installation path", Ns_InfoHomePath());
00446       php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname());
00447       php_info_print_table_row(2, "Source code label", Ns_InfoLabel());
00448       php_info_print_table_row(2, "Server platform", Ns_InfoPlatform());
00449       snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion());
00450       php_info_print_table_row(2, "Server version", buf);
00451       snprintf(buf, 511, "%d day(s), %02d:%02d:%02d", 
00452       uptime / 86400,
00453       (uptime / 3600) % 24,
00454       (uptime / 60) % 60,
00455       uptime % 60);
00456       php_info_print_table_row(2, "Server uptime", buf);
00457   */
00458   php_info_print_table_end();
00459 }
00460 
00461 static zend_module_entry php_roxen_module = {
00462   STANDARD_MODULE_HEADER,
00463   "Roxen",
00464   NULL,
00465   NULL,
00466   NULL,
00467   NULL,
00468   NULL,
00469   php_info_roxen,
00470   NULL,
00471   STANDARD_MODULE_PROPERTIES
00472 };
00473 
00474 static int php_roxen_startup(sapi_module_struct *sapi_module)
00475 {
00476   if(php_module_startup(sapi_module, &php_roxen_module, 1) == FAILURE) {
00477     return FAILURE;
00478   } else {
00479     return SUCCESS;
00480   }
00481 }
00482 
00483 /* this structure is static (as in "it does not change") */
00484 
00485 static sapi_module_struct roxen_sapi_module = {
00486   "roxen",
00487   "Roxen",
00488   php_roxen_startup,               /* startup */
00489   php_module_shutdown_wrapper,            /* shutdown */
00490   NULL,                                   /* activate */
00491   NULL,                                   /* deactivate */
00492   php_roxen_sapi_ub_write,         /* unbuffered write */
00493   NULL,                                   /* flush */
00494   NULL,                                   /* get uid */
00495   NULL,                                   /* getenv */
00496   php_error,                       /* error handler */
00497   php_roxen_sapi_header_handler,   /* header handler */
00498   php_roxen_sapi_send_headers,            /* send headers handler */
00499   NULL,                                   /* send header handler */
00500   php_roxen_sapi_read_post,        /* read POST data */
00501   php_roxen_sapi_read_cookies,            /* read Cookies */
00502   NULL,                                   /* register server variables */
00503   NULL,                                   /* Log message */
00504   NULL,                                   /* Get request time */
00505   NULL,                                   /* Child terminate */
00506 
00507   STANDARD_SAPI_MODULE_PROPERTIES
00508 };
00509 
00510 /*
00511  * php_roxen_hash_environment() populates the php script environment
00512  * with a number of variables. HTTP_* variables are created for
00513  * the HTTP header data, so that a script can access these.
00514  */
00515 #define ADD_STRING(name)                                                                   \
00516        MAKE_STD_ZVAL(zvalue);                                                                     \
00517        zvalue->type = IS_STRING;                                                                  \
00518        zvalue->value.str.len = strlen(buf);                                                \
00519        zvalue->value.str.val = estrndup(buf, zvalue->value.str.len);  \
00520        zend_hash_update(&EG(symbol_table), name, sizeof(name),        \
00521                      &zvalue, sizeof(zval *), NULL)
00522 
00523 static void
00524 php_roxen_hash_environment(TSRMLS_D)
00525 {
00526   int i;
00527   char buf[512];
00528   zval *zvalue;
00529   struct svalue *headers;
00530   struct pike_string *sind;
00531   struct array *indices;
00532   struct svalue *ind, *val;
00533 #ifdef ROXEN_USE_ZTS
00534   GET_THIS();
00535 #endif
00536   sind = make_shared_string("env");
00537   headers = low_mapping_string_lookup(REQUEST_DATA, sind);
00538   free_string(sind);
00539   if(headers && headers->type == PIKE_T_MAPPING) {
00540     indices = mapping_indices(headers->u.mapping);
00541     for(i = 0; i < indices->size; i++) {
00542       ind = &indices->item[i];
00543       val = low_mapping_lookup(headers->u.mapping, ind);
00544       if(ind && ind->type == PIKE_T_STRING &&
00545         val && val->type == PIKE_T_STRING) {
00546        int buf_len;
00547        buf_len = MIN(511, ind->u.string->len);
00548        strncpy(buf, ind->u.string->str, buf_len);
00549        buf[buf_len] = '\0'; /* Terminate correctly */
00550        MAKE_STD_ZVAL(zvalue);
00551        zvalue->type = IS_STRING;
00552        zvalue->value.str.len = val->u.string->len;
00553        zvalue->value.str.val = estrndup(val->u.string->str, zvalue->value.str.len);
00554        
00555        zend_hash_update(&EG(symbol_table), buf, buf_len + 1, &zvalue, sizeof(zval *), NULL);
00556       }
00557     }
00558     free_array(indices);
00559   }
00560   
00561   /*
00562     MAKE_STD_ZVAL(zvalue);
00563     zvalue->type = IS_LONG;
00564     zvalue->value.lval = Ns_InfoBootTime();
00565     zend_hash_update(&EG(symbol_table), "SERVER_BOOTTIME", sizeof("SERVER_BOOTTIME"), &zvalue, sizeof(zval *), NULL);
00566   */
00567 }
00568 
00569 /*
00570  * php_roxen_module_main() is called by the per-request handler and
00571  * "executes" the script
00572  */
00573 
00574 static int php_roxen_module_main(TSRMLS_D)
00575 {
00576   int res, len;
00577   char *dir;
00578   zend_file_handle file_handle;
00579 #ifdef ROXEN_USE_ZTS
00580   GET_THIS();
00581 #endif
00582 
00583   file_handle.type = ZEND_HANDLE_FILENAME;
00584   file_handle.filename = THIS->filename;
00585   file_handle.free_filename = 0;
00586   file_handle.opened_path = NULL;
00587 
00588   THREADS_ALLOW();
00589   res = php_request_startup(TSRMLS_C);
00590   THREADS_DISALLOW();
00591   if(res == FAILURE) {
00592     return 0;
00593   }
00594   php_roxen_hash_environment(TSRMLS_C);
00595   THREADS_ALLOW();
00596   php_execute_script(&file_handle TSRMLS_CC);
00597   php_request_shutdown(NULL);
00598   THREADS_DISALLOW();
00599   return 1;
00600 }
00601 
00602 /*
00603  * The php_roxen_request_handler() is called per request and handles
00604  * everything for one request.
00605  */
00606 
00607 void f_php_roxen_request_handler(INT32 args)
00608 {
00609   struct object *my_fd_obj;
00610   struct mapping *request_data;
00611   struct svalue *done_callback, *raw_fd;
00612   struct pike_string *script, *ind;
00613   int status = 1;
00614 #ifdef ROXEN_USE_ZTS
00615   GET_THIS();
00616 #endif
00617   TSRMLS_FETCH();
00618 
00619   if(current_thread == th_self())
00620     php_error(E_WARNING, "PHP5.Interpreter->run: Tried to run a PHP-script from a PHP "
00621          "callback!");
00622   get_all_args("PHP5.Interpreter->run", args, "%S%m%O%*", &script,
00623               &request_data, &my_fd_obj, &done_callback);
00624   if(done_callback->type != PIKE_T_FUNCTION) 
00625     php_error(E_WARNING, "PHP5.Interpreter->run: Bad argument 4, expected function.\n");
00626   PHP_LOCK(THIS); /* Need to lock here or reusing the same object might cause
00627                      * problems in changing stuff in that object */
00628 #ifndef ROXEN_USE_ZTS
00629   GET_THIS();
00630 #endif
00631   THIS->request_data = request_data;
00632   THIS->my_fd_obj = my_fd_obj;
00633   THIS->filename = script->str;
00634   current_thread = th_self();
00635   SG(request_info).query_string = lookup_string_header("QUERY_STRING", 0);
00636   SG(server_context) = (void *)1; /* avoid server_context == NULL */
00637 
00638   /* path_translated is apparently the absolute path to the file, not
00639      the translated PATH_INFO
00640   */
00641   SG(request_info).path_translated =
00642     lookup_string_header("SCRIPT_FILENAME", NULL);
00643   SG(request_info).request_uri = lookup_string_header("DOCUMENT_URI", NULL);
00644   if(!SG(request_info).request_uri)
00645     SG(request_info).request_uri = lookup_string_header("SCRIPT_NAME", NULL);
00646   SG(request_info).request_method = lookup_string_header("REQUEST_METHOD", "GET");
00647   SG(request_info).content_length = lookup_integer_header("HTTP_CONTENT_LENGTH", 0);
00648   SG(request_info).content_type = lookup_string_header("HTTP_CONTENT_TYPE", NULL);
00649   SG(sapi_headers).http_response_code = 200;
00650 
00651   /* FIXME: Check for auth stuff needs to be fixed... */ 
00652   SG(request_info).auth_user = NULL; 
00653   SG(request_info).auth_password = NULL;
00654   
00655   ind = make_shared_binary_string("my_fd", 5);
00656   raw_fd = low_mapping_string_lookup(THIS->request_data, ind);
00657   if(raw_fd && raw_fd->type == PIKE_T_OBJECT)
00658   {
00659     int fd = fd_from_object(raw_fd->u.object);
00660     if(fd == -1)
00661       php_error(E_WARNING, "PHP5.Interpreter->run: my_fd object not open or not an FD.\n");
00662     THIS->my_fd = fd;
00663   } else
00664     THIS->my_fd = 0;
00665   
00666   status = php_roxen_module_main(TSRMLS_C);
00667   current_thread = -1;
00668   
00669   apply_svalue(done_callback, 0);
00670   pop_stack();
00671   pop_n_elems(args);
00672   push_int(status);
00673   PHP_UNLOCK(THIS);
00674 }
00675 
00676 
00677 /* Clear the object global struct */
00678 static void clear_struct(struct object *o)
00679 {
00680   MEMSET(Pike_fp->current_storage, 0, sizeof(php_roxen_request));
00681 }
00682 
00683 
00684 /*
00685  * pike_module_init() is called by Pike once at startup
00686  *
00687  * This functions allocates basic structures
00688  */
00689 
00690 void pike_module_init( void )
00691 {
00692   if (!roxen_php_initialized) {
00693 #ifdef ZTS
00694     tsrm_startup(1, 1, 0, NULL);
00695 #ifdef ROXEN_USE_ZTS
00696     ts_allocate_id(&roxen_globals_id, sizeof(php_roxen_request), NULL, NULL);
00697 #endif  
00698 #endif
00699     sapi_startup(&roxen_sapi_module);
00700     /*php_roxen_startup(&roxen_sapi_module); removed - should be called from SAPI activation*/
00701     roxen_php_initialized = 1;
00702     PHP_INIT_LOCK();
00703   }
00704   start_new_program(); /* Text */
00705   ADD_STORAGE(php_roxen_request);
00706   set_init_callback(clear_struct);
00707   pike_add_function("run", f_php_roxen_request_handler,
00708                   "function(string, mapping, object, function:int)", 0);
00709   add_program_constant("Interpreter", (php_program = end_program()), 0);
00710 }
00711 
00712 /*
00713  * pike_module_exit() performs the last steps before the
00714  * server exists. Shutdowns basic services and frees memory
00715  */
00716 
00717 void pike_module_exit(void)
00718 {
00719   roxen_php_initialized = 0;
00720   roxen_sapi_module.shutdown(&roxen_sapi_module);
00721   if(php_program)  free_program(php_program);
00722 #ifdef ZTS
00723   tsrm_shutdown();
00724 #endif
00725   PHP_DESTROY();
00726 }
00727 #endif