Annotation of embedaddon/php/sapi/caudium/caudium.c, revision 1.1

1.1     ! misho       1: /* 
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 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: caudium.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            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:  
        !           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:  */
        !           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:  */
        !           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
        !           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
        !           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
        !           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
        !           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
        !           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
        !           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: 
        !           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
        !           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 *
        !           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: 
        !           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: caudium.c 321634 2012-01-01 13:15:04Z felipe $");
        !           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: 
        !           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: 
        !           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: 
        !           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: 
        !           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: 
        !           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: 
        !           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: 
        !           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: 
        !           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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>