Back to index

php5  5.3.10
caudium.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: caudium.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include "php.h"
00023 #ifdef HAVE_CAUDIUM
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 /* Pike Include Files 
00034  *
00035  * conflicts with pike avoided by only using long names. Requires a new
00036  * Pike 0.7 since it was implemented for this interface only.
00037  *
00038  */
00039 #define NO_PIKE_SHORTHAND
00040 
00041 /* Ok, we are now using Pike level threads to handle PHP5 since
00042  * the nice th_farm threads aren't working on Linux with glibc 2.2
00043  * (why this is I don't know).
00044  */
00045 #define USE_PIKE_LEVEL_THREADS
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 <array.h>
00053 #include <backend.h>
00054 #include <stralloc.h>
00055 #include <mapping.h>
00056 #include <object.h>
00057 #include <threads.h>
00058 #include <builtin_functions.h>
00059 #include <operators.h>
00060 #include <version.h>
00061 
00062 #if (PIKE_MAJOR_VERSION == 7 && PIKE_MINOR_VERSION == 1 && PIKE_BUILD_VERSION >= 12) || PIKE_MAJOR_VERSION > 7 || (PIKE_MAJOR_VERSION == 7 && PIKE_MINOR_VERSION > 1)
00063 # include "pike_error.h"
00064 #else
00065 # include "error.h"
00066 # ifndef Pike_error
00067 #  define Pike_error error
00068 # endif
00069 #endif
00070 
00071 /* Pike 7.x and newer */
00072 #define MY_MAPPING_LOOP(md, COUNT, KEY) \
00073   for(COUNT=0;COUNT < md->data->hashsize; COUNT++ ) \
00074        for(KEY=md->data->hash[COUNT];KEY;KEY=KEY->next)
00075 
00076 #ifndef ZTS
00077 /* Need thread safety */
00078 #error You need to compile PHP with threads.
00079 #endif
00080 
00081 #ifndef PIKE_THREADS
00082 #error The PHP5 module requires that your Pike has thread support.
00083 #endif
00084 
00085 #undef HIDE_GLOBAL_VARIABLES
00086 #undef REVEAL_GLOBAL_VARIABLES
00087 #define HIDE_GLOBAL_VARIABLES()
00088 #define REVEAL_GLOBAL_VARIABLES()
00089 
00090 /* php_caudium_request is per-request object storage */
00091 
00092 typedef struct
00093 {
00094   struct mapping *request_data;
00095   struct object *my_fd_obj;
00096   struct svalue done_cb;
00097   struct pike_string *filename;
00098   int my_fd;
00099   int written;
00100   TSRMLS_D;
00101 } php_caudium_request;
00102 
00103 
00104 void pike_module_init(void);
00105 void pike_module_exit(void);
00106 static void free_struct(TSRMLS_D);
00107 void f_php_caudium_request_handler(INT32 args);
00108 
00109 /* Defines to get to the data supplied when the script is started. */
00110 
00111 /* Per thread storage area id... */
00112 static int caudium_globals_id;
00113 
00114 #define GET_THIS() php_caudium_request *_request = ts_resource(caudium_globals_id)
00115 #define THIS _request
00116 #define PTHIS ((php_caudium_request *)(Pike_fp->current_storage))
00117 /* File descriptor integer. Used to write directly to the FD without 
00118  * passing Pike
00119  */
00120 #define MY_FD    (THIS->my_fd)
00121 
00122 /* FD object. Really a PHPScript object from Pike which implements a couple
00123  * of functions to handle headers, writing and buffering.
00124  */
00125 #define MY_FD_OBJ        ((struct object *)(THIS->my_fd_obj))
00126 
00127 /* Mapping with data supplied from the calling Caudium module. Contains
00128  * a mapping with headers, an FD object etc.
00129  */
00130 #define REQUEST_DATA ((struct mapping *)(THIS->request_data))
00131 
00132 extern int fd_from_object(struct object *o);
00133 static unsigned char caudium_php_initialized;
00134 
00135 #ifndef mt_lock_interpreter
00136 #define mt_lock_interpreter()     mt_lock(&interpreter_lock);
00137 #define mt_unlock_interpreter()   mt_unlock(&interpreter_lock);
00138 #endif
00139 
00140 
00141 /* This allows calling of pike functions from the PHP callbacks,
00142  * which requires the Pike interpreter to be locked.
00143  */
00144 #define THREAD_SAFE_RUN(COMMAND, what)  do {\
00145   struct thread_state *state;\
00146   if((state = thread_state_for_id(th_self()))!=NULL) {\
00147     if(!state->swapped) {\
00148       COMMAND;\
00149     } else {\
00150       mt_lock_interpreter();\
00151       SWAP_IN_THREAD(state);\
00152       COMMAND;\
00153       SWAP_OUT_THREAD(state);\
00154       mt_unlock_interpreter();\
00155     }\
00156   }\
00157 } while(0)
00158 
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 INLINE static struct svalue *lookup_header(char *headername)
00166 {
00167   struct svalue *headers, *value;
00168   struct pike_string *sind;
00169   GET_THIS();
00170   sind = make_shared_string("env");
00171   headers = low_mapping_string_lookup(REQUEST_DATA, sind);
00172   free_string(sind);
00173   if(!headers || headers->type != PIKE_T_MAPPING) return NULL;
00174   sind = make_shared_string(headername);
00175   value = low_mapping_string_lookup(headers->u.mapping, sind);
00176   free_string(sind);
00177   if(!value) return NULL;
00178   return value;
00179 }
00180 
00181 /* Lookup a header in the mapping and return the value as a string, or
00182  * return the default if it's missing
00183  */
00184 INLINE static char *lookup_string_header(char *headername, char *default_value)
00185 {
00186   struct svalue *head = NULL;
00187   THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
00188   if(!head || head->type != PIKE_T_STRING)
00189     return default_value;
00190   return head->u.string->str;
00191 }
00192 
00193 /* Lookup a header in the mapping and return the value as if it's an integer
00194  * and otherwise return the default.
00195  */
00196 INLINE static int lookup_integer_header(char *headername, int default_value)
00197 {
00198   struct svalue *head = NULL;
00199   THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
00200   if(!head || head->type != PIKE_T_INT)
00201     return default_value;
00202   return head->u.integer;
00203 }
00204 
00205 /*
00206  * php_caudium_low_ub_write() writes data to the client connection. Might be
00207  * rewritten to do more direct IO to save CPU and the need to lock the 
00208  * interpreter for better threading.
00209  */
00210 
00211 INLINE static int
00212 php_caudium_low_ub_write(const char *str, uint str_length TSRMLS_DC) {
00213   int sent_bytes = 0;
00214   struct pike_string *to_write = NULL;
00215   GET_THIS();
00216   if(!MY_FD_OBJ->prog) {
00217     PG(connection_status) = PHP_CONNECTION_ABORTED;
00218     zend_bailout();
00219     return -1;
00220   }
00221   to_write = make_shared_binary_string(str, str_length);
00222   push_string(to_write);
00223   safe_apply(MY_FD_OBJ, "write", 1);
00224   if(Pike_sp[-1].type == PIKE_T_INT)
00225     sent_bytes = Pike_sp[-1].u.integer;
00226   pop_stack();
00227   if(sent_bytes != str_length) {
00228     /* This means the connection is closed. Dead. Gone. *sniff*  */
00229     PG(connection_status) = PHP_CONNECTION_ABORTED;
00230     zend_bailout();
00231   }
00232   return sent_bytes;
00233 }
00234 
00235 /*
00236  * php_caudium_sapi_ub_write() calls php_caudium_low_ub_write in a Pike thread
00237  * safe manner or writes directly to the output FD if RXML post-parsing is
00238  * disabled. 
00239  */
00240 
00241 static int
00242 php_caudium_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
00243 {
00244   GET_THIS();
00245   int sent_bytes = 0, fd = MY_FD;
00246   if(fd)
00247   {
00248     for(sent_bytes=0;sent_bytes < str_length;)
00249     {
00250       int written;
00251       written = fd_write(fd, str + sent_bytes, str_length - sent_bytes);
00252       if(written < 0)
00253       {
00254        switch(errno)
00255        {
00256         default:
00257          /* This means the connection is closed. Dead. Gone. *sniff*  */
00258          PG(connection_status) = PHP_CONNECTION_ABORTED;
00259          zend_bailout();
00260          THIS->written += sent_bytes;
00261          return sent_bytes;
00262         case EINTR: 
00263         case EWOULDBLOCK:
00264          continue;
00265        }
00266       } else {
00267        sent_bytes += written;
00268       }
00269     }
00270     THIS->written += sent_bytes;
00271   } else {
00272     THREAD_SAFE_RUN(sent_bytes = php_caudium_low_ub_write(str, str_length TSRMLS_CC),
00273                   "write");
00274   }
00275   return sent_bytes;
00276 }
00277 
00278 /* php_caudium_set_header() sets a header in the header mapping. Called in a
00279  * thread safe manner from php_caudium_sapi_header_handler.
00280  */
00281 INLINE static void
00282 php_caudium_set_header(char *header_name, char *value, char *p)
00283 {
00284   struct svalue hsval;
00285   struct pike_string *hval, *ind, *hind;
00286   struct mapping *headermap;
00287   struct svalue *s_headermap, *soldval;
00288   int vallen;
00289   GET_THIS();
00290   /*  hval = make_shared_string(value); */
00291   ind = make_shared_string(" _headers");
00292   hind = make_shared_binary_string(header_name,
00293                                (int)(p - header_name));
00294 
00295   s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
00296   if(!s_headermap || s_headermap->type != PIKE_T_MAPPING)
00297   {
00298     struct svalue mappie;                                           
00299     mappie.type = PIKE_T_MAPPING;
00300     headermap = allocate_mapping(1);
00301     mappie.u.mapping = headermap;
00302     mapping_string_insert(REQUEST_DATA, ind, &mappie);
00303     free_mapping(headermap);
00304     hval = make_shared_string(value);
00305   } else {
00306     headermap = s_headermap->u.mapping;
00307     soldval = low_mapping_string_lookup(headermap, hind);
00308     vallen = strlen(value);
00309     if(soldval != NULL && 
00310        soldval->type == PIKE_T_STRING &&
00311        soldval->u.string->size_shift == 0) {
00312       /* Existing, valid header. Prepend.*/
00313       hval = begin_shared_string(soldval->u.string->len + 1 + vallen);
00314       MEMCPY(hval->str, soldval->u.string->str, soldval->u.string->len);
00315       STR0(hval)[soldval->u.string->len] = '\0';
00316       MEMCPY(hval->str+soldval->u.string->len+1, value, vallen);
00317       hval = end_shared_string(hval);
00318     } else { 
00319       hval = make_shared_string(value);
00320     }
00321   }
00322   hsval.type = PIKE_T_STRING;
00323   hsval.u.string = hval;
00324 
00325   mapping_string_insert(headermap, hind, &hsval);
00326 
00327   free_string(hval);
00328   free_string(ind);
00329   free_string(hind);
00330 }
00331 
00332 /*
00333  * php_caudium_sapi_header_handler() sets a HTTP reply header to be 
00334  * sent to the client.
00335  */
00336 static int
00337 php_caudium_sapi_header_handler(sapi_header_struct *sapi_header,
00338                            sapi_headers_struct *sapi_headers TSRMLS_DC)
00339 {
00340   char *header_name, *header_content, *p;
00341   header_name = sapi_header->header;
00342   header_content = p = strchr(header_name, ':');
00343   
00344   if(p) {
00345   do {
00346     header_content++;
00347   } while(*header_content == ' ');
00348     THREAD_SAFE_RUN(php_caudium_set_header(header_name, header_content, p), "header handler");
00349   }
00350   sapi_free_header(sapi_header);
00351   return 0;
00352 }
00353 
00354 /*
00355  * php_caudium_sapi_send_headers() flushes the headers to the client.
00356  * Called before real content is sent by PHP.
00357  */
00358 
00359 INLINE static int
00360 php_caudium_low_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00361 {
00362   struct pike_string *ind;
00363   struct svalue *s_headermap;
00364   GET_THIS();
00365   if(!MY_FD_OBJ->prog) {
00366     PG(connection_status) = PHP_CONNECTION_ABORTED;
00367     zend_bailout();
00368     return SAPI_HEADER_SEND_FAILED;
00369   }
00370   ind = make_shared_string(" _headers");  
00371   s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
00372   free_string(ind);
00373   
00374   push_int(SG(sapi_headers).http_response_code);
00375   if(s_headermap && s_headermap->type == PIKE_T_MAPPING)
00376     ref_push_mapping(s_headermap->u.mapping);
00377   else
00378     push_int(0);
00379   safe_apply(MY_FD_OBJ, "send_headers", 2);
00380   pop_stack();
00381   
00382   return SAPI_HEADER_SENT_SUCCESSFULLY;
00383 }
00384 
00385 static int
00386 php_caudium_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00387 {
00388   int res = 0;
00389   THREAD_SAFE_RUN(res = php_caudium_low_send_headers(sapi_headers TSRMLS_CC), "send headers");
00390   return res;
00391 }
00392 
00393 /*
00394  * php_caudium_sapi_read_post() reads a specified number of bytes from
00395  * the client. Used for POST/PUT requests.
00396  */
00397 
00398 INLINE static int php_caudium_low_read_post(char *buf, uint count_bytes)
00399 {
00400   uint total_read = 0;
00401   GET_THIS();
00402   TSRMLS_FETCH();
00403   
00404   if(!MY_FD_OBJ->prog)
00405   {
00406     PG(connection_status) = PHP_CONNECTION_ABORTED;
00407     zend_bailout();
00408     return -1;
00409   }
00410   push_int(count_bytes);
00411   safe_apply(MY_FD_OBJ, "read_post", 1);
00412   if(Pike_sp[-1].type == PIKE_T_STRING) {
00413     MEMCPY(buf, Pike_sp[-1].u.string->str,
00414            (total_read = Pike_sp[-1].u.string->len));
00415     buf[total_read] = '\0';
00416   } else
00417     total_read = 0;
00418   pop_stack();
00419   return total_read;
00420 }
00421 
00422 static int
00423 php_caudium_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC)
00424 {
00425   uint total_read = 0;
00426   THREAD_SAFE_RUN(total_read = php_caudium_low_read_post(buf, count_bytes), "read post");
00427   return total_read;
00428 }
00429 
00430 /* 
00431  * php_caudium_sapi_read_cookies() returns the Cookie header from
00432  * the HTTP request header
00433  */
00434        
00435 static char *
00436 php_caudium_sapi_read_cookies(TSRMLS_D)
00437 {
00438   char *cookies;
00439   cookies = lookup_string_header("HTTP_COOKIE", NULL);
00440   return cookies;
00441 }
00442 
00443 static void php_info_caudium(ZEND_MODULE_INFO_FUNC_ARGS)
00444 {
00445   /*  char buf[512]; */
00446   php_info_print_table_start();
00447   php_info_print_table_row(2, "SAPI module version", "$Id: caudium.c 321634 2012-01-01 13:15:04Z felipe $");
00448   /*  php_info_print_table_row(2, "Build date", Ns_InfoBuildDate());
00449       php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile());
00450       php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog());
00451       php_info_print_table_row(2, "Installation path", Ns_InfoHomePath());
00452       php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname());
00453       php_info_print_table_row(2, "Source code label", Ns_InfoLabel());
00454       php_info_print_table_row(2, "Server platform", Ns_InfoPlatform());
00455       snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion());
00456       php_info_print_table_row(2, "Server version", buf);
00457       snprintf(buf, 511, "%d day(s), %02d:%02d:%02d", 
00458       uptime / 86400,
00459       (uptime / 3600) % 24,
00460       (uptime / 60) % 60,
00461       uptime % 60);
00462       php_info_print_table_row(2, "Server uptime", buf);
00463   */
00464   php_info_print_table_end();
00465 }
00466 
00467 static zend_module_entry php_caudium_module = {
00468   STANDARD_MODULE_HEADER,
00469   "Caudium",
00470   NULL,
00471   NULL,
00472   NULL,
00473   NULL,
00474   NULL,
00475   php_info_caudium,
00476   NULL,
00477   STANDARD_MODULE_PROPERTIES
00478 };
00479 
00480 
00481 INLINE static void low_sapi_caudium_register_variables(zval *track_vars_array TSRMLS_DC)   
00482 {
00483   int i;
00484   struct keypair *k;
00485   struct svalue *headers;
00486   struct pike_string *sind;
00487   struct svalue *ind;
00488   struct svalue *val;
00489   GET_THIS();
00490   php_register_variable("PHP_SELF", SG(request_info).request_uri,
00491                      track_vars_array TSRMLS_CC);
00492   php_register_variable("GATEWAY_INTERFACE", "CGI/1.1",
00493                      track_vars_array TSRMLS_CC);
00494   php_register_variable("REQUEST_METHOD",
00495                      (char *) SG(request_info).request_method,
00496                      track_vars_array TSRMLS_CC);
00497   php_register_variable("REQUEST_URI", SG(request_info).request_uri,
00498                      track_vars_array TSRMLS_CC);
00499   php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated,
00500                      track_vars_array TSRMLS_CC);
00501 
00502   sind = make_shared_string("env");
00503   headers = low_mapping_string_lookup(REQUEST_DATA, sind);
00504   free_string(sind);
00505   if(headers && headers->type == PIKE_T_MAPPING) {
00506     MY_MAPPING_LOOP(headers->u.mapping, i, k) {
00507       ind = &k->ind;
00508       val = &k->val;
00509       if(ind && ind->type == PIKE_T_STRING &&
00510         val && val->type == PIKE_T_STRING) {
00511        php_register_variable(ind->u.string->str, val->u.string->str,
00512                            track_vars_array TSRMLS_CC );
00513       }
00514     }
00515   }
00516 }
00517 
00518 static void sapi_caudium_register_variables(zval *track_vars_array TSRMLS_DC)
00519 {
00520   THREAD_SAFE_RUN(low_sapi_caudium_register_variables(track_vars_array TSRMLS_CC), "register_variables");
00521 }
00522 
00523 
00524 static int php_caudium_startup(sapi_module_struct *sapi_module)
00525 {
00526        if (php_module_startup(sapi_module, &php_caudium_module, 1)==FAILURE) {
00527               return FAILURE;
00528        }
00529        return SUCCESS;
00530 }
00531 
00532 
00533 /* this structure is static (as in "it does not change") */
00534 static sapi_module_struct caudium_sapi_module = {
00535   "caudium",
00536   "Caudium",
00537   php_caudium_startup,                    /* startup */
00538   php_module_shutdown_wrapper,            /* shutdown */
00539   NULL,                                   /* activate */
00540   NULL,                                   /* deactivate */
00541   php_caudium_sapi_ub_write,              /* unbuffered write */
00542   NULL,                                   /* flush */
00543   NULL,                                   /* get uid */
00544   NULL,                                   /* getenv */
00545   php_error,                       /* error handler */
00546   php_caudium_sapi_header_handler, /* header handler */
00547   php_caudium_sapi_send_headers,   /* send headers handler */
00548   NULL,                                   /* send header handler */
00549   php_caudium_sapi_read_post,             /* read POST data */
00550   php_caudium_sapi_read_cookies,   /* read cookies */
00551   sapi_caudium_register_variables, /* register server variables */
00552   NULL,                                   /* Log message */
00553   NULL,                                   /* Get request time */
00554   NULL,                                   /* Child terminate */
00555 
00556   STANDARD_SAPI_MODULE_PROPERTIES
00557 };
00558 
00559 /*
00560  * php_caudium_module_main() is called by the per-request handler and
00561  * "executes" the script
00562  */
00563 
00564 static void php_caudium_module_main(php_caudium_request *ureq)
00565 {
00566   int res;
00567   zend_file_handle file_handle;
00568 #ifndef USE_PIKE_LEVEL_THREADS
00569   struct thread_state *state;
00570   extern struct program *thread_id_prog;
00571 #endif
00572   TSRMLS_FETCH();
00573   GET_THIS();
00574   THIS->filename = ureq->filename;
00575   THIS->done_cb = ureq->done_cb;
00576   THIS->my_fd_obj = ureq->my_fd_obj;
00577   THIS->my_fd = ureq->my_fd;
00578   THIS->request_data = ureq->request_data;
00579   free(ureq);
00580 
00581 #ifndef USE_PIKE_LEVEL_THREADS
00582   mt_lock_interpreter();
00583   init_interpreter();
00584 #if PIKE_MAJOR_VERSION == 7 && PIKE_MINOR_VERSION < 1
00585   thread_id = low_clone(thread_id_prog);
00586   state = OBJ2THREAD(thread_id);
00587   Pike_stack_top=((char *)&state)+ (thread_stack_size-16384) * STACK_DIRECTION;
00588   recoveries = NULL;
00589   call_c_initializers(thread_id);
00590   OBJ2THREAD(thread_id)->id=th_self();
00591   num_threads++;
00592   thread_table_insert(thread_id);
00593   state->status=THREAD_RUNNING;
00594 #else
00595   Pike_interpreter.thread_id = low_clone(thread_id_prog);
00596   state = OBJ2THREAD(Pike_interpreter.thread_id);
00597   Pike_interpreter.stack_top=((char *)&state)+ (thread_stack_size-16384) * STACK_DIRECTION;
00598   Pike_interpreter.recoveries = NULL;
00599   call_c_initializers(Pike_interpreter.thread_id);
00600   state->id=th_self();
00601   /*  SWAP_OUT_THREAD(OBJ2THREAD(Pike_interpreter.thread_id)); */
00602   num_threads++;
00603   thread_table_insert(Pike_interpreter.thread_id);
00604   state->status=THREAD_RUNNING;
00605 #endif
00606   state->swapped = 0;
00607 #endif 
00608   SG(request_info).query_string = lookup_string_header("QUERY_STRING", 0);
00609   SG(server_context) = (void *)1; /* avoid server_context == NULL */
00610 
00611   /* path_translated is apparently the absolute path to the file, not
00612      the translated PATH_INFO
00613   */
00614   SG(request_info).path_translated =
00615     lookup_string_header("SCRIPT_FILENAME", NULL);
00616   SG(request_info).request_uri = lookup_string_header("DOCUMENT_URI", NULL);
00617   if(!SG(request_info).request_uri)
00618     SG(request_info).request_uri = lookup_string_header("SCRIPT_NAME", NULL);
00619   SG(request_info).request_method = lookup_string_header("REQUEST_METHOD", "GET");
00620   SG(request_info).content_length = lookup_integer_header("HTTP_CONTENT_LENGTH", 0);
00621   SG(request_info).content_type = lookup_string_header("HTTP_CONTENT_TYPE", NULL);
00622   SG(sapi_headers).http_response_code = 200;
00623   if (!strcmp(SG(request_info).request_method, "HEAD")) {
00624     SG(request_info).headers_only = 1;
00625   } else {
00626     SG(request_info).headers_only = 0;
00627   }
00628 
00629   /* Let PHP5 handle the deconding of the AUTH */
00630   php_handle_auth_data(lookup_string_header("HTTP_AUTHORIZATION", NULL), TSRMLS_C);
00631    /* Swap out this thread and release the interpreter lock to allow
00632    * Pike threads to run. We wait since the above would otherwise require
00633    * a lot of unlock/lock.
00634    */
00635 #ifndef USE_PIKE_LEVEL_THREADS
00636   SWAP_OUT_THREAD(state);
00637   mt_unlock_interpreter();
00638 #else
00639   THREADS_ALLOW();
00640 #endif
00641 
00642   file_handle.type = ZEND_HANDLE_FILENAME;
00643   file_handle.filename = THIS->filename->str;
00644   file_handle.opened_path = NULL;
00645   file_handle.free_filename = 0;
00646 
00647   THIS->written = 0;
00648   res = php_request_startup(TSRMLS_C);
00649 
00650   if(res == FAILURE) {
00651     THREAD_SAFE_RUN({
00652       apply_svalue(&THIS->done_cb, 0);
00653       pop_stack();
00654       free_struct(TSRMLS_C);
00655     }, "Negative run response");
00656   } else {
00657     php_execute_script(&file_handle TSRMLS_CC);
00658     php_request_shutdown(NULL);
00659     THREAD_SAFE_RUN({
00660       push_int(THIS->written);
00661       apply_svalue(&THIS->done_cb, 1);
00662       pop_stack();
00663       free_struct(TSRMLS_C);
00664     }, "positive run response");
00665   }
00666 
00667 #ifndef USE_PIKE_LEVEL_THREADS
00668   mt_lock_interpreter();
00669   SWAP_IN_THREAD(state);
00670 #if PIKE_MAJOR_VERSION == 7 && PIKE_MINOR_VERSION < 1
00671   state->status=THREAD_EXITED;
00672   co_signal(& state->status_change);
00673   thread_table_delete(thread_id);
00674   free_object(thread_id);
00675   thread_id=NULL;
00676 #else
00677   state->status=THREAD_EXITED;
00678   co_signal(& state->status_change);
00679   thread_table_delete(Pike_interpreter.thread_id);
00680   free_object(Pike_interpreter.thread_id);
00681   Pike_interpreter.thread_id=NULL;
00682 #endif
00683   cleanup_interpret();
00684   num_threads--;
00685   mt_unlock_interpreter();
00686 #else
00687   THREADS_DISALLOW();
00688 #endif
00689 }
00690 
00691 /*
00692  * The php_caudium_request_handler() is called per request and handles
00693  * everything for one request.
00694  */
00695 
00696 void f_php_caudium_request_handler(INT32 args)
00697 {
00698   struct object *my_fd_obj;
00699   struct mapping *request_data;
00700   struct svalue *done_callback;
00701   struct pike_string *script;
00702   struct svalue *raw_fd;
00703   struct pike_string *ind;
00704   php_caudium_request *_request;
00705   THIS = malloc(sizeof(php_caudium_request));
00706   if(THIS == NULL)
00707     Pike_error("Out of memory.");
00708 
00709   get_all_args("PHP5.Interpreter->run", args, "%S%m%O%*", &script,
00710               &request_data, &my_fd_obj, &done_callback);
00711   if(done_callback->type != PIKE_T_FUNCTION) 
00712     Pike_error("PHP5.Interpreter->run: Bad argument 4, expected function.\n");
00713   add_ref(request_data);
00714   add_ref(my_fd_obj);
00715   add_ref(script);
00716 
00717   THIS->request_data = request_data;
00718   THIS->my_fd_obj = my_fd_obj;
00719   THIS->filename = script;
00720   assign_svalue_no_free(&THIS->done_cb, done_callback);
00721 
00722   ind = make_shared_binary_string("my_fd", 5);
00723   raw_fd = low_mapping_string_lookup(THIS->request_data, ind);
00724   if(raw_fd && raw_fd->type == PIKE_T_OBJECT)
00725   {
00726     int fd = fd_from_object(raw_fd->u.object);
00727     if(fd == -1)
00728       THIS->my_fd = 0; /* Don't send directly to this FD... */
00729     else
00730       THIS->my_fd = fd;
00731   } else
00732     THIS->my_fd = 0;
00733 #ifdef USE_PIKE_LEVEL_THREADS
00734   php_caudium_module_main(THIS);
00735 #else
00736   th_farm((void (*)(void *))php_caudium_module_main, THIS);
00737 #endif
00738   pop_n_elems(args);
00739 }
00740 
00741 static void free_struct(TSRMLS_D)
00742 {
00743   GET_THIS();
00744   if(THIS->request_data) free_mapping(THIS->request_data);
00745   if(THIS->my_fd_obj)    free_object(THIS->my_fd_obj);
00746   free_svalue(&THIS->done_cb);
00747   if(THIS->filename)     free_string(THIS->filename);
00748   MEMSET(THIS, 0, sizeof(php_caudium_request));
00749 }
00750 
00751 
00752 /*
00753  * pike_module_init() is called by Pike once at startup
00754  *
00755  * This functions allocates basic structures
00756  */
00757 
00758 void pike_module_init( void )
00759 {
00760   if (!caudium_php_initialized) {
00761     caudium_php_initialized = 1;
00762     tsrm_startup(1, 1, 0, NULL);
00763     ts_allocate_id(&caudium_globals_id, sizeof(php_caudium_request), NULL, NULL);
00764     sapi_startup(&caudium_sapi_module);
00765     sapi_module.startup(&caudium_sapi_module);
00766   }
00767   start_new_program(); /* Text */
00768   pike_add_function("run", f_php_caudium_request_handler,
00769                   "function(string, mapping, object, function:void)", 0);
00770   end_class("Interpreter", 0);
00771 }
00772 
00773 /*
00774  * pike_module_exit() performs the last steps before the
00775  * server exists. Shutdowns basic services and frees memory
00776  */
00777 
00778 void pike_module_exit(void)
00779 {
00780   caudium_php_initialized = 0;
00781   sapi_module.shutdown(&caudium_sapi_module);
00782   tsrm_shutdown();
00783 }
00784 #endif