Back to index

php5  5.3.10
capi.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: Alex Leigh <php (at) postfin (dot) com>                      |
00016   +----------------------------------------------------------------------+
00017 */
00018 
00019 /* For more information on Continuity: http://www.ashpool.com/ */
00020 
00021 /*
00022  * This code is based on the PHP5 SAPI module for NSAPI by Jayakumar
00023  * Muthukumarasamy
00024  */
00025 
00026 /* PHP includes */
00027 #define CONTINUITY 1
00028 #define CAPI_DEBUG
00029 
00030 /* Define for CDP specific extensions */
00031 #undef CONTINUITY_CDPEXT
00032 
00033 #include "php.h"
00034 #include "php_variables.h"
00035 #include "ext/standard/info.h"
00036 #include "php_ini.h"
00037 #include "php_globals.h"
00038 #include "SAPI.h"
00039 #include "php_main.h"
00040 #include "php_version.h"
00041 #include "TSRM.h"
00042 #include "ext/standard/php_standard.h"
00043 
00044 /*
00045  * CAPI includes
00046  */
00047 #include <continuity.h>
00048 #include <http.h>
00049 
00050 #define NSLS_D              struct capi_request_context *request_context
00051 #define NSLS_DC             , NSLS_D
00052 #define NSLS_C              request_context
00053 #define NSLS_CC             , NSLS_C
00054 #define NSG(v)              (request_context->v)
00055 
00056 /*
00057  * ZTS needs to be defined for CAPI to work
00058  */
00059 #if !defined(ZTS)
00060 #error "CAPI module needs ZTS to be defined"
00061 #endif
00062 
00063 /*
00064  * Structure to encapsulate the CAPI request in SAPI
00065  */
00066 typedef struct capi_request_context {
00067    httpTtrans *t;
00068    int read_post_bytes;
00069 } capi_request_context;
00070 
00071 /**************/
00072 
00073 PHP_MINIT_FUNCTION(continuity);
00074 PHP_MSHUTDOWN_FUNCTION(continuity);
00075 PHP_RINIT_FUNCTION(continuity);
00076 PHP_RSHUTDOWN_FUNCTION(continuity);
00077 PHP_MINFO_FUNCTION(continuity);
00078         
00079 PHP_FUNCTION(continuity_virtual);
00080 PHP_FUNCTION(continuity_request_headers);
00081 PHP_FUNCTION(continuity_response_headers);
00082 
00083 const zend_function_entry continuity_functions[] = {
00084         {NULL, NULL, NULL}
00085 };
00086 
00087 zend_module_entry continuity_module_entry = {
00088         STANDARD_MODULE_HEADER,
00089         "continuity",
00090         continuity_functions,   
00091         PHP_MINIT(continuity),
00092         PHP_MSHUTDOWN(continuity),
00093         NULL,
00094         NULL,
00095         PHP_MINFO(continuity),
00096         NO_VERSION_YET,
00097         STANDARD_MODULE_PROPERTIES
00098 };
00099 
00100 PHP_MINIT_FUNCTION(continuity)
00101 {
00102         return SUCCESS;
00103 }
00104 
00105 PHP_MSHUTDOWN_FUNCTION(continuity)
00106 {
00107         return SUCCESS;
00108 }
00109 
00110 PHP_MINFO_FUNCTION(continuity)
00111 {
00112         php_info_print_table_start();
00113         php_info_print_table_row(2, "Continuity Module Revision", "$Revision: 321634 $");
00114         php_info_print_table_row(2, "Server Version", conFget_build());
00115 #ifdef CONTINUITY_CDPEXT
00116        php_info_print_table_row(2,"CDP Extensions", "enabled");
00117 #else
00118        php_info_print_table_row(2,"CDP Extensions", "disabled");
00119 #endif
00120         php_info_print_table_end();
00121         
00122 /*        DISPLAY_INI_ENTRIES(); */
00123 }
00124 
00125 /**************/
00126 
00127 /*
00128  * sapi_capi_ub_write: Write len bytes to the connection output.
00129  */
00130 static int sapi_capi_ub_write(const char *str, unsigned int str_length TSRMLS_DC)
00131 {
00132    int retval;
00133    capi_request_context *rc;
00134 
00135    rc = (capi_request_context *) SG(server_context);
00136    retval = httpFwrite(rc->t, (char *) str, str_length);
00137    if (retval == -1 || retval == 0)
00138       php_handle_aborted_connection();
00139    return retval;
00140 }
00141 
00142 /*
00143  * sapi_capi_header_handler: Add/update response headers with those provided
00144  * by the PHP engine.
00145  */
00146 static int sapi_capi_header_handler(sapi_header_struct * sapi_header, sapi_headers_struct * sapi_headers TSRMLS_DC)
00147 {
00148    char *header_name, *header_content, *p;
00149    capi_request_context *rc = (capi_request_context *) SG(server_context);
00150 
00151    lstFset_delete_key(rc->t->res_hdrs, "Content-Type");
00152 
00153    header_name = sapi_header->header;
00154    header_content = p = strchr(header_name, ':');
00155    if (p == NULL) {
00156       return 0;
00157    }
00158    *p = 0;
00159    do {
00160       header_content++;
00161    } while (*header_content == ' ');
00162 
00163    lstFset_add(rc->t->res_hdrs, header_name, header_content);
00164 
00165    *p = ':';                /* restore '*p' */
00166 
00167    efree(sapi_header->header);
00168 
00169    return 0;                /* don't use the default SAPI mechanism, CAPI
00170                              * duplicates this functionality */
00171 }
00172 
00173 /*
00174  * sapi_capi_send_headers: Transmit the headers to the client. This has the
00175  * effect of starting the response under Continuity.
00176  */
00177 static int sapi_capi_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC)
00178 {
00179    int retval;
00180    capi_request_context *rc = (capi_request_context *) SG(server_context);
00181 
00182    /*
00183     * We could probably just do this in the header_handler. But, I don't know
00184     * what the implication of doing it there is.
00185     */
00186 
00187    if (SG(sapi_headers).send_default_content_type) {
00188       /* lstFset_delete_key(rc->t->res_hdrs, "Content-Type"); */
00189       lstFset_update(rc->t->res_hdrs, "Content-Type", "text/html");
00190    }
00191    httpFset_status(rc->t, SG(sapi_headers).http_response_code, NULL);
00192    httpFstart_response(rc->t);
00193 
00194    return SAPI_HEADER_SENT_SUCCESSFULLY;
00195 
00196 }
00197 
00198 static int sapi_capi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
00199 {
00200    unsigned int max_read, total_read = 0;
00201    capi_request_context *rc = (capi_request_context *) SG(server_context);
00202 
00203    if (rc->read_post_bytes == -1) {
00204       max_read = MIN(count_bytes, SG(request_info).content_length);
00205    } else {
00206       if (rc->read_post_bytes == 0)
00207         return 0;
00208       max_read = MIN(count_bytes, (SG(request_info).content_length - rc->read_post_bytes));
00209    }
00210 
00211    total_read = httpFread(rc->t, buffer, max_read);
00212 
00213    if (total_read < 0)
00214       total_read = -1;
00215    else
00216       rc->read_post_bytes = total_read;
00217 
00218    return total_read;
00219 }
00220 
00221 /*
00222  * sapi_capi_read_cookies: Return cookie information into PHP.
00223  */
00224 static char *sapi_capi_read_cookies(TSRMLS_D)
00225 {
00226    char *cookie_string;
00227    capi_request_context *rc = (capi_request_context *) SG(server_context);
00228 
00229    cookie_string = lstFset_get(rc->t->req_hdrs, "cookie");
00230    return cookie_string;
00231 }
00232 
00233 static void sapi_capi_register_server_variables(zval * track_vars_array TSRMLS_DC)
00234 {
00235    capi_request_context *rc = (capi_request_context *) SG(server_context);
00236    size_t i;
00237    char *value;
00238    char buf[128];
00239 
00240    /* PHP_SELF and REQUEST_URI */
00241    value = lstFset_get(rc->t->vars, "uri");
00242    if (value != NULL) {
00243       php_register_variable("PHP_SELF", value, track_vars_array TSRMLS_CC);
00244       php_register_variable("REQUEST_URI", value, track_vars_array TSRMLS_CC);
00245    }
00246  
00247    /* COUNTRY CODE */
00248    value = lstFset_get(rc->t->vars, "ccode");
00249    if(value!=NULL)
00250      php_register_variable("COUNTRY_CODE", value, track_vars_array TSRMLS_CC);
00251 
00252    /* argv */
00253    value = lstFset_get(rc->t->vars, "query");
00254    if (value != NULL)
00255       php_register_variable("argv", value, track_vars_array TSRMLS_CC);
00256 
00257    /* GATEWAY_INTERFACE */
00258    php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
00259 
00260    /* SERVER_NAME and HTTP_HOST */
00261    value = lstFset_get(rc->t->req_hdrs, "host");
00262    if (value != NULL) {
00263       php_register_variable("HTTP_HOST", value, track_vars_array TSRMLS_CC);
00264       /* TODO: This should probably scrub the port value if one is present. */
00265       php_register_variable("SERVER_NAME", value, track_vars_array TSRMLS_CC);
00266    }
00267    /* SERVER_SOFTWARE */
00268    value = lstFset_get(rc->t->res_hdrs, "Server");
00269    if (value != NULL)
00270       php_register_variable("SERVER_SOFTWARE", value, track_vars_array TSRMLS_CC);
00271 
00272    /* SERVER_PROTOCOL */
00273    value = lstFset_get(rc->t->vars, "protocol");
00274    if (value != NULL)
00275       php_register_variable("SERVER_PROTOCOL", value, track_vars_array TSRMLS_CC);
00276 
00277    /* REQUEST_METHOD */
00278    value = lstFset_get(rc->t->vars, "method");
00279    if (value != NULL)
00280       php_register_variable("REQUEST_METHOD", value, track_vars_array TSRMLS_CC);
00281 
00282    /* QUERY_STRING */
00283    value = lstFset_get(rc->t->vars, "query");
00284    if (value != NULL)
00285       php_register_variable("QUERY_STRING", value, track_vars_array TSRMLS_CC);
00286 
00287    /* DOCUMENT_ROOT */
00288    value = lstFset_get(rc->t->vars, "docroot");
00289    if (value != NULL)
00290       php_register_variable("DOCUMENT_ROOT", value, track_vars_array TSRMLS_CC);
00291 
00292    /* HTTP_ACCEPT */
00293    value = lstFset_get(rc->t->req_hdrs, "accept");
00294    if (value != NULL)
00295       php_register_variable("HTTP_ACCEPT", value, track_vars_array TSRMLS_CC);
00296 
00297    /* HTTP_ACCEPT_CHARSET */
00298    value = lstFset_get(rc->t->req_hdrs, "accept-charset");
00299    if (value != NULL)
00300       php_register_variable("HTTP_ACCEPT_CHARSET", value, track_vars_array TSRMLS_CC);
00301 
00302    /* HTTP_ACCEPT_ENCODING */
00303    value = lstFset_get(rc->t->req_hdrs, "accept-encoding");
00304    if (value != NULL)
00305       php_register_variable("HTTP_ACCEPT_ENCODING", value, track_vars_array TSRMLS_CC);
00306 
00307    /* HTTP_ACCEPT_LANGUAGE */
00308    value = lstFset_get(rc->t->req_hdrs, "accept-language");
00309    if (value != NULL)
00310       php_register_variable("HTTP_ACCEPT_LANGUAGE", value, track_vars_array TSRMLS_CC);
00311 
00312    /* HTTP_CONNECTION */
00313    value = lstFset_get(rc->t->req_hdrs, "connection");
00314    if (value != NULL)
00315       php_register_variable("HTTP_CONNECTION", value, track_vars_array TSRMLS_CC);
00316 
00317    /* HTTP_REFERER */
00318    value = lstFset_get(rc->t->req_hdrs, "referer");
00319    if (value != NULL)
00320       php_register_variable("HTTP_REFERER", value, track_vars_array TSRMLS_CC);
00321 
00322    /* HTTP_USER_AGENT */
00323    value = lstFset_get(rc->t->req_hdrs, "user-agent");
00324    if (value != NULL)
00325       php_register_variable("HTTP_USER_AGENT", value, track_vars_array TSRMLS_CC);
00326 
00327    /* REMOTE_ADDR */
00328    utlFip_to_str(rc->t->cli_ipv4_addr, buf, sizeof(buf));
00329    php_register_variable("REMOTE_ADDR", buf, track_vars_array TSRMLS_CC);
00330 
00331    /* REMOTE_PORT */
00332 
00333    /* SCRIPT_FILENAME and PATH_TRANSLATED */
00334    value = lstFset_get(rc->t->vars, "path");
00335    if (value != NULL) {
00336       php_register_variable("SCRIPT_FILENAME", value, track_vars_array TSRMLS_CC);
00337       php_register_variable("PATH_TRANSLATED", value, track_vars_array TSRMLS_CC);
00338    }
00339    /* SERVER_ADMIN */
00340    /* Not applicable */
00341 
00342    /* SERVER_PORT */
00343 
00344 }
00345 
00346 static void capi_log_message(char *message)
00347 {
00348    TSRMLS_FETCH();
00349    capi_request_context *rc = (capi_request_context *) SG(server_context);
00350    logFmsg(0, "mod/php: %s", message);
00351 }
00352 
00353 static int php_capi_startup(sapi_module_struct *sapi_module);
00354 
00355 sapi_module_struct capi_sapi_module = {
00356    "Continuity",                   /* name */
00357    "Continuity Server Enterprise Edition",       /* pretty name */
00358 
00359    php_capi_startup,        /* startup */
00360    php_module_shutdown_wrapper,    /* shutdown */
00361 
00362    NULL,                    /* activate */
00363    NULL,                    /* deactivate */
00364 
00365    sapi_capi_ub_write,             /* unbuffered write */
00366    NULL,                    /* flush */
00367    NULL,                    /* get uid */
00368    NULL,                    /* getenv */
00369 
00370    php_error,               /* error handler */
00371 
00372    sapi_capi_header_handler,       /* header handler */
00373    sapi_capi_send_headers,  /* send headers handler */
00374    NULL,                    /* send header handler */
00375 
00376    sapi_capi_read_post,            /* read POST data */
00377    sapi_capi_read_cookies,  /* read Cookies */
00378 
00379    sapi_capi_register_server_variables,   /* register server variables */
00380    capi_log_message,        /* Log message */
00381    NULL,                    /* Get request time */
00382    NULL,                    /* Child terminate */
00383 
00384    NULL,                    /* Block interruptions */
00385    NULL,                    /* Unblock interruptions */
00386 
00387    STANDARD_SAPI_MODULE_PROPERTIES
00388 };
00389 
00390 static int php_capi_startup(sapi_module_struct *sapi_module) {
00391   if(php_module_startup(sapi_module,&continuity_module_entry,1)==FAILURE) {
00392     return FAILURE;
00393   }
00394   return SUCCESS;
00395 }
00396 
00397 
00398 static char *
00399  capi_strdup(char *str)
00400 {
00401    if (str != NULL)
00402       return strFcopy(str);
00403    return NULL;
00404 }
00405 
00406 static void capi_free(void *addr)
00407 {
00408    if (addr != NULL)
00409       free(addr);
00410 }
00411 
00412 static void capi_request_ctor(NSLS_D TSRMLS_DC)
00413 {
00414    char *query_string = lstFset_get(NSG(t->vars), "query");
00415    char *uri = lstFset_get(NSG(t->vars), "uri");
00416    char *path_info = lstFset_get(NSG(t->vars), "path-info");
00417    char *path_translated = lstFset_get(NSG(t->vars), "path");
00418    char *request_method = lstFset_get(NSG(t->vars), "method");
00419    char *content_type = lstFset_get(NSG(t->req_hdrs), "content-type");
00420    char *content_length = lstFset_get(NSG(t->req_hdrs), "content-length");
00421 
00422    SG(request_info).query_string = capi_strdup(query_string);
00423    SG(request_info).request_uri = capi_strdup(uri);
00424    SG(request_info).request_method = capi_strdup(request_method);
00425    SG(request_info).path_translated = capi_strdup(path_translated);
00426    SG(request_info).content_type = capi_strdup(content_type);
00427    SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
00428    SG(sapi_headers).http_response_code = 200;
00429 }
00430 
00431 static void capi_request_dtor(NSLS_D TSRMLS_DC)
00432 {
00433    capi_free(SG(request_info).query_string);
00434    capi_free(SG(request_info).request_uri);
00435    capi_free(SG(request_info).request_method);
00436    capi_free(SG(request_info).path_translated);
00437    capi_free(SG(request_info).content_type);
00438 }
00439 
00440 int capi_module_main(NSLS_D TSRMLS_DC)
00441 {
00442    zend_file_handle file_handle;
00443 
00444    if (php_request_startup(TSRMLS_C) == FAILURE) {
00445       return FAILURE;
00446    }
00447    file_handle.type = ZEND_HANDLE_FILENAME;
00448    file_handle.filename = SG(request_info).path_translated;
00449    file_handle.free_filename = 0;
00450    file_handle.opened_path = NULL;
00451 
00452    php_execute_script(&file_handle TSRMLS_CC);
00453    php_request_shutdown(NULL);
00454 
00455    return SUCCESS;
00456 }
00457 
00458 int phpFinit(lstTset * opt)
00459 {
00460    php_core_globals *core_globals;
00461 
00462    tsrm_startup(128, 1, 0, NULL);
00463    core_globals = ts_resource(core_globals_id);
00464 
00465    logFmsg(0, "mod/php: PHP Interface v3 (module)");
00466    logFmsg(0, "mod/php: Copyright (c) 1999-2005 The PHP Group. All rights reserved.");
00467 
00468    sapi_startup(&capi_sapi_module);
00469    capi_sapi_module.startup(&capi_sapi_module);
00470 
00471    return STATUS_PROCEED;
00472 }
00473 
00474 int phpFservice(httpTtrans * t, lstTset * opts)
00475 {
00476    int retval;
00477    capi_request_context *request_context;
00478 
00479    TSRMLS_FETCH();
00480 
00481    request_context = (capi_request_context *) malloc(sizeof(capi_request_context));
00482    request_context->t = t;
00483    request_context->read_post_bytes = -1;
00484 
00485    SG(server_context) = request_context;
00486 
00487    capi_request_ctor(NSLS_C TSRMLS_CC);
00488    retval = capi_module_main(NSLS_C TSRMLS_CC);
00489    capi_request_dtor(NSLS_C TSRMLS_CC);
00490 
00491    free(request_context);
00492 
00493    /*
00494     * This call is ostensibly provided to free the memory from PHP/TSRM when
00495     * the thread terminated, but, it leaks a structure in some hash list
00496     * according to the developers. Not calling this will leak the entire
00497     * interpreter, around 100k, but calling it and then terminating the
00498     * thread will leak the struct (around a k). The only answer with the
00499     * current TSRM implementation is to reuse the threads that allocate TSRM
00500     * resources.
00501     */
00502    /* ts_free_thread(); */
00503 
00504    if (retval == SUCCESS) {
00505       return STATUS_EXIT;
00506    } else {
00507       return STATUS_ERROR;
00508    }
00509 }