Return to roxen.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / roxen |
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