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