File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / continuity / capi.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:35 2012 UTC (12 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_17p0, HEAD
php 5.4.3+patches

    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", "$Id: capi.c,v 1.1.1.2 2012/05/29 12:34:35 misho Exp $");
  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 TSRMLS_DC)
  347: {
  348:    capi_request_context *rc = (capi_request_context *) SG(server_context);
  349:    logFmsg(0, "mod/php: %s", message);
  350: }
  351: 
  352: static int php_capi_startup(sapi_module_struct *sapi_module);
  353: 
  354: sapi_module_struct capi_sapi_module = {
  355:    "Continuity",			/* name */
  356:    "Continuity Server Enterprise Edition",	/* pretty name */
  357: 
  358:    php_capi_startup,		/* startup */
  359:    php_module_shutdown_wrapper,	/* shutdown */
  360: 
  361:    NULL,			/* activate */
  362:    NULL,			/* deactivate */
  363: 
  364:    sapi_capi_ub_write,		/* unbuffered write */
  365:    NULL,			/* flush */
  366:    NULL,			/* get uid */
  367:    NULL,			/* getenv */
  368: 
  369:    php_error,			/* error handler */
  370: 
  371:    sapi_capi_header_handler,	/* header handler */
  372:    sapi_capi_send_headers,	/* send headers handler */
  373:    NULL,			/* send header handler */
  374: 
  375:    sapi_capi_read_post,		/* read POST data */
  376:    sapi_capi_read_cookies,	/* read Cookies */
  377: 
  378:    sapi_capi_register_server_variables,	/* register server variables */
  379:    capi_log_message,		/* Log message */
  380:    NULL,			/* Get request time */
  381:    NULL,			/* Child terminate */
  382: 
  383:    NULL,			/* Block interruptions */
  384:    NULL,			/* Unblock interruptions */
  385: 
  386:    STANDARD_SAPI_MODULE_PROPERTIES
  387: };
  388: 
  389: static int php_capi_startup(sapi_module_struct *sapi_module) {
  390:   if(php_module_startup(sapi_module,&continuity_module_entry,1)==FAILURE) {
  391:     return FAILURE;
  392:   }
  393:   return SUCCESS;
  394: }
  395: 
  396: 
  397: static char *
  398:  capi_strdup(char *str)
  399: {
  400:    if (str != NULL)
  401:       return strFcopy(str);
  402:    return NULL;
  403: }
  404: 
  405: static void capi_free(void *addr)
  406: {
  407:    if (addr != NULL)
  408:       free(addr);
  409: }
  410: 
  411: static void capi_request_ctor(NSLS_D TSRMLS_DC)
  412: {
  413:    char *query_string = lstFset_get(NSG(t->vars), "query");
  414:    char *uri = lstFset_get(NSG(t->vars), "uri");
  415:    char *path_info = lstFset_get(NSG(t->vars), "path-info");
  416:    char *path_translated = lstFset_get(NSG(t->vars), "path");
  417:    char *request_method = lstFset_get(NSG(t->vars), "method");
  418:    char *content_type = lstFset_get(NSG(t->req_hdrs), "content-type");
  419:    char *content_length = lstFset_get(NSG(t->req_hdrs), "content-length");
  420: 
  421:    SG(request_info).query_string = capi_strdup(query_string);
  422:    SG(request_info).request_uri = capi_strdup(uri);
  423:    SG(request_info).request_method = capi_strdup(request_method);
  424:    SG(request_info).path_translated = capi_strdup(path_translated);
  425:    SG(request_info).content_type = capi_strdup(content_type);
  426:    SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
  427:    SG(sapi_headers).http_response_code = 200;
  428: }
  429: 
  430: static void capi_request_dtor(NSLS_D TSRMLS_DC)
  431: {
  432:    capi_free(SG(request_info).query_string);
  433:    capi_free(SG(request_info).request_uri);
  434:    capi_free(SG(request_info).request_method);
  435:    capi_free(SG(request_info).path_translated);
  436:    capi_free(SG(request_info).content_type);
  437: }
  438: 
  439: int capi_module_main(NSLS_D TSRMLS_DC)
  440: {
  441:    zend_file_handle file_handle;
  442: 
  443:    if (php_request_startup(TSRMLS_C) == FAILURE) {
  444:       return FAILURE;
  445:    }
  446:    file_handle.type = ZEND_HANDLE_FILENAME;
  447:    file_handle.filename = SG(request_info).path_translated;
  448:    file_handle.free_filename = 0;
  449:    file_handle.opened_path = NULL;
  450: 
  451:    php_execute_script(&file_handle TSRMLS_CC);
  452:    php_request_shutdown(NULL);
  453: 
  454:    return SUCCESS;
  455: }
  456: 
  457: int phpFinit(lstTset * opt)
  458: {
  459:    php_core_globals *core_globals;
  460: 
  461:    tsrm_startup(128, 1, 0, NULL);
  462:    core_globals = ts_resource(core_globals_id);
  463: 
  464:    logFmsg(0, "mod/php: PHP Interface v3 (module)");
  465:    logFmsg(0, "mod/php: Copyright (c) 1999-2005 The PHP Group. All rights reserved.");
  466: 
  467:    sapi_startup(&capi_sapi_module);
  468:    capi_sapi_module.startup(&capi_sapi_module);
  469: 
  470:    return STATUS_PROCEED;
  471: }
  472: 
  473: int phpFservice(httpTtrans * t, lstTset * opts)
  474: {
  475:    int retval;
  476:    capi_request_context *request_context;
  477: 
  478:    TSRMLS_FETCH();
  479: 
  480:    request_context = (capi_request_context *) malloc(sizeof(capi_request_context));
  481:    request_context->t = t;
  482:    request_context->read_post_bytes = -1;
  483: 
  484:    SG(server_context) = request_context;
  485: 
  486:    capi_request_ctor(NSLS_C TSRMLS_CC);
  487:    retval = capi_module_main(NSLS_C TSRMLS_CC);
  488:    capi_request_dtor(NSLS_C TSRMLS_CC);
  489: 
  490:    free(request_context);
  491: 
  492:    /*
  493:     * This call is ostensibly provided to free the memory from PHP/TSRM when
  494:     * the thread terminated, but, it leaks a structure in some hash list
  495:     * according to the developers. Not calling this will leak the entire
  496:     * interpreter, around 100k, but calling it and then terminating the
  497:     * thread will leak the struct (around a k). The only answer with the
  498:     * current TSRM implementation is to reuse the threads that allocate TSRM
  499:     * resources.
  500:     */
  501:    /* ts_free_thread(); */
  502: 
  503:    if (retval == SUCCESS) {
  504:       return STATUS_EXIT;
  505:    } else {
  506:       return STATUS_ERROR;
  507:    }
  508: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>