Return to capi.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / continuity |
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: Alex Leigh <php (at) postfin (dot) com> | ! 16: +----------------------------------------------------------------------+ ! 17: */ ! 18: ! 19: /* For more information on Continuity: http://www.ashpool.com/ */ ! 20: ! 21: /* ! 22: * This code is based on the PHP5 SAPI module for NSAPI by Jayakumar ! 23: * Muthukumarasamy ! 24: */ ! 25: ! 26: /* PHP includes */ ! 27: #define CONTINUITY 1 ! 28: #define CAPI_DEBUG ! 29: ! 30: /* Define for CDP specific extensions */ ! 31: #undef CONTINUITY_CDPEXT ! 32: ! 33: #include "php.h" ! 34: #include "php_variables.h" ! 35: #include "ext/standard/info.h" ! 36: #include "php_ini.h" ! 37: #include "php_globals.h" ! 38: #include "SAPI.h" ! 39: #include "php_main.h" ! 40: #include "php_version.h" ! 41: #include "TSRM.h" ! 42: #include "ext/standard/php_standard.h" ! 43: ! 44: /* ! 45: * CAPI includes ! 46: */ ! 47: #include <continuity.h> ! 48: #include <http.h> ! 49: ! 50: #define NSLS_D struct capi_request_context *request_context ! 51: #define NSLS_DC , NSLS_D ! 52: #define NSLS_C request_context ! 53: #define NSLS_CC , NSLS_C ! 54: #define NSG(v) (request_context->v) ! 55: ! 56: /* ! 57: * ZTS needs to be defined for CAPI to work ! 58: */ ! 59: #if !defined(ZTS) ! 60: #error "CAPI module needs ZTS to be defined" ! 61: #endif ! 62: ! 63: /* ! 64: * Structure to encapsulate the CAPI request in SAPI ! 65: */ ! 66: typedef struct capi_request_context { ! 67: httpTtrans *t; ! 68: int read_post_bytes; ! 69: } capi_request_context; ! 70: ! 71: /**************/ ! 72: ! 73: PHP_MINIT_FUNCTION(continuity); ! 74: PHP_MSHUTDOWN_FUNCTION(continuity); ! 75: PHP_RINIT_FUNCTION(continuity); ! 76: PHP_RSHUTDOWN_FUNCTION(continuity); ! 77: PHP_MINFO_FUNCTION(continuity); ! 78: ! 79: PHP_FUNCTION(continuity_virtual); ! 80: PHP_FUNCTION(continuity_request_headers); ! 81: PHP_FUNCTION(continuity_response_headers); ! 82: ! 83: const zend_function_entry continuity_functions[] = { ! 84: {NULL, NULL, NULL} ! 85: }; ! 86: ! 87: zend_module_entry continuity_module_entry = { ! 88: STANDARD_MODULE_HEADER, ! 89: "continuity", ! 90: continuity_functions, ! 91: PHP_MINIT(continuity), ! 92: PHP_MSHUTDOWN(continuity), ! 93: NULL, ! 94: NULL, ! 95: PHP_MINFO(continuity), ! 96: NO_VERSION_YET, ! 97: STANDARD_MODULE_PROPERTIES ! 98: }; ! 99: ! 100: PHP_MINIT_FUNCTION(continuity) ! 101: { ! 102: return SUCCESS; ! 103: } ! 104: ! 105: PHP_MSHUTDOWN_FUNCTION(continuity) ! 106: { ! 107: return SUCCESS; ! 108: } ! 109: ! 110: PHP_MINFO_FUNCTION(continuity) ! 111: { ! 112: php_info_print_table_start(); ! 113: php_info_print_table_row(2, "Continuity Module Revision", "$Revision: 321634 $"); ! 114: php_info_print_table_row(2, "Server Version", conFget_build()); ! 115: #ifdef CONTINUITY_CDPEXT ! 116: php_info_print_table_row(2,"CDP Extensions", "enabled"); ! 117: #else ! 118: php_info_print_table_row(2,"CDP Extensions", "disabled"); ! 119: #endif ! 120: php_info_print_table_end(); ! 121: ! 122: /* DISPLAY_INI_ENTRIES(); */ ! 123: } ! 124: ! 125: /**************/ ! 126: ! 127: /* ! 128: * sapi_capi_ub_write: Write len bytes to the connection output. ! 129: */ ! 130: static int sapi_capi_ub_write(const char *str, unsigned int str_length TSRMLS_DC) ! 131: { ! 132: int retval; ! 133: capi_request_context *rc; ! 134: ! 135: rc = (capi_request_context *) SG(server_context); ! 136: retval = httpFwrite(rc->t, (char *) str, str_length); ! 137: if (retval == -1 || retval == 0) ! 138: php_handle_aborted_connection(); ! 139: return retval; ! 140: } ! 141: ! 142: /* ! 143: * sapi_capi_header_handler: Add/update response headers with those provided ! 144: * by the PHP engine. ! 145: */ ! 146: static int sapi_capi_header_handler(sapi_header_struct * sapi_header, sapi_headers_struct * sapi_headers TSRMLS_DC) ! 147: { ! 148: char *header_name, *header_content, *p; ! 149: capi_request_context *rc = (capi_request_context *) SG(server_context); ! 150: ! 151: lstFset_delete_key(rc->t->res_hdrs, "Content-Type"); ! 152: ! 153: header_name = sapi_header->header; ! 154: header_content = p = strchr(header_name, ':'); ! 155: if (p == NULL) { ! 156: return 0; ! 157: } ! 158: *p = 0; ! 159: do { ! 160: header_content++; ! 161: } while (*header_content == ' '); ! 162: ! 163: lstFset_add(rc->t->res_hdrs, header_name, header_content); ! 164: ! 165: *p = ':'; /* restore '*p' */ ! 166: ! 167: efree(sapi_header->header); ! 168: ! 169: return 0; /* don't use the default SAPI mechanism, CAPI ! 170: * duplicates this functionality */ ! 171: } ! 172: ! 173: /* ! 174: * sapi_capi_send_headers: Transmit the headers to the client. This has the ! 175: * effect of starting the response under Continuity. ! 176: */ ! 177: static int sapi_capi_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC) ! 178: { ! 179: int retval; ! 180: capi_request_context *rc = (capi_request_context *) SG(server_context); ! 181: ! 182: /* ! 183: * We could probably just do this in the header_handler. But, I don't know ! 184: * what the implication of doing it there is. ! 185: */ ! 186: ! 187: if (SG(sapi_headers).send_default_content_type) { ! 188: /* lstFset_delete_key(rc->t->res_hdrs, "Content-Type"); */ ! 189: lstFset_update(rc->t->res_hdrs, "Content-Type", "text/html"); ! 190: } ! 191: httpFset_status(rc->t, SG(sapi_headers).http_response_code, NULL); ! 192: httpFstart_response(rc->t); ! 193: ! 194: return SAPI_HEADER_SENT_SUCCESSFULLY; ! 195: ! 196: } ! 197: ! 198: static int sapi_capi_read_post(char *buffer, uint count_bytes TSRMLS_DC) ! 199: { ! 200: unsigned int max_read, total_read = 0; ! 201: capi_request_context *rc = (capi_request_context *) SG(server_context); ! 202: ! 203: if (rc->read_post_bytes == -1) { ! 204: max_read = MIN(count_bytes, SG(request_info).content_length); ! 205: } else { ! 206: if (rc->read_post_bytes == 0) ! 207: return 0; ! 208: max_read = MIN(count_bytes, (SG(request_info).content_length - rc->read_post_bytes)); ! 209: } ! 210: ! 211: total_read = httpFread(rc->t, buffer, max_read); ! 212: ! 213: if (total_read < 0) ! 214: total_read = -1; ! 215: else ! 216: rc->read_post_bytes = total_read; ! 217: ! 218: return total_read; ! 219: } ! 220: ! 221: /* ! 222: * sapi_capi_read_cookies: Return cookie information into PHP. ! 223: */ ! 224: static char *sapi_capi_read_cookies(TSRMLS_D) ! 225: { ! 226: char *cookie_string; ! 227: capi_request_context *rc = (capi_request_context *) SG(server_context); ! 228: ! 229: cookie_string = lstFset_get(rc->t->req_hdrs, "cookie"); ! 230: return cookie_string; ! 231: } ! 232: ! 233: static void sapi_capi_register_server_variables(zval * track_vars_array TSRMLS_DC) ! 234: { ! 235: capi_request_context *rc = (capi_request_context *) SG(server_context); ! 236: size_t i; ! 237: char *value; ! 238: char buf[128]; ! 239: ! 240: /* PHP_SELF and REQUEST_URI */ ! 241: value = lstFset_get(rc->t->vars, "uri"); ! 242: if (value != NULL) { ! 243: php_register_variable("PHP_SELF", value, track_vars_array TSRMLS_CC); ! 244: php_register_variable("REQUEST_URI", value, track_vars_array TSRMLS_CC); ! 245: } ! 246: ! 247: /* COUNTRY CODE */ ! 248: value = lstFset_get(rc->t->vars, "ccode"); ! 249: if(value!=NULL) ! 250: php_register_variable("COUNTRY_CODE", value, track_vars_array TSRMLS_CC); ! 251: ! 252: /* argv */ ! 253: value = lstFset_get(rc->t->vars, "query"); ! 254: if (value != NULL) ! 255: php_register_variable("argv", value, track_vars_array TSRMLS_CC); ! 256: ! 257: /* GATEWAY_INTERFACE */ ! 258: php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC); ! 259: ! 260: /* SERVER_NAME and HTTP_HOST */ ! 261: value = lstFset_get(rc->t->req_hdrs, "host"); ! 262: if (value != NULL) { ! 263: php_register_variable("HTTP_HOST", value, track_vars_array TSRMLS_CC); ! 264: /* TODO: This should probably scrub the port value if one is present. */ ! 265: php_register_variable("SERVER_NAME", value, track_vars_array TSRMLS_CC); ! 266: } ! 267: /* SERVER_SOFTWARE */ ! 268: value = lstFset_get(rc->t->res_hdrs, "Server"); ! 269: if (value != NULL) ! 270: php_register_variable("SERVER_SOFTWARE", value, track_vars_array TSRMLS_CC); ! 271: ! 272: /* SERVER_PROTOCOL */ ! 273: value = lstFset_get(rc->t->vars, "protocol"); ! 274: if (value != NULL) ! 275: php_register_variable("SERVER_PROTOCOL", value, track_vars_array TSRMLS_CC); ! 276: ! 277: /* REQUEST_METHOD */ ! 278: value = lstFset_get(rc->t->vars, "method"); ! 279: if (value != NULL) ! 280: php_register_variable("REQUEST_METHOD", value, track_vars_array TSRMLS_CC); ! 281: ! 282: /* QUERY_STRING */ ! 283: value = lstFset_get(rc->t->vars, "query"); ! 284: if (value != NULL) ! 285: php_register_variable("QUERY_STRING", value, track_vars_array TSRMLS_CC); ! 286: ! 287: /* DOCUMENT_ROOT */ ! 288: value = lstFset_get(rc->t->vars, "docroot"); ! 289: if (value != NULL) ! 290: php_register_variable("DOCUMENT_ROOT", value, track_vars_array TSRMLS_CC); ! 291: ! 292: /* HTTP_ACCEPT */ ! 293: value = lstFset_get(rc->t->req_hdrs, "accept"); ! 294: if (value != NULL) ! 295: php_register_variable("HTTP_ACCEPT", value, track_vars_array TSRMLS_CC); ! 296: ! 297: /* HTTP_ACCEPT_CHARSET */ ! 298: value = lstFset_get(rc->t->req_hdrs, "accept-charset"); ! 299: if (value != NULL) ! 300: php_register_variable("HTTP_ACCEPT_CHARSET", value, track_vars_array TSRMLS_CC); ! 301: ! 302: /* HTTP_ACCEPT_ENCODING */ ! 303: value = lstFset_get(rc->t->req_hdrs, "accept-encoding"); ! 304: if (value != NULL) ! 305: php_register_variable("HTTP_ACCEPT_ENCODING", value, track_vars_array TSRMLS_CC); ! 306: ! 307: /* HTTP_ACCEPT_LANGUAGE */ ! 308: value = lstFset_get(rc->t->req_hdrs, "accept-language"); ! 309: if (value != NULL) ! 310: php_register_variable("HTTP_ACCEPT_LANGUAGE", value, track_vars_array TSRMLS_CC); ! 311: ! 312: /* HTTP_CONNECTION */ ! 313: value = lstFset_get(rc->t->req_hdrs, "connection"); ! 314: if (value != NULL) ! 315: php_register_variable("HTTP_CONNECTION", value, track_vars_array TSRMLS_CC); ! 316: ! 317: /* HTTP_REFERER */ ! 318: value = lstFset_get(rc->t->req_hdrs, "referer"); ! 319: if (value != NULL) ! 320: php_register_variable("HTTP_REFERER", value, track_vars_array TSRMLS_CC); ! 321: ! 322: /* HTTP_USER_AGENT */ ! 323: value = lstFset_get(rc->t->req_hdrs, "user-agent"); ! 324: if (value != NULL) ! 325: php_register_variable("HTTP_USER_AGENT", value, track_vars_array TSRMLS_CC); ! 326: ! 327: /* REMOTE_ADDR */ ! 328: utlFip_to_str(rc->t->cli_ipv4_addr, buf, sizeof(buf)); ! 329: php_register_variable("REMOTE_ADDR", buf, track_vars_array TSRMLS_CC); ! 330: ! 331: /* REMOTE_PORT */ ! 332: ! 333: /* SCRIPT_FILENAME and PATH_TRANSLATED */ ! 334: value = lstFset_get(rc->t->vars, "path"); ! 335: if (value != NULL) { ! 336: php_register_variable("SCRIPT_FILENAME", value, track_vars_array TSRMLS_CC); ! 337: php_register_variable("PATH_TRANSLATED", value, track_vars_array TSRMLS_CC); ! 338: } ! 339: /* SERVER_ADMIN */ ! 340: /* Not applicable */ ! 341: ! 342: /* SERVER_PORT */ ! 343: ! 344: } ! 345: ! 346: static void capi_log_message(char *message) ! 347: { ! 348: TSRMLS_FETCH(); ! 349: capi_request_context *rc = (capi_request_context *) SG(server_context); ! 350: logFmsg(0, "mod/php: %s", message); ! 351: } ! 352: ! 353: static int php_capi_startup(sapi_module_struct *sapi_module); ! 354: ! 355: sapi_module_struct capi_sapi_module = { ! 356: "Continuity", /* name */ ! 357: "Continuity Server Enterprise Edition", /* pretty name */ ! 358: ! 359: php_capi_startup, /* startup */ ! 360: php_module_shutdown_wrapper, /* shutdown */ ! 361: ! 362: NULL, /* activate */ ! 363: NULL, /* deactivate */ ! 364: ! 365: sapi_capi_ub_write, /* unbuffered write */ ! 366: NULL, /* flush */ ! 367: NULL, /* get uid */ ! 368: NULL, /* getenv */ ! 369: ! 370: php_error, /* error handler */ ! 371: ! 372: sapi_capi_header_handler, /* header handler */ ! 373: sapi_capi_send_headers, /* send headers handler */ ! 374: NULL, /* send header handler */ ! 375: ! 376: sapi_capi_read_post, /* read POST data */ ! 377: sapi_capi_read_cookies, /* read Cookies */ ! 378: ! 379: sapi_capi_register_server_variables, /* register server variables */ ! 380: capi_log_message, /* Log message */ ! 381: NULL, /* Get request time */ ! 382: NULL, /* Child terminate */ ! 383: ! 384: NULL, /* Block interruptions */ ! 385: NULL, /* Unblock interruptions */ ! 386: ! 387: STANDARD_SAPI_MODULE_PROPERTIES ! 388: }; ! 389: ! 390: static int php_capi_startup(sapi_module_struct *sapi_module) { ! 391: if(php_module_startup(sapi_module,&continuity_module_entry,1)==FAILURE) { ! 392: return FAILURE; ! 393: } ! 394: return SUCCESS; ! 395: } ! 396: ! 397: ! 398: static char * ! 399: capi_strdup(char *str) ! 400: { ! 401: if (str != NULL) ! 402: return strFcopy(str); ! 403: return NULL; ! 404: } ! 405: ! 406: static void capi_free(void *addr) ! 407: { ! 408: if (addr != NULL) ! 409: free(addr); ! 410: } ! 411: ! 412: static void capi_request_ctor(NSLS_D TSRMLS_DC) ! 413: { ! 414: char *query_string = lstFset_get(NSG(t->vars), "query"); ! 415: char *uri = lstFset_get(NSG(t->vars), "uri"); ! 416: char *path_info = lstFset_get(NSG(t->vars), "path-info"); ! 417: char *path_translated = lstFset_get(NSG(t->vars), "path"); ! 418: char *request_method = lstFset_get(NSG(t->vars), "method"); ! 419: char *content_type = lstFset_get(NSG(t->req_hdrs), "content-type"); ! 420: char *content_length = lstFset_get(NSG(t->req_hdrs), "content-length"); ! 421: ! 422: SG(request_info).query_string = capi_strdup(query_string); ! 423: SG(request_info).request_uri = capi_strdup(uri); ! 424: SG(request_info).request_method = capi_strdup(request_method); ! 425: SG(request_info).path_translated = capi_strdup(path_translated); ! 426: SG(request_info).content_type = capi_strdup(content_type); ! 427: SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0); ! 428: SG(sapi_headers).http_response_code = 200; ! 429: } ! 430: ! 431: static void capi_request_dtor(NSLS_D TSRMLS_DC) ! 432: { ! 433: capi_free(SG(request_info).query_string); ! 434: capi_free(SG(request_info).request_uri); ! 435: capi_free(SG(request_info).request_method); ! 436: capi_free(SG(request_info).path_translated); ! 437: capi_free(SG(request_info).content_type); ! 438: } ! 439: ! 440: int capi_module_main(NSLS_D TSRMLS_DC) ! 441: { ! 442: zend_file_handle file_handle; ! 443: ! 444: if (php_request_startup(TSRMLS_C) == FAILURE) { ! 445: return FAILURE; ! 446: } ! 447: file_handle.type = ZEND_HANDLE_FILENAME; ! 448: file_handle.filename = SG(request_info).path_translated; ! 449: file_handle.free_filename = 0; ! 450: file_handle.opened_path = NULL; ! 451: ! 452: php_execute_script(&file_handle TSRMLS_CC); ! 453: php_request_shutdown(NULL); ! 454: ! 455: return SUCCESS; ! 456: } ! 457: ! 458: int phpFinit(lstTset * opt) ! 459: { ! 460: php_core_globals *core_globals; ! 461: ! 462: tsrm_startup(128, 1, 0, NULL); ! 463: core_globals = ts_resource(core_globals_id); ! 464: ! 465: logFmsg(0, "mod/php: PHP Interface v3 (module)"); ! 466: logFmsg(0, "mod/php: Copyright (c) 1999-2005 The PHP Group. All rights reserved."); ! 467: ! 468: sapi_startup(&capi_sapi_module); ! 469: capi_sapi_module.startup(&capi_sapi_module); ! 470: ! 471: return STATUS_PROCEED; ! 472: } ! 473: ! 474: int phpFservice(httpTtrans * t, lstTset * opts) ! 475: { ! 476: int retval; ! 477: capi_request_context *request_context; ! 478: ! 479: TSRMLS_FETCH(); ! 480: ! 481: request_context = (capi_request_context *) malloc(sizeof(capi_request_context)); ! 482: request_context->t = t; ! 483: request_context->read_post_bytes = -1; ! 484: ! 485: SG(server_context) = request_context; ! 486: ! 487: capi_request_ctor(NSLS_C TSRMLS_CC); ! 488: retval = capi_module_main(NSLS_C TSRMLS_CC); ! 489: capi_request_dtor(NSLS_C TSRMLS_CC); ! 490: ! 491: free(request_context); ! 492: ! 493: /* ! 494: * This call is ostensibly provided to free the memory from PHP/TSRM when ! 495: * the thread terminated, but, it leaks a structure in some hash list ! 496: * according to the developers. Not calling this will leak the entire ! 497: * interpreter, around 100k, but calling it and then terminating the ! 498: * thread will leak the struct (around a k). The only answer with the ! 499: * current TSRM implementation is to reuse the threads that allocate TSRM ! 500: * resources. ! 501: */ ! 502: /* ts_free_thread(); */ ! 503: ! 504: if (retval == SUCCESS) { ! 505: return STATUS_EXIT; ! 506: } else { ! 507: return STATUS_ERROR; ! 508: } ! 509: }