root/sapi/continuity/capi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_MINIT_FUNCTION
  2. PHP_MSHUTDOWN_FUNCTION
  3. PHP_MINFO_FUNCTION
  4. sapi_capi_ub_write
  5. sapi_capi_header_handler
  6. sapi_capi_send_headers
  7. sapi_capi_read_post
  8. sapi_capi_read_cookies
  9. sapi_capi_register_server_variables
  10. capi_log_message
  11. php_capi_startup
  12. capi_strdup
  13. capi_free
  14. capi_request_ctor
  15. capi_request_dtor
  16. capi_module_main
  17. phpFinit
  18. phpFservice

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 5                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 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: 56ead374990d554956cb24fc788773a42f46d2c0 $");
 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-2016 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 }

/* [<][>][^][v][top][bottom][index][help] */