Annotation of embedaddon/php/sapi/roxen/roxen.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: roxen.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            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:  
        !           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:  */
        !           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:  */
        !           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
        !           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
        !           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:  */
        !           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
        !           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
        !           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
        !           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: 
        !           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
        !           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 *
        !           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: 
        !           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: roxen.c 321634 2012-01-01 13:15:04Z felipe $");
        !           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: 
        !           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
        !           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: 
        !           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: 
        !           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 */
        !           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: 
        !           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: 
        !           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

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