Annotation of embedaddon/php/sapi/continuity/capi.c, revision 1.1.1.2

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: 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();
1.1.1.2 ! misho     113:         php_info_print_table_row(2, "Continuity Module Revision", "$Id: 96c39230afa6e73940a9011414341fe43d7566d9 $");
1.1       misho     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: 
1.1.1.2 ! misho     346: static void capi_log_message(char *message TSRMLS_DC)
1.1       misho     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>