diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-03-14 05:42:27 +0000 |
---|---|---|
committer | <> | 2013-04-03 16:25:08 +0000 |
commit | c4dd7a1a684490673e25aaf4fabec5df138854c4 (patch) | |
tree | 4d57c44caae4480efff02b90b9be86f44bf25409 /sapi/aolserver/aolserver.c | |
download | php2-master.tar.gz |
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'sapi/aolserver/aolserver.c')
-rw-r--r-- | sapi/aolserver/aolserver.c | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/sapi/aolserver/aolserver.c b/sapi/aolserver/aolserver.c new file mode 100644 index 0000000..3dcbc8d --- /dev/null +++ b/sapi/aolserver/aolserver.c @@ -0,0 +1,625 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Sascha Schumann <sascha@schumann.cx> | + +----------------------------------------------------------------------+ + */ + +/* + * TODO: + * - write documentation + * - CGI/1.1 conformance + */ + +/* $Id$ */ + +/* conflict between PHP and AOLserver headers */ +#define Debug php_Debug +#include "php.h" +#undef Debug + +#ifdef HAVE_AOLSERVER + +#ifndef ZTS +#error AOLserver module is only useable in thread-safe mode +#endif + +#include "ext/standard/info.h" +#define SECTION(name) PUTS("<h2>" name "</h2>\n") + +#define NS_BUF_SIZE 511 + +#include "php_ini.h" +#include "php_globals.h" +#include "SAPI.h" +#include "php_main.h" +#include "php_variables.h" + +#include "ns.h" + +#include "php_version.h" + +/* This symbol is used by AOLserver to tell the API version we expect */ + +int Ns_ModuleVersion = 1; + +#define NSG(v) TSRMG(ns_globals_id, ns_globals_struct *, v) + +/* php_ns_context is per-server (thus only once at all) */ + +typedef struct { + sapi_module_struct *sapi_module; + char *ns_server; + char *ns_module; +} php_ns_context; + +/* ns_globals_struct is per-thread */ + +typedef struct { + Ns_Conn *conn; + size_t data_avail; +} ns_globals_struct; + +/* TSRM id */ + +static int ns_globals_id; + +/* global context */ + +static php_ns_context *global_context; + +static void php_ns_config(php_ns_context *ctx, char global); + +/* + * php_ns_sapi_ub_write() writes data to the client connection. + */ + +static int +php_ns_sapi_ub_write(const char *str, uint str_length TSRMLS_DC) +{ + int n; + uint sent = 0; + + while (str_length > 0) { + n = Ns_ConnWrite(NSG(conn), (void *) str, str_length); + + if (n == -1) + php_handle_aborted_connection(); + + str += n; + sent += n; + str_length -= n; + } + + return sent; +} + +/* + * php_ns_sapi_header_handler() sets a HTTP reply header to be + * sent to the client. + */ + +static int +php_ns_sapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC) +{ + char *header_name, *header_content; + char *p; + + header_name = sapi_header->header; + header_content = p = strchr(header_name, ':'); + + if (p) { + *p = '\0'; + do { + header_content++; + } while (*header_content == ' '); + + if (!strcasecmp(header_name, "Content-type")) { + Ns_ConnSetTypeHeader(NSG(conn), header_content); + } else { + Ns_ConnSetHeaders(NSG(conn), header_name, header_content); + } + + *p = ':'; + } + + sapi_free_header(sapi_header); + + return 0; +} + +/* + * php_ns_sapi_send_headers() flushes the headers to the client. + * Called before real content is sent by PHP. + */ + +static int +php_ns_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) +{ + if(SG(sapi_headers).send_default_content_type) { + Ns_ConnSetRequiredHeaders(NSG(conn), "text/html", 0); + } + + Ns_ConnFlushHeaders(NSG(conn), SG(sapi_headers).http_response_code); + + return SAPI_HEADER_SENT_SUCCESSFULLY; +} + +/* + * php_ns_sapi_read_post() reads a specified number of bytes from + * the client. Used for POST/PUT requests. + */ + +static int +php_ns_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC) +{ + uint max_read; + uint total_read = 0; + + max_read = MIN(NSG(data_avail), count_bytes); + + total_read = Ns_ConnRead(NSG(conn), buf, max_read); + + if(total_read == NS_ERROR) { + total_read = -1; + } else { + NSG(data_avail) -= total_read; + } + + return total_read; +} + +/* + * php_ns_sapi_read_cookies() returns the Cookie header from + * the HTTP request header + */ + +static char *php_ns_sapi_read_cookies(TSRMLS_D) +{ + int i; + char *http_cookie = NULL; + + i = Ns_SetIFind(NSG(conn->headers), "cookie"); + if(i != -1) { + http_cookie = Ns_SetValue(NSG(conn->headers), i); + } + + return http_cookie; +} + +static void php_info_aolserver(ZEND_MODULE_INFO_FUNC_ARGS) +{ + char buf[512]; + int uptime = Ns_InfoUptime(); + int i; + + php_info_print_table_start(); + php_info_print_table_row(2, "SAPI module version", "$Id$"); + php_info_print_table_row(2, "Build date", Ns_InfoBuildDate()); + php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile()); + php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog()); + php_info_print_table_row(2, "Installation path", Ns_InfoHomePath()); + php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname()); + php_info_print_table_row(2, "Source code label", Ns_InfoLabel()); + php_info_print_table_row(2, "Server platform", Ns_InfoPlatform()); + snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion()); + php_info_print_table_row(2, "Server version", buf); + snprintf(buf, 511, "%d day(s), %02d:%02d:%02d", + uptime / 86400, + (uptime / 3600) % 24, + (uptime / 60) % 60, + uptime % 60); + php_info_print_table_row(2, "Server uptime", buf); + php_info_print_table_end(); + + SECTION("HTTP Headers Information"); + php_info_print_table_start(); + php_info_print_table_colspan_header(2, "HTTP Request Headers"); + php_info_print_table_row(2, "HTTP Request", NSG(conn)->request->line); + for (i = 0; i < Ns_SetSize(NSG(conn)->headers); i++) { + php_info_print_table_row(2, Ns_SetKey(NSG(conn)->headers, i), Ns_SetValue(NSG(conn)->headers, i)); + } + + php_info_print_table_colspan_header(2, "HTTP Response Headers"); + for (i = 0; i < Ns_SetSize(NSG(conn)->outputheaders); i++) { + php_info_print_table_row(2, Ns_SetKey(NSG(conn)->outputheaders, i), Ns_SetValue(NSG(conn)->outputheaders, i)); + } + php_info_print_table_end(); +} + +PHP_FUNCTION(getallheaders); + +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO(arginfo_aolserver_getallheaders, 0) +ZEND_END_ARG_INFO() +/* }}} */ + +static const zend_function_entry aolserver_functions[] = { + PHP_FE(getallheaders, arginfo_aolserver_getallheaders) + {NULL, NULL, NULL} +}; + +static zend_module_entry php_aolserver_module = { + STANDARD_MODULE_HEADER, + "AOLserver", + aolserver_functions, + NULL, + NULL, + NULL, + NULL, + php_info_aolserver, + NULL, + STANDARD_MODULE_PROPERTIES +}; + +PHP_FUNCTION(getallheaders) +{ + int i; + + array_init(return_value); + + for (i = 0; i < Ns_SetSize(NSG(conn->headers)); i++) { + char *key = Ns_SetKey(NSG(conn->headers), i); + char *value = Ns_SetValue(NSG(conn->headers), i); + + add_assoc_string(return_value, key, value, 1); + } +} + +static int +php_ns_startup(sapi_module_struct *sapi_module) +{ + if (php_module_startup(sapi_module, &php_aolserver_module, 1) == FAILURE) { + return FAILURE; + } else { + return SUCCESS; + } +} + + +/* + * php_ns_sapi_register_variables() populates the php script environment + * with a number of variables. HTTP_* variables are created for + * the HTTP header data, so that a script can access these. + */ + +#define ADD_STRINGX(name, buf) \ + php_register_variable(name, buf, track_vars_array TSRMLS_CC) + +#define ADD_STRING(name) \ + ADD_STRINGX(name, buf) + +static void +php_ns_sapi_register_variables(zval *track_vars_array TSRMLS_DC) +{ + int i; + char buf[NS_BUF_SIZE + 1]; + char *tmp; + + for(i = 0; i < Ns_SetSize(NSG(conn->headers)); i++) { + char *key = Ns_SetKey(NSG(conn->headers), i); + char *value = Ns_SetValue(NSG(conn->headers), i); + char *p; + char c; + + snprintf(buf, NS_BUF_SIZE, "HTTP_%s", key); + + for(p = buf + 5; (c = *p); p++) { + c = toupper(c); + if(c < 'A' || c > 'Z') { + c = '_'; + } + *p = c; + } + + ADD_STRINGX(buf, value); + } + + snprintf(buf, NS_BUF_SIZE, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion()); + ADD_STRING("SERVER_SOFTWARE"); + snprintf(buf, NS_BUF_SIZE, "HTTP/%1.1f", NSG(conn)->request->version); + ADD_STRING("SERVER_PROTOCOL"); + + ADD_STRINGX("REQUEST_METHOD", NSG(conn)->request->method); + + if(NSG(conn)->request->query) + ADD_STRINGX("QUERY_STRING", NSG(conn)->request->query); + + ADD_STRINGX("SERVER_BUILDDATE", Ns_InfoBuildDate()); + + ADD_STRINGX("REMOTE_ADDR", Ns_ConnPeer(NSG(conn))); + + snprintf(buf, NS_BUF_SIZE, "%d", Ns_ConnPeerPort(NSG(conn))); + ADD_STRING("REMOTE_PORT"); + + snprintf(buf, NS_BUF_SIZE, "%d", Ns_ConnPort(NSG(conn))); + ADD_STRING("SERVER_PORT"); + + tmp = Ns_ConnHost(NSG(conn)); + if (tmp) + ADD_STRINGX("SERVER_NAME", tmp); + + ADD_STRINGX("PATH_TRANSLATED", SG(request_info).path_translated); + ADD_STRINGX("REQUEST_URI", SG(request_info).request_uri); + ADD_STRINGX("PHP_SELF", SG(request_info).request_uri); + + ADD_STRINGX("GATEWAY_INTERFACE", "CGI/1.1"); + + snprintf(buf, NS_BUF_SIZE, "%d", Ns_InfoBootTime()); + ADD_STRING("SERVER_BOOTTIME"); +} + + + +/* this structure is static (as in "it does not change") */ + +static sapi_module_struct aolserver_sapi_module = { + "aolserver", + "AOLserver", + + php_ns_startup, /* startup */ + php_module_shutdown_wrapper, /* shutdown */ + + NULL, /* activate */ + NULL, /* deactivate */ + + php_ns_sapi_ub_write, /* unbuffered write */ + NULL, /* flush */ + NULL, /* get uid */ + NULL, /* getenv */ + + php_error, /* error handler */ + + php_ns_sapi_header_handler, /* header handler */ + php_ns_sapi_send_headers, /* send headers handler */ + NULL, /* send header handler */ + + php_ns_sapi_read_post, /* read POST data */ + php_ns_sapi_read_cookies, /* read Cookies */ + + php_ns_sapi_register_variables, + NULL, /* Log message */ + NULL, /* Get request time */ + NULL, /* child terminate */ + + STANDARD_SAPI_MODULE_PROPERTIES +}; + +/* + * php_ns_module_main() is called by the per-request handler and + * "executes" the script + */ + +static int +php_ns_module_main(TSRMLS_D) +{ + zend_file_handle file_handle; + + file_handle.type = ZEND_HANDLE_FILENAME; + file_handle.filename = SG(request_info).path_translated; + file_handle.free_filename = 0; + file_handle.opened_path = NULL; + + php_ns_config(global_context, 0); + if (php_request_startup(TSRMLS_C) == FAILURE) { + return NS_ERROR; + } + + php_execute_script(&file_handle TSRMLS_CC); + php_request_shutdown(NULL); + + return NS_OK; +} + +/* + * php_ns_request_ctor() initializes the per-request data structure + * and fills it with data provided by the web server + */ + +static void +php_ns_request_ctor(TSRMLS_D) +{ + char *server; + Ns_DString ds; + char *root; + int index; + char *tmp; + + server = Ns_ConnServer(NSG(conn)); + +#define safe_strdup(x) ((x)?strdup((x)):NULL) + SG(request_info).query_string = safe_strdup(NSG(conn->request->query)); + + Ns_DStringInit(&ds); + Ns_UrlToFile(&ds, server, NSG(conn->request->url)); + + /* path_translated is the absolute path to the file */ + SG(request_info).path_translated = safe_strdup(Ns_DStringValue(&ds)); + Ns_DStringFree(&ds); + root = Ns_PageRoot(server); + SG(request_info).request_uri = strdup(SG(request_info).path_translated + strlen(root)); + SG(request_info).request_method = NSG(conn)->request->method; + if(NSG(conn)->request->version > 1.0) SG(request_info).proto_num = 1001; + else SG(request_info).proto_num = 1000; + SG(request_info).content_length = Ns_ConnContentLength(NSG(conn)); + index = Ns_SetIFind(NSG(conn)->headers, "content-type"); + SG(request_info).content_type = index == -1 ? NULL : + Ns_SetValue(NSG(conn)->headers, index); + SG(sapi_headers).http_response_code = 200; + + tmp = Ns_ConnAuthUser(NSG(conn)); + if (tmp) + tmp = estrdup(tmp); + SG(request_info).auth_user = tmp; + + tmp = Ns_ConnAuthPasswd(NSG(conn)); + if (tmp) + tmp = estrdup(tmp); + SG(request_info).auth_password = tmp; + + NSG(data_avail) = SG(request_info).content_length; +} + +/* + * php_ns_request_dtor() destroys all data associated with + * the per-request structure + */ + +static void +php_ns_request_dtor(TSRMLS_D) +{ + free(SG(request_info).path_translated); + if (SG(request_info).query_string) + free(SG(request_info).query_string); + free(SG(request_info).request_uri); +} + +/* + * The php_ns_request_handler() is called per request and handles + * everything for one request. + */ + +static int +php_ns_request_handler(void *context, Ns_Conn *conn) +{ + int status = NS_OK; + TSRMLS_FETCH(); + + NSG(conn) = conn; + + SG(server_context) = global_context; + + php_ns_request_ctor(TSRMLS_C); + + status = php_ns_module_main(TSRMLS_C); + + php_ns_request_dtor(TSRMLS_C); + + return status; +} + +/* + * php_ns_config() fetches the configuration data. + * + * It understands the "map" and "php_value" command. + */ + +static void +php_ns_config(php_ns_context *ctx, char global) +{ + int i; + char *path; + Ns_Set *set; + + path = Ns_ConfigGetPath(ctx->ns_server, ctx->ns_module, NULL); + set = Ns_ConfigGetSection(path); + + for (i = 0; set && i < Ns_SetSize(set); i++) { + char *key = Ns_SetKey(set, i); + char *value = Ns_SetValue(set, i); + + if (global && !strcasecmp(key, "map")) { + Ns_Log(Notice, "Registering PHP for \"%s\"", value); + Ns_RegisterRequest(ctx->ns_server, "GET", value, php_ns_request_handler, NULL, ctx, 0); + Ns_RegisterRequest(ctx->ns_server, "POST", value, php_ns_request_handler, NULL, ctx, 0); + Ns_RegisterRequest(ctx->ns_server, "HEAD", value, php_ns_request_handler, NULL, ctx, 0); + + /* + * Deactivated for now. The ini system will cause random crashes when + * accessed from here (since there are no locks to protect the global + * known_directives) + */ + + } else if (!global && !strcasecmp(key, "php_value")) { + Ns_Log(Notice, "php_value has been deactivated temporarily. Please use a php.ini file to pass directives to PHP. Thanks."); +#if 0 + char *val; + + val = strchr(value, ' '); + if (val) { + char *new_key; + + new_key = estrndup(value, val - value); + + do { + val++; + } while(*val == ' '); + + Ns_Log(Debug, "PHP configuration option '%s=%s'", new_key, val); + zend_alter_ini_entry(new_key, strlen(new_key) + 1, val, + strlen(val) + 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); + + efree(new_key); + } +#endif + } + + } +} + +/* + * php_ns_server_shutdown() performs the last steps before the + * server exits. Shutdowns basic services and frees memory + */ + +static void +php_ns_server_shutdown(void *context) +{ + php_ns_context *ctx = (php_ns_context *) context; + + ctx->sapi_module->shutdown(ctx->sapi_module); + sapi_shutdown(); + tsrm_shutdown(); + + free(ctx->ns_module); + free(ctx->ns_server); + free(ctx); +} + +/* + * Ns_ModuleInit() is called by AOLserver once at startup + * + * This functions allocates basic structures and initializes + * basic services. + */ + +int Ns_ModuleInit(char *server, char *module) +{ + php_ns_context *ctx; + + tsrm_startup(1, 1, 0, NULL); + sapi_startup(&aolserver_sapi_module); + sapi_module.startup(&aolserver_sapi_module); + + /* TSRM is used to allocate a per-thread structure */ + ts_allocate_id(&ns_globals_id, sizeof(ns_globals_struct), NULL, NULL); + + /* the context contains data valid for all threads */ + ctx = malloc(sizeof *ctx); + ctx->sapi_module = &aolserver_sapi_module; + ctx->ns_server = strdup(server); + ctx->ns_module = strdup(module); + + /* read the configuration */ + php_ns_config(ctx, 1); + + global_context = ctx; + + /* register shutdown handler */ + Ns_RegisterServerShutdown(server, php_ns_server_shutdown, ctx); + + return NS_OK; +} + +#endif |