Back to index

php5  5.3.10
aolserver.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Sascha Schumann <sascha@schumann.cx>                         |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /*
00020  * TODO:
00021  * - write documentation
00022  * - CGI/1.1 conformance
00023  */
00024 
00025 /* $Id: aolserver.c 321634 2012-01-01 13:15:04Z felipe $ */
00026 
00027 /* conflict between PHP and AOLserver headers */
00028 #define Debug php_Debug
00029 #include "php.h"
00030 #undef Debug
00031 
00032 #ifdef HAVE_AOLSERVER
00033 
00034 #ifndef ZTS
00035 #error AOLserver module is only useable in thread-safe mode
00036 #endif
00037 
00038 #include "ext/standard/info.h"
00039 #define SECTION(name)  PUTS("<h2>" name "</h2>\n")
00040 
00041 #define NS_BUF_SIZE 511
00042 
00043 #include "php_ini.h"
00044 #include "php_globals.h"
00045 #include "SAPI.h"
00046 #include "php_main.h"
00047 #include "php_variables.h"
00048 
00049 #include "ns.h"
00050 
00051 #include "php_version.h"
00052 
00053 /* This symbol is used by AOLserver to tell the API version we expect */
00054 
00055 int Ns_ModuleVersion = 1;
00056 
00057 #define NSG(v) TSRMG(ns_globals_id, ns_globals_struct *, v)
00058 
00059 /* php_ns_context is per-server (thus only once at all) */
00060 
00061 typedef struct {
00062        sapi_module_struct *sapi_module;
00063        char *ns_server;
00064        char *ns_module;
00065 } php_ns_context;
00066 
00067 /* ns_globals_struct is per-thread */
00068 
00069 typedef struct {
00070        Ns_Conn *conn;
00071        size_t data_avail;
00072 } ns_globals_struct;
00073 
00074 /* TSRM id */
00075 
00076 static int ns_globals_id;
00077 
00078 /* global context */
00079 
00080 static php_ns_context *global_context;
00081 
00082 static void php_ns_config(php_ns_context *ctx, char global);
00083 
00084 /*
00085  * php_ns_sapi_ub_write() writes data to the client connection.
00086  */
00087 
00088 static int
00089 php_ns_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
00090 {
00091        int n;
00092        uint sent = 0;
00093 
00094        while (str_length > 0) {
00095               n = Ns_ConnWrite(NSG(conn), (void *) str, str_length);
00096 
00097               if (n == -1)
00098                      php_handle_aborted_connection();
00099 
00100               str += n;
00101               sent += n;
00102               str_length -= n;
00103        }
00104        
00105        return sent;
00106 }
00107 
00108 /*
00109  * php_ns_sapi_header_handler() sets a HTTP reply header to be 
00110  * sent to the client.
00111  */
00112 
00113 static int
00114 php_ns_sapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC)
00115 {
00116        char *header_name, *header_content;
00117        char *p;
00118 
00119        header_name = sapi_header->header;
00120        header_content = p = strchr(header_name, ':');
00121 
00122        if (p) {
00123               *p = '\0';
00124               do {
00125                      header_content++;
00126               } while (*header_content == ' ');
00127 
00128               if (!strcasecmp(header_name, "Content-type")) {
00129                      Ns_ConnSetTypeHeader(NSG(conn), header_content);
00130               } else {
00131                      Ns_ConnSetHeaders(NSG(conn), header_name, header_content);
00132               }
00133 
00134               *p = ':';
00135        }
00136 
00137        sapi_free_header(sapi_header);
00138        
00139        return 0;
00140 }
00141 
00142 /*
00143  * php_ns_sapi_send_headers() flushes the headers to the client.
00144  * Called before real content is sent by PHP.
00145  */
00146 
00147 static int
00148 php_ns_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00149 {
00150        if(SG(sapi_headers).send_default_content_type) {
00151               Ns_ConnSetRequiredHeaders(NSG(conn), "text/html", 0);
00152        }
00153        
00154        Ns_ConnFlushHeaders(NSG(conn), SG(sapi_headers).http_response_code);
00155        
00156        return SAPI_HEADER_SENT_SUCCESSFULLY;
00157 }
00158 
00159 /*
00160  * php_ns_sapi_read_post() reads a specified number of bytes from
00161  * the client. Used for POST/PUT requests.
00162  */
00163 
00164 static int
00165 php_ns_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC)
00166 {
00167        uint max_read;
00168        uint total_read = 0;
00169 
00170        max_read = MIN(NSG(data_avail), count_bytes);
00171        
00172        total_read = Ns_ConnRead(NSG(conn), buf, max_read);
00173        
00174        if(total_read == NS_ERROR) {
00175               total_read = -1;
00176        } else {
00177               NSG(data_avail) -= total_read;
00178        }
00179 
00180        return total_read;
00181 }
00182 
00183 /* 
00184  * php_ns_sapi_read_cookies() returns the Cookie header from
00185  * the HTTP request header
00186  */
00187        
00188 static char *php_ns_sapi_read_cookies(TSRMLS_D)
00189 {
00190        int i;
00191        char *http_cookie = NULL;
00192        
00193        i = Ns_SetIFind(NSG(conn->headers), "cookie");
00194        if(i != -1) {
00195               http_cookie = Ns_SetValue(NSG(conn->headers), i);
00196        }
00197 
00198        return http_cookie;
00199 }
00200 
00201 static void php_info_aolserver(ZEND_MODULE_INFO_FUNC_ARGS)
00202 {
00203        char buf[512];
00204        int uptime = Ns_InfoUptime();
00205        int i;
00206        
00207        php_info_print_table_start();
00208        php_info_print_table_row(2, "SAPI module version", "$Id: aolserver.c 321634 2012-01-01 13:15:04Z felipe $");
00209        php_info_print_table_row(2, "Build date", Ns_InfoBuildDate());
00210        php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile());
00211        php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog());
00212        php_info_print_table_row(2, "Installation path", Ns_InfoHomePath());
00213        php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname());
00214        php_info_print_table_row(2, "Source code label", Ns_InfoLabel());
00215        php_info_print_table_row(2, "Server platform", Ns_InfoPlatform());
00216        snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion());
00217        php_info_print_table_row(2, "Server version", buf);
00218        snprintf(buf, 511, "%d day(s), %02d:%02d:%02d", 
00219                      uptime / 86400,
00220                      (uptime / 3600) % 24,
00221                      (uptime / 60) % 60,
00222                      uptime % 60);
00223        php_info_print_table_row(2, "Server uptime", buf);
00224        php_info_print_table_end();
00225 
00226        SECTION("HTTP Headers Information");
00227        php_info_print_table_start();
00228        php_info_print_table_colspan_header(2, "HTTP Request Headers");
00229        php_info_print_table_row(2, "HTTP Request", NSG(conn)->request->line);
00230        for (i = 0; i < Ns_SetSize(NSG(conn)->headers); i++) {
00231               php_info_print_table_row(2, Ns_SetKey(NSG(conn)->headers, i), Ns_SetValue(NSG(conn)->headers, i));
00232        }
00233 
00234        php_info_print_table_colspan_header(2, "HTTP Response Headers");
00235        for (i = 0; i < Ns_SetSize(NSG(conn)->outputheaders); i++) {
00236               php_info_print_table_row(2, Ns_SetKey(NSG(conn)->outputheaders, i), Ns_SetValue(NSG(conn)->outputheaders, i));
00237        }
00238        php_info_print_table_end();
00239 }
00240 
00241 PHP_FUNCTION(getallheaders);
00242 
00243 /* {{{ arginfo */
00244 ZEND_BEGIN_ARG_INFO(arginfo_aolserver_getallheaders, 0)
00245 ZEND_END_ARG_INFO()
00246 /* }}} */
00247 
00248 static const zend_function_entry aolserver_functions[] = {
00249        PHP_FE(getallheaders, arginfo_aolserver_getallheaders)
00250        {NULL, NULL, NULL}
00251 };
00252 
00253 static zend_module_entry php_aolserver_module = {
00254        STANDARD_MODULE_HEADER,
00255        "AOLserver",
00256        aolserver_functions,
00257        NULL,
00258        NULL,
00259        NULL,
00260        NULL,
00261        php_info_aolserver,
00262        NULL,
00263        STANDARD_MODULE_PROPERTIES
00264 };
00265 
00266 PHP_FUNCTION(getallheaders)
00267 {
00268        int i;
00269 
00270        array_init(return_value);
00271        
00272        for (i = 0; i < Ns_SetSize(NSG(conn->headers)); i++) {
00273               char *key = Ns_SetKey(NSG(conn->headers), i);
00274               char *value = Ns_SetValue(NSG(conn->headers), i);
00275               
00276               add_assoc_string(return_value, key, value, 1);
00277        }
00278 }
00279 
00280 static int
00281 php_ns_startup(sapi_module_struct *sapi_module)
00282 {
00283        if (php_module_startup(sapi_module, &php_aolserver_module, 1) == FAILURE) {
00284               return FAILURE;
00285        } else {
00286               return SUCCESS;
00287        }
00288 }
00289 
00290 
00291 /*
00292  * php_ns_sapi_register_variables() populates the php script environment
00293  * with a number of variables. HTTP_* variables are created for
00294  * the HTTP header data, so that a script can access these.
00295  */
00296 
00297 #define ADD_STRINGX(name, buf)                                                                    \
00298        php_register_variable(name, buf, track_vars_array TSRMLS_CC)
00299 
00300 #define ADD_STRING(name)                                                                   \
00301        ADD_STRINGX(name, buf)
00302 
00303 static void
00304 php_ns_sapi_register_variables(zval *track_vars_array TSRMLS_DC)
00305 {
00306        int i;
00307        char buf[NS_BUF_SIZE + 1];
00308        char *tmp;
00309 
00310        for(i = 0; i < Ns_SetSize(NSG(conn->headers)); i++) {
00311               char *key = Ns_SetKey(NSG(conn->headers), i);
00312               char *value = Ns_SetValue(NSG(conn->headers), i);
00313               char *p;
00314               char c;
00315 
00316               snprintf(buf, NS_BUF_SIZE, "HTTP_%s", key);
00317               
00318               for(p = buf + 5; (c = *p); p++) {
00319                      c = toupper(c);
00320                      if(c < 'A' || c > 'Z') {
00321                             c = '_';
00322                      }
00323                      *p = c;
00324               }
00325 
00326               ADD_STRINGX(buf, value);
00327        }
00328        
00329        snprintf(buf, NS_BUF_SIZE, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion());
00330        ADD_STRING("SERVER_SOFTWARE");
00331        snprintf(buf, NS_BUF_SIZE, "HTTP/%1.1f", NSG(conn)->request->version);
00332        ADD_STRING("SERVER_PROTOCOL");
00333 
00334        ADD_STRINGX("REQUEST_METHOD", NSG(conn)->request->method);
00335 
00336        if(NSG(conn)->request->query)
00337               ADD_STRINGX("QUERY_STRING", NSG(conn)->request->query);
00338        
00339        ADD_STRINGX("SERVER_BUILDDATE", Ns_InfoBuildDate());
00340 
00341        ADD_STRINGX("REMOTE_ADDR", Ns_ConnPeer(NSG(conn)));
00342 
00343        snprintf(buf, NS_BUF_SIZE, "%d", Ns_ConnPeerPort(NSG(conn)));
00344        ADD_STRING("REMOTE_PORT");
00345 
00346        snprintf(buf, NS_BUF_SIZE, "%d", Ns_ConnPort(NSG(conn)));
00347        ADD_STRING("SERVER_PORT");
00348 
00349        tmp = Ns_ConnHost(NSG(conn));
00350        if (tmp)
00351               ADD_STRINGX("SERVER_NAME", tmp);
00352 
00353        ADD_STRINGX("PATH_TRANSLATED", SG(request_info).path_translated);
00354        ADD_STRINGX("REQUEST_URI", SG(request_info).request_uri);
00355        ADD_STRINGX("PHP_SELF", SG(request_info).request_uri);
00356 
00357        ADD_STRINGX("GATEWAY_INTERFACE", "CGI/1.1");
00358 
00359        snprintf(buf, NS_BUF_SIZE, "%d", Ns_InfoBootTime());
00360        ADD_STRING("SERVER_BOOTTIME");
00361 }
00362 
00363 
00364 
00365 /* this structure is static (as in "it does not change") */
00366 
00367 static sapi_module_struct aolserver_sapi_module = {
00368        "aolserver",
00369        "AOLserver",
00370 
00371        php_ns_startup,                                                /* startup */
00372        php_module_shutdown_wrapper,                     /* shutdown */
00373 
00374        NULL,                                                          /* activate */
00375        NULL,                                                          /* deactivate */
00376 
00377        php_ns_sapi_ub_write,                                   /* unbuffered write */
00378        NULL,                                                          /* flush */
00379        NULL,                                                          /* get uid */
00380        NULL,                                                          /* getenv */
00381 
00382        php_error,                                                     /* error handler */
00383 
00384        php_ns_sapi_header_handler,                      /* header handler */
00385        php_ns_sapi_send_headers,                        /* send headers handler */
00386        NULL,                                                          /* send header handler */
00387 
00388        php_ns_sapi_read_post,                                  /* read POST data */
00389        php_ns_sapi_read_cookies,                        /* read Cookies */
00390 
00391        php_ns_sapi_register_variables,
00392        NULL,                                                          /* Log message */
00393        NULL,                                                          /* Get request time */
00394        NULL,                                            /* child terminate */
00395 
00396        STANDARD_SAPI_MODULE_PROPERTIES
00397 };
00398 
00399 /*
00400  * php_ns_module_main() is called by the per-request handler and
00401  * "executes" the script
00402  */
00403 
00404 static int
00405 php_ns_module_main(TSRMLS_D)
00406 {
00407        zend_file_handle file_handle;
00408 
00409        file_handle.type = ZEND_HANDLE_FILENAME;
00410        file_handle.filename = SG(request_info).path_translated;
00411        file_handle.free_filename = 0;
00412        file_handle.opened_path = NULL;
00413        
00414        php_ns_config(global_context, 0);
00415        if (php_request_startup(TSRMLS_C) == FAILURE) {
00416               return NS_ERROR;
00417        }
00418        
00419        php_execute_script(&file_handle TSRMLS_CC);
00420        php_request_shutdown(NULL);
00421 
00422        return NS_OK;
00423 }
00424 
00425 /*
00426  * php_ns_request_ctor() initializes the per-request data structure
00427  * and fills it with data provided by the web server
00428  */
00429 
00430 static void 
00431 php_ns_request_ctor(TSRMLS_D)
00432 {
00433        char *server;
00434        Ns_DString ds;
00435        char *root;
00436        int index;
00437        char *tmp;
00438        
00439        server = Ns_ConnServer(NSG(conn));
00440        
00441 #define safe_strdup(x) ((x)?strdup((x)):NULL)
00442        SG(request_info).query_string = safe_strdup(NSG(conn->request->query));
00443 
00444        Ns_DStringInit(&ds);
00445        Ns_UrlToFile(&ds, server, NSG(conn->request->url));
00446        
00447        /* path_translated is the absolute path to the file */
00448        SG(request_info).path_translated = safe_strdup(Ns_DStringValue(&ds));
00449        Ns_DStringFree(&ds);
00450        root = Ns_PageRoot(server);
00451        SG(request_info).request_uri = strdup(SG(request_info).path_translated + strlen(root));
00452        SG(request_info).request_method = NSG(conn)->request->method;
00453        if(NSG(conn)->request->version > 1.0) SG(request_info).proto_num = 1001;
00454        else SG(request_info).proto_num = 1000;
00455        SG(request_info).content_length = Ns_ConnContentLength(NSG(conn));
00456        index = Ns_SetIFind(NSG(conn)->headers, "content-type");
00457        SG(request_info).content_type = index == -1 ? NULL : 
00458               Ns_SetValue(NSG(conn)->headers, index);
00459        SG(sapi_headers).http_response_code = 200;
00460 
00461        tmp = Ns_ConnAuthUser(NSG(conn));
00462        if (tmp)
00463               tmp = estrdup(tmp);
00464        SG(request_info).auth_user = tmp;
00465 
00466        tmp = Ns_ConnAuthPasswd(NSG(conn));
00467        if (tmp)
00468               tmp = estrdup(tmp);
00469        SG(request_info).auth_password = tmp;
00470 
00471        NSG(data_avail) = SG(request_info).content_length;
00472 }
00473 
00474 /*
00475  * php_ns_request_dtor() destroys all data associated with
00476  * the per-request structure 
00477  */
00478 
00479 static void
00480 php_ns_request_dtor(TSRMLS_D)
00481 {
00482        free(SG(request_info).path_translated);
00483        if (SG(request_info).query_string)
00484               free(SG(request_info).query_string);
00485        free(SG(request_info).request_uri);
00486 }
00487 
00488 /*
00489  * The php_ns_request_handler() is called per request and handles
00490  * everything for one request.
00491  */
00492 
00493 static int
00494 php_ns_request_handler(void *context, Ns_Conn *conn)
00495 {
00496        int status = NS_OK;
00497        TSRMLS_FETCH();
00498        
00499        NSG(conn) = conn;
00500        
00501        SG(server_context) = global_context;
00502 
00503        php_ns_request_ctor(TSRMLS_C);
00504        
00505        status = php_ns_module_main(TSRMLS_C);
00506        
00507        php_ns_request_dtor(TSRMLS_C);
00508 
00509        return status;
00510 }
00511 
00512 /*
00513  * php_ns_config() fetches the configuration data.
00514  *
00515  * It understands the "map" and "php_value" command.
00516  */
00517 
00518 static void 
00519 php_ns_config(php_ns_context *ctx, char global)
00520 {
00521        int i;
00522        char *path;
00523        Ns_Set *set;
00524 
00525        path = Ns_ConfigGetPath(ctx->ns_server, ctx->ns_module, NULL);
00526        set = Ns_ConfigGetSection(path);
00527 
00528        for (i = 0; set && i < Ns_SetSize(set); i++) {
00529               char *key = Ns_SetKey(set, i);
00530               char *value = Ns_SetValue(set, i);
00531 
00532               if (global && !strcasecmp(key, "map")) {
00533                      Ns_Log(Notice, "Registering PHP for \"%s\"", value);
00534                      Ns_RegisterRequest(ctx->ns_server, "GET", value, php_ns_request_handler, NULL, ctx, 0);
00535                      Ns_RegisterRequest(ctx->ns_server, "POST", value, php_ns_request_handler, NULL, ctx, 0);
00536                      Ns_RegisterRequest(ctx->ns_server, "HEAD", value, php_ns_request_handler, NULL, ctx, 0);
00537 
00538        /* 
00539         * Deactivated for now. The ini system will cause random crashes when 
00540         * accessed from here (since there are no locks to protect the global 
00541         * known_directives) 
00542         */
00543 
00544               } else if (!global && !strcasecmp(key, "php_value")) {
00545                      Ns_Log(Notice, "php_value has been deactivated temporarily. Please use a php.ini file to pass directives to PHP. Thanks.");
00546 #if 0
00547                      char *val;
00548 
00549                      val = strchr(value, ' ');
00550                      if (val) {
00551                             char *new_key;
00552                             
00553                             new_key = estrndup(value, val - value);
00554                             
00555                             do { 
00556                                    val++; 
00557                             } while(*val == ' ');
00558 
00559                             Ns_Log(Debug, "PHP configuration option '%s=%s'", new_key, val);
00560                             zend_alter_ini_entry(new_key, strlen(new_key) + 1, val, 
00561                                           strlen(val) + 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
00562                             
00563                             efree(new_key);
00564                      }
00565 #endif
00566               }
00567               
00568        }
00569 }
00570        
00571 /*
00572  * php_ns_server_shutdown() performs the last steps before the
00573  * server exits. Shutdowns basic services and frees memory
00574  */
00575 
00576 static void
00577 php_ns_server_shutdown(void *context)
00578 {
00579        php_ns_context *ctx = (php_ns_context *) context;
00580        
00581        ctx->sapi_module->shutdown(ctx->sapi_module);
00582        sapi_shutdown();
00583        tsrm_shutdown();
00584 
00585        free(ctx->ns_module);
00586        free(ctx->ns_server);
00587        free(ctx);
00588 }
00589 
00590 /*
00591  * Ns_ModuleInit() is called by AOLserver once at startup
00592  *
00593  * This functions allocates basic structures and initializes
00594  * basic services.
00595  */
00596 
00597 int Ns_ModuleInit(char *server, char *module)
00598 {
00599        php_ns_context *ctx;
00600        
00601        tsrm_startup(1, 1, 0, NULL);
00602        sapi_startup(&aolserver_sapi_module);
00603        sapi_module.startup(&aolserver_sapi_module);
00604        
00605        /* TSRM is used to allocate a per-thread structure */
00606        ts_allocate_id(&ns_globals_id, sizeof(ns_globals_struct), NULL, NULL);
00607        
00608        /* the context contains data valid for all threads */
00609        ctx = malloc(sizeof *ctx);
00610        ctx->sapi_module = &aolserver_sapi_module;
00611        ctx->ns_server = strdup(server);
00612        ctx->ns_module = strdup(module);
00613        
00614        /* read the configuration */
00615        php_ns_config(ctx, 1);
00616 
00617        global_context = ctx;
00618 
00619        /* register shutdown handler */
00620        Ns_RegisterServerShutdown(server, php_ns_server_shutdown, ctx);
00621 
00622        return NS_OK;
00623 }
00624 
00625 #endif