Return to aolserver.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / aolserver |
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: Sascha Schumann <sascha@schumann.cx> | ! 16: +----------------------------------------------------------------------+ ! 17: */ ! 18: ! 19: /* ! 20: * TODO: ! 21: * - write documentation ! 22: * - CGI/1.1 conformance ! 23: */ ! 24: ! 25: /* $Id: aolserver.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 26: ! 27: /* conflict between PHP and AOLserver headers */ ! 28: #define Debug php_Debug ! 29: #include "php.h" ! 30: #undef Debug ! 31: ! 32: #ifdef HAVE_AOLSERVER ! 33: ! 34: #ifndef ZTS ! 35: #error AOLserver module is only useable in thread-safe mode ! 36: #endif ! 37: ! 38: #include "ext/standard/info.h" ! 39: #define SECTION(name) PUTS("<h2>" name "</h2>\n") ! 40: ! 41: #define NS_BUF_SIZE 511 ! 42: ! 43: #include "php_ini.h" ! 44: #include "php_globals.h" ! 45: #include "SAPI.h" ! 46: #include "php_main.h" ! 47: #include "php_variables.h" ! 48: ! 49: #include "ns.h" ! 50: ! 51: #include "php_version.h" ! 52: ! 53: /* This symbol is used by AOLserver to tell the API version we expect */ ! 54: ! 55: int Ns_ModuleVersion = 1; ! 56: ! 57: #define NSG(v) TSRMG(ns_globals_id, ns_globals_struct *, v) ! 58: ! 59: /* php_ns_context is per-server (thus only once at all) */ ! 60: ! 61: typedef struct { ! 62: sapi_module_struct *sapi_module; ! 63: char *ns_server; ! 64: char *ns_module; ! 65: } php_ns_context; ! 66: ! 67: /* ns_globals_struct is per-thread */ ! 68: ! 69: typedef struct { ! 70: Ns_Conn *conn; ! 71: size_t data_avail; ! 72: } ns_globals_struct; ! 73: ! 74: /* TSRM id */ ! 75: ! 76: static int ns_globals_id; ! 77: ! 78: /* global context */ ! 79: ! 80: static php_ns_context *global_context; ! 81: ! 82: static void php_ns_config(php_ns_context *ctx, char global); ! 83: ! 84: /* ! 85: * php_ns_sapi_ub_write() writes data to the client connection. ! 86: */ ! 87: ! 88: static int ! 89: php_ns_sapi_ub_write(const char *str, uint str_length TSRMLS_DC) ! 90: { ! 91: int n; ! 92: uint sent = 0; ! 93: ! 94: while (str_length > 0) { ! 95: n = Ns_ConnWrite(NSG(conn), (void *) str, str_length); ! 96: ! 97: if (n == -1) ! 98: php_handle_aborted_connection(); ! 99: ! 100: str += n; ! 101: sent += n; ! 102: str_length -= n; ! 103: } ! 104: ! 105: return sent; ! 106: } ! 107: ! 108: /* ! 109: * php_ns_sapi_header_handler() sets a HTTP reply header to be ! 110: * sent to the client. ! 111: */ ! 112: ! 113: static int ! 114: php_ns_sapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC) ! 115: { ! 116: char *header_name, *header_content; ! 117: char *p; ! 118: ! 119: header_name = sapi_header->header; ! 120: header_content = p = strchr(header_name, ':'); ! 121: ! 122: if (p) { ! 123: *p = '\0'; ! 124: do { ! 125: header_content++; ! 126: } while (*header_content == ' '); ! 127: ! 128: if (!strcasecmp(header_name, "Content-type")) { ! 129: Ns_ConnSetTypeHeader(NSG(conn), header_content); ! 130: } else { ! 131: Ns_ConnSetHeaders(NSG(conn), header_name, header_content); ! 132: } ! 133: ! 134: *p = ':'; ! 135: } ! 136: ! 137: sapi_free_header(sapi_header); ! 138: ! 139: return 0; ! 140: } ! 141: ! 142: /* ! 143: * php_ns_sapi_send_headers() flushes the headers to the client. ! 144: * Called before real content is sent by PHP. ! 145: */ ! 146: ! 147: static int ! 148: php_ns_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) ! 149: { ! 150: if(SG(sapi_headers).send_default_content_type) { ! 151: Ns_ConnSetRequiredHeaders(NSG(conn), "text/html", 0); ! 152: } ! 153: ! 154: Ns_ConnFlushHeaders(NSG(conn), SG(sapi_headers).http_response_code); ! 155: ! 156: return SAPI_HEADER_SENT_SUCCESSFULLY; ! 157: } ! 158: ! 159: /* ! 160: * php_ns_sapi_read_post() reads a specified number of bytes from ! 161: * the client. Used for POST/PUT requests. ! 162: */ ! 163: ! 164: static int ! 165: php_ns_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC) ! 166: { ! 167: uint max_read; ! 168: uint total_read = 0; ! 169: ! 170: max_read = MIN(NSG(data_avail), count_bytes); ! 171: ! 172: total_read = Ns_ConnRead(NSG(conn), buf, max_read); ! 173: ! 174: if(total_read == NS_ERROR) { ! 175: total_read = -1; ! 176: } else { ! 177: NSG(data_avail) -= total_read; ! 178: } ! 179: ! 180: return total_read; ! 181: } ! 182: ! 183: /* ! 184: * php_ns_sapi_read_cookies() returns the Cookie header from ! 185: * the HTTP request header ! 186: */ ! 187: ! 188: static char *php_ns_sapi_read_cookies(TSRMLS_D) ! 189: { ! 190: int i; ! 191: char *http_cookie = NULL; ! 192: ! 193: i = Ns_SetIFind(NSG(conn->headers), "cookie"); ! 194: if(i != -1) { ! 195: http_cookie = Ns_SetValue(NSG(conn->headers), i); ! 196: } ! 197: ! 198: return http_cookie; ! 199: } ! 200: ! 201: static void php_info_aolserver(ZEND_MODULE_INFO_FUNC_ARGS) ! 202: { ! 203: char buf[512]; ! 204: int uptime = Ns_InfoUptime(); ! 205: int i; ! 206: ! 207: php_info_print_table_start(); ! 208: php_info_print_table_row(2, "SAPI module version", "$Id: aolserver.c 321634 2012-01-01 13:15:04Z felipe $"); ! 209: php_info_print_table_row(2, "Build date", Ns_InfoBuildDate()); ! 210: php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile()); ! 211: php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog()); ! 212: php_info_print_table_row(2, "Installation path", Ns_InfoHomePath()); ! 213: php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname()); ! 214: php_info_print_table_row(2, "Source code label", Ns_InfoLabel()); ! 215: php_info_print_table_row(2, "Server platform", Ns_InfoPlatform()); ! 216: snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion()); ! 217: php_info_print_table_row(2, "Server version", buf); ! 218: snprintf(buf, 511, "%d day(s), %02d:%02d:%02d", ! 219: uptime / 86400, ! 220: (uptime / 3600) % 24, ! 221: (uptime / 60) % 60, ! 222: uptime % 60); ! 223: php_info_print_table_row(2, "Server uptime", buf); ! 224: php_info_print_table_end(); ! 225: ! 226: SECTION("HTTP Headers Information"); ! 227: php_info_print_table_start(); ! 228: php_info_print_table_colspan_header(2, "HTTP Request Headers"); ! 229: php_info_print_table_row(2, "HTTP Request", NSG(conn)->request->line); ! 230: for (i = 0; i < Ns_SetSize(NSG(conn)->headers); i++) { ! 231: php_info_print_table_row(2, Ns_SetKey(NSG(conn)->headers, i), Ns_SetValue(NSG(conn)->headers, i)); ! 232: } ! 233: ! 234: php_info_print_table_colspan_header(2, "HTTP Response Headers"); ! 235: for (i = 0; i < Ns_SetSize(NSG(conn)->outputheaders); i++) { ! 236: php_info_print_table_row(2, Ns_SetKey(NSG(conn)->outputheaders, i), Ns_SetValue(NSG(conn)->outputheaders, i)); ! 237: } ! 238: php_info_print_table_end(); ! 239: } ! 240: ! 241: PHP_FUNCTION(getallheaders); ! 242: ! 243: /* {{{ arginfo */ ! 244: ZEND_BEGIN_ARG_INFO(arginfo_aolserver_getallheaders, 0) ! 245: ZEND_END_ARG_INFO() ! 246: /* }}} */ ! 247: ! 248: static const zend_function_entry aolserver_functions[] = { ! 249: PHP_FE(getallheaders, arginfo_aolserver_getallheaders) ! 250: {NULL, NULL, NULL} ! 251: }; ! 252: ! 253: static zend_module_entry php_aolserver_module = { ! 254: STANDARD_MODULE_HEADER, ! 255: "AOLserver", ! 256: aolserver_functions, ! 257: NULL, ! 258: NULL, ! 259: NULL, ! 260: NULL, ! 261: php_info_aolserver, ! 262: NULL, ! 263: STANDARD_MODULE_PROPERTIES ! 264: }; ! 265: ! 266: PHP_FUNCTION(getallheaders) ! 267: { ! 268: int i; ! 269: ! 270: array_init(return_value); ! 271: ! 272: for (i = 0; i < Ns_SetSize(NSG(conn->headers)); i++) { ! 273: char *key = Ns_SetKey(NSG(conn->headers), i); ! 274: char *value = Ns_SetValue(NSG(conn->headers), i); ! 275: ! 276: add_assoc_string(return_value, key, value, 1); ! 277: } ! 278: } ! 279: ! 280: static int ! 281: php_ns_startup(sapi_module_struct *sapi_module) ! 282: { ! 283: if (php_module_startup(sapi_module, &php_aolserver_module, 1) == FAILURE) { ! 284: return FAILURE; ! 285: } else { ! 286: return SUCCESS; ! 287: } ! 288: } ! 289: ! 290: ! 291: /* ! 292: * php_ns_sapi_register_variables() populates the php script environment ! 293: * with a number of variables. HTTP_* variables are created for ! 294: * the HTTP header data, so that a script can access these. ! 295: */ ! 296: ! 297: #define ADD_STRINGX(name, buf) \ ! 298: php_register_variable(name, buf, track_vars_array TSRMLS_CC) ! 299: ! 300: #define ADD_STRING(name) \ ! 301: ADD_STRINGX(name, buf) ! 302: ! 303: static void ! 304: php_ns_sapi_register_variables(zval *track_vars_array TSRMLS_DC) ! 305: { ! 306: int i; ! 307: char buf[NS_BUF_SIZE + 1]; ! 308: char *tmp; ! 309: ! 310: for(i = 0; i < Ns_SetSize(NSG(conn->headers)); i++) { ! 311: char *key = Ns_SetKey(NSG(conn->headers), i); ! 312: char *value = Ns_SetValue(NSG(conn->headers), i); ! 313: char *p; ! 314: char c; ! 315: ! 316: snprintf(buf, NS_BUF_SIZE, "HTTP_%s", key); ! 317: ! 318: for(p = buf + 5; (c = *p); p++) { ! 319: c = toupper(c); ! 320: if(c < 'A' || c > 'Z') { ! 321: c = '_'; ! 322: } ! 323: *p = c; ! 324: } ! 325: ! 326: ADD_STRINGX(buf, value); ! 327: } ! 328: ! 329: snprintf(buf, NS_BUF_SIZE, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion()); ! 330: ADD_STRING("SERVER_SOFTWARE"); ! 331: snprintf(buf, NS_BUF_SIZE, "HTTP/%1.1f", NSG(conn)->request->version); ! 332: ADD_STRING("SERVER_PROTOCOL"); ! 333: ! 334: ADD_STRINGX("REQUEST_METHOD", NSG(conn)->request->method); ! 335: ! 336: if(NSG(conn)->request->query) ! 337: ADD_STRINGX("QUERY_STRING", NSG(conn)->request->query); ! 338: ! 339: ADD_STRINGX("SERVER_BUILDDATE", Ns_InfoBuildDate()); ! 340: ! 341: ADD_STRINGX("REMOTE_ADDR", Ns_ConnPeer(NSG(conn))); ! 342: ! 343: snprintf(buf, NS_BUF_SIZE, "%d", Ns_ConnPeerPort(NSG(conn))); ! 344: ADD_STRING("REMOTE_PORT"); ! 345: ! 346: snprintf(buf, NS_BUF_SIZE, "%d", Ns_ConnPort(NSG(conn))); ! 347: ADD_STRING("SERVER_PORT"); ! 348: ! 349: tmp = Ns_ConnHost(NSG(conn)); ! 350: if (tmp) ! 351: ADD_STRINGX("SERVER_NAME", tmp); ! 352: ! 353: ADD_STRINGX("PATH_TRANSLATED", SG(request_info).path_translated); ! 354: ADD_STRINGX("REQUEST_URI", SG(request_info).request_uri); ! 355: ADD_STRINGX("PHP_SELF", SG(request_info).request_uri); ! 356: ! 357: ADD_STRINGX("GATEWAY_INTERFACE", "CGI/1.1"); ! 358: ! 359: snprintf(buf, NS_BUF_SIZE, "%d", Ns_InfoBootTime()); ! 360: ADD_STRING("SERVER_BOOTTIME"); ! 361: } ! 362: ! 363: ! 364: ! 365: /* this structure is static (as in "it does not change") */ ! 366: ! 367: static sapi_module_struct aolserver_sapi_module = { ! 368: "aolserver", ! 369: "AOLserver", ! 370: ! 371: php_ns_startup, /* startup */ ! 372: php_module_shutdown_wrapper, /* shutdown */ ! 373: ! 374: NULL, /* activate */ ! 375: NULL, /* deactivate */ ! 376: ! 377: php_ns_sapi_ub_write, /* unbuffered write */ ! 378: NULL, /* flush */ ! 379: NULL, /* get uid */ ! 380: NULL, /* getenv */ ! 381: ! 382: php_error, /* error handler */ ! 383: ! 384: php_ns_sapi_header_handler, /* header handler */ ! 385: php_ns_sapi_send_headers, /* send headers handler */ ! 386: NULL, /* send header handler */ ! 387: ! 388: php_ns_sapi_read_post, /* read POST data */ ! 389: php_ns_sapi_read_cookies, /* read Cookies */ ! 390: ! 391: php_ns_sapi_register_variables, ! 392: NULL, /* Log message */ ! 393: NULL, /* Get request time */ ! 394: NULL, /* child terminate */ ! 395: ! 396: STANDARD_SAPI_MODULE_PROPERTIES ! 397: }; ! 398: ! 399: /* ! 400: * php_ns_module_main() is called by the per-request handler and ! 401: * "executes" the script ! 402: */ ! 403: ! 404: static int ! 405: php_ns_module_main(TSRMLS_D) ! 406: { ! 407: zend_file_handle file_handle; ! 408: ! 409: file_handle.type = ZEND_HANDLE_FILENAME; ! 410: file_handle.filename = SG(request_info).path_translated; ! 411: file_handle.free_filename = 0; ! 412: file_handle.opened_path = NULL; ! 413: ! 414: php_ns_config(global_context, 0); ! 415: if (php_request_startup(TSRMLS_C) == FAILURE) { ! 416: return NS_ERROR; ! 417: } ! 418: ! 419: php_execute_script(&file_handle TSRMLS_CC); ! 420: php_request_shutdown(NULL); ! 421: ! 422: return NS_OK; ! 423: } ! 424: ! 425: /* ! 426: * php_ns_request_ctor() initializes the per-request data structure ! 427: * and fills it with data provided by the web server ! 428: */ ! 429: ! 430: static void ! 431: php_ns_request_ctor(TSRMLS_D) ! 432: { ! 433: char *server; ! 434: Ns_DString ds; ! 435: char *root; ! 436: int index; ! 437: char *tmp; ! 438: ! 439: server = Ns_ConnServer(NSG(conn)); ! 440: ! 441: #define safe_strdup(x) ((x)?strdup((x)):NULL) ! 442: SG(request_info).query_string = safe_strdup(NSG(conn->request->query)); ! 443: ! 444: Ns_DStringInit(&ds); ! 445: Ns_UrlToFile(&ds, server, NSG(conn->request->url)); ! 446: ! 447: /* path_translated is the absolute path to the file */ ! 448: SG(request_info).path_translated = safe_strdup(Ns_DStringValue(&ds)); ! 449: Ns_DStringFree(&ds); ! 450: root = Ns_PageRoot(server); ! 451: SG(request_info).request_uri = strdup(SG(request_info).path_translated + strlen(root)); ! 452: SG(request_info).request_method = NSG(conn)->request->method; ! 453: if(NSG(conn)->request->version > 1.0) SG(request_info).proto_num = 1001; ! 454: else SG(request_info).proto_num = 1000; ! 455: SG(request_info).content_length = Ns_ConnContentLength(NSG(conn)); ! 456: index = Ns_SetIFind(NSG(conn)->headers, "content-type"); ! 457: SG(request_info).content_type = index == -1 ? NULL : ! 458: Ns_SetValue(NSG(conn)->headers, index); ! 459: SG(sapi_headers).http_response_code = 200; ! 460: ! 461: tmp = Ns_ConnAuthUser(NSG(conn)); ! 462: if (tmp) ! 463: tmp = estrdup(tmp); ! 464: SG(request_info).auth_user = tmp; ! 465: ! 466: tmp = Ns_ConnAuthPasswd(NSG(conn)); ! 467: if (tmp) ! 468: tmp = estrdup(tmp); ! 469: SG(request_info).auth_password = tmp; ! 470: ! 471: NSG(data_avail) = SG(request_info).content_length; ! 472: } ! 473: ! 474: /* ! 475: * php_ns_request_dtor() destroys all data associated with ! 476: * the per-request structure ! 477: */ ! 478: ! 479: static void ! 480: php_ns_request_dtor(TSRMLS_D) ! 481: { ! 482: free(SG(request_info).path_translated); ! 483: if (SG(request_info).query_string) ! 484: free(SG(request_info).query_string); ! 485: free(SG(request_info).request_uri); ! 486: } ! 487: ! 488: /* ! 489: * The php_ns_request_handler() is called per request and handles ! 490: * everything for one request. ! 491: */ ! 492: ! 493: static int ! 494: php_ns_request_handler(void *context, Ns_Conn *conn) ! 495: { ! 496: int status = NS_OK; ! 497: TSRMLS_FETCH(); ! 498: ! 499: NSG(conn) = conn; ! 500: ! 501: SG(server_context) = global_context; ! 502: ! 503: php_ns_request_ctor(TSRMLS_C); ! 504: ! 505: status = php_ns_module_main(TSRMLS_C); ! 506: ! 507: php_ns_request_dtor(TSRMLS_C); ! 508: ! 509: return status; ! 510: } ! 511: ! 512: /* ! 513: * php_ns_config() fetches the configuration data. ! 514: * ! 515: * It understands the "map" and "php_value" command. ! 516: */ ! 517: ! 518: static void ! 519: php_ns_config(php_ns_context *ctx, char global) ! 520: { ! 521: int i; ! 522: char *path; ! 523: Ns_Set *set; ! 524: ! 525: path = Ns_ConfigGetPath(ctx->ns_server, ctx->ns_module, NULL); ! 526: set = Ns_ConfigGetSection(path); ! 527: ! 528: for (i = 0; set && i < Ns_SetSize(set); i++) { ! 529: char *key = Ns_SetKey(set, i); ! 530: char *value = Ns_SetValue(set, i); ! 531: ! 532: if (global && !strcasecmp(key, "map")) { ! 533: Ns_Log(Notice, "Registering PHP for \"%s\"", value); ! 534: Ns_RegisterRequest(ctx->ns_server, "GET", value, php_ns_request_handler, NULL, ctx, 0); ! 535: Ns_RegisterRequest(ctx->ns_server, "POST", value, php_ns_request_handler, NULL, ctx, 0); ! 536: Ns_RegisterRequest(ctx->ns_server, "HEAD", value, php_ns_request_handler, NULL, ctx, 0); ! 537: ! 538: /* ! 539: * Deactivated for now. The ini system will cause random crashes when ! 540: * accessed from here (since there are no locks to protect the global ! 541: * known_directives) ! 542: */ ! 543: ! 544: } else if (!global && !strcasecmp(key, "php_value")) { ! 545: Ns_Log(Notice, "php_value has been deactivated temporarily. Please use a php.ini file to pass directives to PHP. Thanks."); ! 546: #if 0 ! 547: char *val; ! 548: ! 549: val = strchr(value, ' '); ! 550: if (val) { ! 551: char *new_key; ! 552: ! 553: new_key = estrndup(value, val - value); ! 554: ! 555: do { ! 556: val++; ! 557: } while(*val == ' '); ! 558: ! 559: Ns_Log(Debug, "PHP configuration option '%s=%s'", new_key, val); ! 560: zend_alter_ini_entry(new_key, strlen(new_key) + 1, val, ! 561: strlen(val) + 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); ! 562: ! 563: efree(new_key); ! 564: } ! 565: #endif ! 566: } ! 567: ! 568: } ! 569: } ! 570: ! 571: /* ! 572: * php_ns_server_shutdown() performs the last steps before the ! 573: * server exits. Shutdowns basic services and frees memory ! 574: */ ! 575: ! 576: static void ! 577: php_ns_server_shutdown(void *context) ! 578: { ! 579: php_ns_context *ctx = (php_ns_context *) context; ! 580: ! 581: ctx->sapi_module->shutdown(ctx->sapi_module); ! 582: sapi_shutdown(); ! 583: tsrm_shutdown(); ! 584: ! 585: free(ctx->ns_module); ! 586: free(ctx->ns_server); ! 587: free(ctx); ! 588: } ! 589: ! 590: /* ! 591: * Ns_ModuleInit() is called by AOLserver once at startup ! 592: * ! 593: * This functions allocates basic structures and initializes ! 594: * basic services. ! 595: */ ! 596: ! 597: int Ns_ModuleInit(char *server, char *module) ! 598: { ! 599: php_ns_context *ctx; ! 600: ! 601: tsrm_startup(1, 1, 0, NULL); ! 602: sapi_startup(&aolserver_sapi_module); ! 603: sapi_module.startup(&aolserver_sapi_module); ! 604: ! 605: /* TSRM is used to allocate a per-thread structure */ ! 606: ts_allocate_id(&ns_globals_id, sizeof(ns_globals_struct), NULL, NULL); ! 607: ! 608: /* the context contains data valid for all threads */ ! 609: ctx = malloc(sizeof *ctx); ! 610: ctx->sapi_module = &aolserver_sapi_module; ! 611: ctx->ns_server = strdup(server); ! 612: ctx->ns_module = strdup(module); ! 613: ! 614: /* read the configuration */ ! 615: php_ns_config(ctx, 1); ! 616: ! 617: global_context = ctx; ! 618: ! 619: /* register shutdown handler */ ! 620: Ns_RegisterServerShutdown(server, php_ns_server_shutdown, ctx); ! 621: ! 622: return NS_OK; ! 623: } ! 624: ! 625: #endif