xref: /PHP-5.4/sapi/caudium/caudium.c (revision c0d060f5)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2014 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_CAUDIUM
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 /* Pike Include Files
34  *
35  * conflicts with pike avoided by only using long names. Requires a new
36  * Pike 0.7 since it was implemented for this interface only.
37  *
38  */
39 #define NO_PIKE_SHORTHAND
40 
41 /* Ok, we are now using Pike level threads to handle PHP5 since
42  * the nice th_farm threads aren't working on Linux with glibc 2.2
43  * (why this is I don't know).
44  */
45 #define USE_PIKE_LEVEL_THREADS
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 <array.h>
53 #include <backend.h>
54 #include <stralloc.h>
55 #include <mapping.h>
56 #include <object.h>
57 #include <threads.h>
58 #include <builtin_functions.h>
59 #include <operators.h>
60 #include <version.h>
61 
62 #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)
63 # include "pike_error.h"
64 #else
65 # include "error.h"
66 # ifndef Pike_error
67 #  define Pike_error error
68 # endif
69 #endif
70 
71 /* Pike 7.x and newer */
72 #define MY_MAPPING_LOOP(md, COUNT, KEY) \
73   for(COUNT=0;COUNT < md->data->hashsize; COUNT++ ) \
74 	for(KEY=md->data->hash[COUNT];KEY;KEY=KEY->next)
75 
76 #ifndef ZTS
77 /* Need thread safety */
78 #error You need to compile PHP with threads.
79 #endif
80 
81 #ifndef PIKE_THREADS
82 #error The PHP5 module requires that your Pike has thread support.
83 #endif
84 
85 #undef HIDE_GLOBAL_VARIABLES
86 #undef REVEAL_GLOBAL_VARIABLES
87 #define HIDE_GLOBAL_VARIABLES()
88 #define REVEAL_GLOBAL_VARIABLES()
89 
90 /* php_caudium_request is per-request object storage */
91 
92 typedef struct
93 {
94   struct mapping *request_data;
95   struct object *my_fd_obj;
96   struct svalue done_cb;
97   struct pike_string *filename;
98   int my_fd;
99   int written;
100   TSRMLS_D;
101 } php_caudium_request;
102 
103 
104 void pike_module_init(void);
105 void pike_module_exit(void);
106 static void free_struct(TSRMLS_D);
107 void f_php_caudium_request_handler(INT32 args);
108 
109 /* Defines to get to the data supplied when the script is started. */
110 
111 /* Per thread storage area id... */
112 static int caudium_globals_id;
113 
114 #define GET_THIS() php_caudium_request *_request = ts_resource(caudium_globals_id)
115 #define THIS _request
116 #define PTHIS ((php_caudium_request *)(Pike_fp->current_storage))
117 /* File descriptor integer. Used to write directly to the FD without
118  * passing Pike
119  */
120 #define MY_FD    (THIS->my_fd)
121 
122 /* FD object. Really a PHPScript object from Pike which implements a couple
123  * of functions to handle headers, writing and buffering.
124  */
125 #define MY_FD_OBJ        ((struct object *)(THIS->my_fd_obj))
126 
127 /* Mapping with data supplied from the calling Caudium module. Contains
128  * a mapping with headers, an FD object etc.
129  */
130 #define REQUEST_DATA ((struct mapping *)(THIS->request_data))
131 
132 extern int fd_from_object(struct object *o);
133 static unsigned char caudium_php_initialized;
134 
135 #ifndef mt_lock_interpreter
136 #define mt_lock_interpreter()     mt_lock(&interpreter_lock);
137 #define mt_unlock_interpreter()   mt_unlock(&interpreter_lock);
138 #endif
139 
140 
141 /* This allows calling of pike functions from the PHP callbacks,
142  * which requires the Pike interpreter to be locked.
143  */
144 #define THREAD_SAFE_RUN(COMMAND, what)  do {\
145   struct thread_state *state;\
146   if((state = thread_state_for_id(th_self()))!=NULL) {\
147     if(!state->swapped) {\
148       COMMAND;\
149     } else {\
150       mt_lock_interpreter();\
151       SWAP_IN_THREAD(state);\
152       COMMAND;\
153       SWAP_OUT_THREAD(state);\
154       mt_unlock_interpreter();\
155     }\
156   }\
157 } while(0)
158 
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 INLINE static struct svalue *lookup_header(char *headername)
166 {
167   struct svalue *headers, *value;
168   struct pike_string *sind;
169   GET_THIS();
170   sind = make_shared_string("env");
171   headers = low_mapping_string_lookup(REQUEST_DATA, sind);
172   free_string(sind);
173   if(!headers || headers->type != PIKE_T_MAPPING) return NULL;
174   sind = make_shared_string(headername);
175   value = low_mapping_string_lookup(headers->u.mapping, sind);
176   free_string(sind);
177   if(!value) return NULL;
178   return value;
179 }
180 
181 /* Lookup a header in the mapping and return the value as a string, or
182  * return the default if it's missing
183  */
lookup_string_header(char * headername,char * default_value)184 INLINE static char *lookup_string_header(char *headername, char *default_value)
185 {
186   struct svalue *head = NULL;
187   THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
188   if(!head || head->type != PIKE_T_STRING)
189     return default_value;
190   return head->u.string->str;
191 }
192 
193 /* Lookup a header in the mapping and return the value as if it's an integer
194  * and otherwise return the default.
195  */
lookup_integer_header(char * headername,int default_value)196 INLINE static int lookup_integer_header(char *headername, int default_value)
197 {
198   struct svalue *head = NULL;
199   THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
200   if(!head || head->type != PIKE_T_INT)
201     return default_value;
202   return head->u.integer;
203 }
204 
205 /*
206  * php_caudium_low_ub_write() writes data to the client connection. Might be
207  * rewritten to do more direct IO to save CPU and the need to lock the
208  * interpreter for better threading.
209  */
210 
211 INLINE static int
php_caudium_low_ub_write(const char * str,uint str_length TSRMLS_DC)212 php_caudium_low_ub_write(const char *str, uint str_length TSRMLS_DC) {
213   int sent_bytes = 0;
214   struct pike_string *to_write = NULL;
215   GET_THIS();
216   if(!MY_FD_OBJ->prog) {
217     PG(connection_status) = PHP_CONNECTION_ABORTED;
218     zend_bailout();
219     return -1;
220   }
221   to_write = make_shared_binary_string(str, str_length);
222   push_string(to_write);
223   safe_apply(MY_FD_OBJ, "write", 1);
224   if(Pike_sp[-1].type == PIKE_T_INT)
225     sent_bytes = Pike_sp[-1].u.integer;
226   pop_stack();
227   if(sent_bytes != str_length) {
228     /* This means the connection is closed. Dead. Gone. *sniff*  */
229     PG(connection_status) = PHP_CONNECTION_ABORTED;
230     zend_bailout();
231   }
232   return sent_bytes;
233 }
234 
235 /*
236  * php_caudium_sapi_ub_write() calls php_caudium_low_ub_write in a Pike thread
237  * safe manner or writes directly to the output FD if RXML post-parsing is
238  * disabled.
239  */
240 
241 static int
php_caudium_sapi_ub_write(const char * str,uint str_length TSRMLS_DC)242 php_caudium_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
243 {
244   GET_THIS();
245   int sent_bytes = 0, fd = MY_FD;
246   if(fd)
247   {
248     for(sent_bytes=0;sent_bytes < str_length;)
249     {
250       int written;
251       written = fd_write(fd, str + sent_bytes, str_length - sent_bytes);
252       if(written < 0)
253       {
254 	switch(errno)
255 	{
256 	 default:
257 	  /* This means the connection is closed. Dead. Gone. *sniff*  */
258 	  PG(connection_status) = PHP_CONNECTION_ABORTED;
259 	  zend_bailout();
260 	  THIS->written += sent_bytes;
261 	  return sent_bytes;
262 	 case EINTR:
263 	 case EWOULDBLOCK:
264 	  continue;
265 	}
266       } else {
267 	sent_bytes += written;
268       }
269     }
270     THIS->written += sent_bytes;
271   } else {
272     THREAD_SAFE_RUN(sent_bytes = php_caudium_low_ub_write(str, str_length TSRMLS_CC),
273 		    "write");
274   }
275   return sent_bytes;
276 }
277 
278 /* php_caudium_set_header() sets a header in the header mapping. Called in a
279  * thread safe manner from php_caudium_sapi_header_handler.
280  */
281 INLINE static void
php_caudium_set_header(char * header_name,char * value,char * p)282 php_caudium_set_header(char *header_name, char *value, char *p)
283 {
284   struct svalue hsval;
285   struct pike_string *hval, *ind, *hind;
286   struct mapping *headermap;
287   struct svalue *s_headermap, *soldval;
288   int vallen;
289   GET_THIS();
290   /*  hval = make_shared_string(value); */
291   ind = make_shared_string(" _headers");
292   hind = make_shared_binary_string(header_name,
293 				   (int)(p - header_name));
294 
295   s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
296   if(!s_headermap || s_headermap->type != PIKE_T_MAPPING)
297   {
298     struct svalue mappie;
299     mappie.type = PIKE_T_MAPPING;
300     headermap = allocate_mapping(1);
301     mappie.u.mapping = headermap;
302     mapping_string_insert(REQUEST_DATA, ind, &mappie);
303     free_mapping(headermap);
304     hval = make_shared_string(value);
305   } else {
306     headermap = s_headermap->u.mapping;
307     soldval = low_mapping_string_lookup(headermap, hind);
308     vallen = strlen(value);
309     if(soldval != NULL &&
310        soldval->type == PIKE_T_STRING &&
311        soldval->u.string->size_shift == 0) {
312       /* Existing, valid header. Prepend.*/
313       hval = begin_shared_string(soldval->u.string->len + 1 + vallen);
314       MEMCPY(hval->str, soldval->u.string->str, soldval->u.string->len);
315       STR0(hval)[soldval->u.string->len] = '\0';
316       MEMCPY(hval->str+soldval->u.string->len+1, value, vallen);
317       hval = end_shared_string(hval);
318     } else {
319       hval = make_shared_string(value);
320     }
321   }
322   hsval.type = PIKE_T_STRING;
323   hsval.u.string = hval;
324 
325   mapping_string_insert(headermap, hind, &hsval);
326 
327   free_string(hval);
328   free_string(ind);
329   free_string(hind);
330 }
331 
332 /*
333  * php_caudium_sapi_header_handler() sets a HTTP reply header to be
334  * sent to the client.
335  */
336 static int
php_caudium_sapi_header_handler(sapi_header_struct * sapi_header,sapi_headers_struct * sapi_headers TSRMLS_DC)337 php_caudium_sapi_header_handler(sapi_header_struct *sapi_header,
338 			      sapi_headers_struct *sapi_headers TSRMLS_DC)
339 {
340   char *header_name, *header_content, *p;
341   header_name = sapi_header->header;
342   header_content = p = strchr(header_name, ':');
343 
344   if(p) {
345   do {
346     header_content++;
347   } while(*header_content == ' ');
348     THREAD_SAFE_RUN(php_caudium_set_header(header_name, header_content, p), "header handler");
349   }
350   sapi_free_header(sapi_header);
351   return 0;
352 }
353 
354 /*
355  * php_caudium_sapi_send_headers() flushes the headers to the client.
356  * Called before real content is sent by PHP.
357  */
358 
359 INLINE static int
php_caudium_low_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC)360 php_caudium_low_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
361 {
362   struct pike_string *ind;
363   struct svalue *s_headermap;
364   GET_THIS();
365   if(!MY_FD_OBJ->prog) {
366     PG(connection_status) = PHP_CONNECTION_ABORTED;
367     zend_bailout();
368     return SAPI_HEADER_SEND_FAILED;
369   }
370   ind = make_shared_string(" _headers");
371   s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
372   free_string(ind);
373 
374   push_int(SG(sapi_headers).http_response_code);
375   if(s_headermap && s_headermap->type == PIKE_T_MAPPING)
376     ref_push_mapping(s_headermap->u.mapping);
377   else
378     push_int(0);
379   safe_apply(MY_FD_OBJ, "send_headers", 2);
380   pop_stack();
381 
382   return SAPI_HEADER_SENT_SUCCESSFULLY;
383 }
384 
385 static int
php_caudium_sapi_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC)386 php_caudium_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
387 {
388   int res = 0;
389   THREAD_SAFE_RUN(res = php_caudium_low_send_headers(sapi_headers TSRMLS_CC), "send headers");
390   return res;
391 }
392 
393 /*
394  * php_caudium_sapi_read_post() reads a specified number of bytes from
395  * the client. Used for POST/PUT requests.
396  */
397 
php_caudium_low_read_post(char * buf,uint count_bytes)398 INLINE static int php_caudium_low_read_post(char *buf, uint count_bytes)
399 {
400   uint total_read = 0;
401   GET_THIS();
402   TSRMLS_FETCH();
403 
404   if(!MY_FD_OBJ->prog)
405   {
406     PG(connection_status) = PHP_CONNECTION_ABORTED;
407     zend_bailout();
408     return -1;
409   }
410   push_int(count_bytes);
411   safe_apply(MY_FD_OBJ, "read_post", 1);
412   if(Pike_sp[-1].type == PIKE_T_STRING) {
413     MEMCPY(buf, Pike_sp[-1].u.string->str,
414            (total_read = Pike_sp[-1].u.string->len));
415     buf[total_read] = '\0';
416   } else
417     total_read = 0;
418   pop_stack();
419   return total_read;
420 }
421 
422 static int
php_caudium_sapi_read_post(char * buf,uint count_bytes TSRMLS_DC)423 php_caudium_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC)
424 {
425   uint total_read = 0;
426   THREAD_SAFE_RUN(total_read = php_caudium_low_read_post(buf, count_bytes), "read post");
427   return total_read;
428 }
429 
430 /*
431  * php_caudium_sapi_read_cookies() returns the Cookie header from
432  * the HTTP request header
433  */
434 
435 static char *
php_caudium_sapi_read_cookies(TSRMLS_D)436 php_caudium_sapi_read_cookies(TSRMLS_D)
437 {
438   char *cookies;
439   cookies = lookup_string_header("HTTP_COOKIE", NULL);
440   return cookies;
441 }
442 
php_info_caudium(ZEND_MODULE_INFO_FUNC_ARGS)443 static void php_info_caudium(ZEND_MODULE_INFO_FUNC_ARGS)
444 {
445   /*  char buf[512]; */
446   php_info_print_table_start();
447   php_info_print_table_row(2, "SAPI module version", "$Id$");
448   /*  php_info_print_table_row(2, "Build date", Ns_InfoBuildDate());
449       php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile());
450       php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog());
451       php_info_print_table_row(2, "Installation path", Ns_InfoHomePath());
452       php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname());
453       php_info_print_table_row(2, "Source code label", Ns_InfoLabel());
454       php_info_print_table_row(2, "Server platform", Ns_InfoPlatform());
455       snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion());
456       php_info_print_table_row(2, "Server version", buf);
457       snprintf(buf, 511, "%d day(s), %02d:%02d:%02d",
458       uptime / 86400,
459       (uptime / 3600) % 24,
460       (uptime / 60) % 60,
461       uptime % 60);
462       php_info_print_table_row(2, "Server uptime", buf);
463   */
464   php_info_print_table_end();
465 }
466 
467 static zend_module_entry php_caudium_module = {
468   STANDARD_MODULE_HEADER,
469   "Caudium",
470   NULL,
471   NULL,
472   NULL,
473   NULL,
474   NULL,
475   php_info_caudium,
476   NULL,
477   STANDARD_MODULE_PROPERTIES
478 };
479 
480 
low_sapi_caudium_register_variables(zval * track_vars_array TSRMLS_DC)481 INLINE static void low_sapi_caudium_register_variables(zval *track_vars_array TSRMLS_DC)
482 {
483   int i;
484   struct keypair *k;
485   struct svalue *headers;
486   struct pike_string *sind;
487   struct svalue *ind;
488   struct svalue *val;
489   GET_THIS();
490   php_register_variable("PHP_SELF", SG(request_info).request_uri,
491 			track_vars_array TSRMLS_CC);
492   php_register_variable("GATEWAY_INTERFACE", "CGI/1.1",
493 			track_vars_array TSRMLS_CC);
494   php_register_variable("REQUEST_METHOD",
495 			(char *) SG(request_info).request_method,
496 			track_vars_array TSRMLS_CC);
497   php_register_variable("REQUEST_URI", SG(request_info).request_uri,
498 			track_vars_array TSRMLS_CC);
499   php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated,
500 			track_vars_array TSRMLS_CC);
501 
502   sind = make_shared_string("env");
503   headers = low_mapping_string_lookup(REQUEST_DATA, sind);
504   free_string(sind);
505   if(headers && headers->type == PIKE_T_MAPPING) {
506     MY_MAPPING_LOOP(headers->u.mapping, i, k) {
507       ind = &k->ind;
508       val = &k->val;
509       if(ind && ind->type == PIKE_T_STRING &&
510 	 val && val->type == PIKE_T_STRING) {
511 	php_register_variable(ind->u.string->str, val->u.string->str,
512 			      track_vars_array TSRMLS_CC );
513       }
514     }
515   }
516 }
517 
sapi_caudium_register_variables(zval * track_vars_array TSRMLS_DC)518 static void sapi_caudium_register_variables(zval *track_vars_array TSRMLS_DC)
519 {
520   THREAD_SAFE_RUN(low_sapi_caudium_register_variables(track_vars_array TSRMLS_CC), "register_variables");
521 }
522 
523 
php_caudium_startup(sapi_module_struct * sapi_module)524 static int php_caudium_startup(sapi_module_struct *sapi_module)
525 {
526 	if (php_module_startup(sapi_module, &php_caudium_module, 1)==FAILURE) {
527 		return FAILURE;
528 	}
529 	return SUCCESS;
530 }
531 
532 
533 /* this structure is static (as in "it does not change") */
534 static sapi_module_struct caudium_sapi_module = {
535   "caudium",
536   "Caudium",
537   php_caudium_startup,			/* startup */
538   php_module_shutdown_wrapper,		/* shutdown */
539   NULL,					/* activate */
540   NULL,					/* deactivate */
541   php_caudium_sapi_ub_write,		/* unbuffered write */
542   NULL,					/* flush */
543   NULL,					/* get uid */
544   NULL,					/* getenv */
545   php_error,				/* error handler */
546   php_caudium_sapi_header_handler,	/* header handler */
547   php_caudium_sapi_send_headers,	/* send headers handler */
548   NULL,					/* send header handler */
549   php_caudium_sapi_read_post,		/* read POST data */
550   php_caudium_sapi_read_cookies,	/* read cookies */
551   sapi_caudium_register_variables,	/* register server variables */
552   NULL,					/* Log message */
553   NULL,					/* Get request time */
554   NULL,					/* Child terminate */
555 
556   STANDARD_SAPI_MODULE_PROPERTIES
557 };
558 
559 /*
560  * php_caudium_module_main() is called by the per-request handler and
561  * "executes" the script
562  */
563 
php_caudium_module_main(php_caudium_request * ureq)564 static void php_caudium_module_main(php_caudium_request *ureq)
565 {
566   int res;
567   zend_file_handle file_handle;
568 #ifndef USE_PIKE_LEVEL_THREADS
569   struct thread_state *state;
570   extern struct program *thread_id_prog;
571 #endif
572   TSRMLS_FETCH();
573   GET_THIS();
574   THIS->filename = ureq->filename;
575   THIS->done_cb = ureq->done_cb;
576   THIS->my_fd_obj = ureq->my_fd_obj;
577   THIS->my_fd = ureq->my_fd;
578   THIS->request_data = ureq->request_data;
579   free(ureq);
580 
581 #ifndef USE_PIKE_LEVEL_THREADS
582   mt_lock_interpreter();
583   init_interpreter();
584 #if PIKE_MAJOR_VERSION == 7 && PIKE_MINOR_VERSION < 1
585   thread_id = low_clone(thread_id_prog);
586   state = OBJ2THREAD(thread_id);
587   Pike_stack_top=((char *)&state)+ (thread_stack_size-16384) * STACK_DIRECTION;
588   recoveries = NULL;
589   call_c_initializers(thread_id);
590   OBJ2THREAD(thread_id)->id=th_self();
591   num_threads++;
592   thread_table_insert(thread_id);
593   state->status=THREAD_RUNNING;
594 #else
595   Pike_interpreter.thread_id = low_clone(thread_id_prog);
596   state = OBJ2THREAD(Pike_interpreter.thread_id);
597   Pike_interpreter.stack_top=((char *)&state)+ (thread_stack_size-16384) * STACK_DIRECTION;
598   Pike_interpreter.recoveries = NULL;
599   call_c_initializers(Pike_interpreter.thread_id);
600   state->id=th_self();
601   /*  SWAP_OUT_THREAD(OBJ2THREAD(Pike_interpreter.thread_id)); */
602   num_threads++;
603   thread_table_insert(Pike_interpreter.thread_id);
604   state->status=THREAD_RUNNING;
605 #endif
606   state->swapped = 0;
607 #endif
608   SG(request_info).query_string = lookup_string_header("QUERY_STRING", 0);
609   SG(server_context) = (void *)1; /* avoid server_context == NULL */
610 
611   /* path_translated is apparently the absolute path to the file, not
612      the translated PATH_INFO
613   */
614   SG(request_info).path_translated =
615     lookup_string_header("SCRIPT_FILENAME", NULL);
616   SG(request_info).request_uri = lookup_string_header("DOCUMENT_URI", NULL);
617   if(!SG(request_info).request_uri)
618     SG(request_info).request_uri = lookup_string_header("SCRIPT_NAME", NULL);
619   SG(request_info).request_method = lookup_string_header("REQUEST_METHOD", "GET");
620   SG(request_info).content_length = lookup_integer_header("HTTP_CONTENT_LENGTH", 0);
621   SG(request_info).content_type = lookup_string_header("HTTP_CONTENT_TYPE", NULL);
622   SG(sapi_headers).http_response_code = 200;
623   if (!strcmp(SG(request_info).request_method, "HEAD")) {
624     SG(request_info).headers_only = 1;
625   } else {
626     SG(request_info).headers_only = 0;
627   }
628 
629   /* Let PHP5 handle the deconding of the AUTH */
630   php_handle_auth_data(lookup_string_header("HTTP_AUTHORIZATION", NULL), TSRMLS_C);
631    /* Swap out this thread and release the interpreter lock to allow
632    * Pike threads to run. We wait since the above would otherwise require
633    * a lot of unlock/lock.
634    */
635 #ifndef USE_PIKE_LEVEL_THREADS
636   SWAP_OUT_THREAD(state);
637   mt_unlock_interpreter();
638 #else
639   THREADS_ALLOW();
640 #endif
641 
642   file_handle.type = ZEND_HANDLE_FILENAME;
643   file_handle.filename = THIS->filename->str;
644   file_handle.opened_path = NULL;
645   file_handle.free_filename = 0;
646 
647   THIS->written = 0;
648   res = php_request_startup(TSRMLS_C);
649 
650   if(res == FAILURE) {
651     THREAD_SAFE_RUN({
652       apply_svalue(&THIS->done_cb, 0);
653       pop_stack();
654       free_struct(TSRMLS_C);
655     }, "Negative run response");
656   } else {
657     php_execute_script(&file_handle TSRMLS_CC);
658     php_request_shutdown(NULL);
659     THREAD_SAFE_RUN({
660       push_int(THIS->written);
661       apply_svalue(&THIS->done_cb, 1);
662       pop_stack();
663       free_struct(TSRMLS_C);
664     }, "positive run response");
665   }
666 
667 #ifndef USE_PIKE_LEVEL_THREADS
668   mt_lock_interpreter();
669   SWAP_IN_THREAD(state);
670 #if PIKE_MAJOR_VERSION == 7 && PIKE_MINOR_VERSION < 1
671   state->status=THREAD_EXITED;
672   co_signal(& state->status_change);
673   thread_table_delete(thread_id);
674   free_object(thread_id);
675   thread_id=NULL;
676 #else
677   state->status=THREAD_EXITED;
678   co_signal(& state->status_change);
679   thread_table_delete(Pike_interpreter.thread_id);
680   free_object(Pike_interpreter.thread_id);
681   Pike_interpreter.thread_id=NULL;
682 #endif
683   cleanup_interpret();
684   num_threads--;
685   mt_unlock_interpreter();
686 #else
687   THREADS_DISALLOW();
688 #endif
689 }
690 
691 /*
692  * The php_caudium_request_handler() is called per request and handles
693  * everything for one request.
694  */
695 
f_php_caudium_request_handler(INT32 args)696 void f_php_caudium_request_handler(INT32 args)
697 {
698   struct object *my_fd_obj;
699   struct mapping *request_data;
700   struct svalue *done_callback;
701   struct pike_string *script;
702   struct svalue *raw_fd;
703   struct pike_string *ind;
704   php_caudium_request *_request;
705   THIS = malloc(sizeof(php_caudium_request));
706   if(THIS == NULL)
707     Pike_error("Out of memory.");
708 
709   get_all_args("PHP5.Interpreter->run", args, "%S%m%O%*", &script,
710 	       &request_data, &my_fd_obj, &done_callback);
711   if(done_callback->type != PIKE_T_FUNCTION)
712     Pike_error("PHP5.Interpreter->run: Bad argument 4, expected function.\n");
713   add_ref(request_data);
714   add_ref(my_fd_obj);
715   add_ref(script);
716 
717   THIS->request_data = request_data;
718   THIS->my_fd_obj = my_fd_obj;
719   THIS->filename = script;
720   assign_svalue_no_free(&THIS->done_cb, done_callback);
721 
722   ind = make_shared_binary_string("my_fd", 5);
723   raw_fd = low_mapping_string_lookup(THIS->request_data, ind);
724   if(raw_fd && raw_fd->type == PIKE_T_OBJECT)
725   {
726     int fd = fd_from_object(raw_fd->u.object);
727     if(fd == -1)
728       THIS->my_fd = 0; /* Don't send directly to this FD... */
729     else
730       THIS->my_fd = fd;
731   } else
732     THIS->my_fd = 0;
733 #ifdef USE_PIKE_LEVEL_THREADS
734   php_caudium_module_main(THIS);
735 #else
736   th_farm((void (*)(void *))php_caudium_module_main, THIS);
737 #endif
738   pop_n_elems(args);
739 }
740 
free_struct(TSRMLS_D)741 static void free_struct(TSRMLS_D)
742 {
743   GET_THIS();
744   if(THIS->request_data) free_mapping(THIS->request_data);
745   if(THIS->my_fd_obj)    free_object(THIS->my_fd_obj);
746   free_svalue(&THIS->done_cb);
747   if(THIS->filename)     free_string(THIS->filename);
748   MEMSET(THIS, 0, sizeof(php_caudium_request));
749 }
750 
751 
752 /*
753  * pike_module_init() is called by Pike once at startup
754  *
755  * This functions allocates basic structures
756  */
757 
pike_module_init(void)758 void pike_module_init( void )
759 {
760   if (!caudium_php_initialized) {
761     caudium_php_initialized = 1;
762     tsrm_startup(1, 1, 0, NULL);
763     ts_allocate_id(&caudium_globals_id, sizeof(php_caudium_request), NULL, NULL);
764     sapi_startup(&caudium_sapi_module);
765     sapi_module.startup(&caudium_sapi_module);
766   }
767   start_new_program(); /* Text */
768   pike_add_function("run", f_php_caudium_request_handler,
769 		    "function(string, mapping, object, function:void)", 0);
770   end_class("Interpreter", 0);
771 }
772 
773 /*
774  * pike_module_exit() performs the last steps before the
775  * server exists. Shutdowns basic services and frees memory
776  */
777 
pike_module_exit(void)778 void pike_module_exit(void)
779 {
780   caudium_php_initialized = 0;
781   sapi_module.shutdown(&caudium_sapi_module);
782   tsrm_shutdown();
783 }
784 #endif
785