123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- /*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2016 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: Alex Leigh <php (at) postfin (dot) com> |
- +----------------------------------------------------------------------+
- */
- /* For more information on Continuity: http://www.ashpool.com/ */
- /*
- * This code is based on the PHP5 SAPI module for NSAPI by Jayakumar
- * Muthukumarasamy
- */
- /* PHP includes */
- #define CONTINUITY 1
- #define CAPI_DEBUG
- /* Define for CDP specific extensions */
- #undef CONTINUITY_CDPEXT
- #include "php.h"
- #include "php_variables.h"
- #include "ext/standard/info.h"
- #include "php_ini.h"
- #include "php_globals.h"
- #include "SAPI.h"
- #include "php_main.h"
- #include "php_version.h"
- #include "TSRM.h"
- #include "ext/standard/php_standard.h"
- /*
- * CAPI includes
- */
- #include <continuity.h>
- #include <http.h>
- #define NSLS_D struct capi_request_context *request_context
- #define NSLS_DC , NSLS_D
- #define NSLS_C request_context
- #define NSLS_CC , NSLS_C
- #define NSG(v) (request_context->v)
- /*
- * ZTS needs to be defined for CAPI to work
- */
- #if !defined(ZTS)
- #error "CAPI module needs ZTS to be defined"
- #endif
- /*
- * Structure to encapsulate the CAPI request in SAPI
- */
- typedef struct capi_request_context {
- httpTtrans *t;
- int read_post_bytes;
- } capi_request_context;
- /**************/
- PHP_MINIT_FUNCTION(continuity);
- PHP_MSHUTDOWN_FUNCTION(continuity);
- PHP_RINIT_FUNCTION(continuity);
- PHP_RSHUTDOWN_FUNCTION(continuity);
- PHP_MINFO_FUNCTION(continuity);
-
- PHP_FUNCTION(continuity_virtual);
- PHP_FUNCTION(continuity_request_headers);
- PHP_FUNCTION(continuity_response_headers);
- const zend_function_entry continuity_functions[] = {
- {NULL, NULL, NULL}
- };
- zend_module_entry continuity_module_entry = {
- STANDARD_MODULE_HEADER,
- "continuity",
- continuity_functions,
- PHP_MINIT(continuity),
- PHP_MSHUTDOWN(continuity),
- NULL,
- NULL,
- PHP_MINFO(continuity),
- NO_VERSION_YET,
- STANDARD_MODULE_PROPERTIES
- };
- PHP_MINIT_FUNCTION(continuity)
- {
- return SUCCESS;
- }
- PHP_MSHUTDOWN_FUNCTION(continuity)
- {
- return SUCCESS;
- }
- PHP_MINFO_FUNCTION(continuity)
- {
- php_info_print_table_start();
- php_info_print_table_row(2, "Continuity Module Revision", "$Id$");
- php_info_print_table_row(2, "Server Version", conFget_build());
- #ifdef CONTINUITY_CDPEXT
- php_info_print_table_row(2,"CDP Extensions", "enabled");
- #else
- php_info_print_table_row(2,"CDP Extensions", "disabled");
- #endif
- php_info_print_table_end();
-
- /* DISPLAY_INI_ENTRIES(); */
- }
- /**************/
- /*
- * sapi_capi_ub_write: Write len bytes to the connection output.
- */
- static int sapi_capi_ub_write(const char *str, unsigned int str_length TSRMLS_DC)
- {
- int retval;
- capi_request_context *rc;
- rc = (capi_request_context *) SG(server_context);
- retval = httpFwrite(rc->t, (char *) str, str_length);
- if (retval == -1 || retval == 0)
- php_handle_aborted_connection();
- return retval;
- }
- /*
- * sapi_capi_header_handler: Add/update response headers with those provided
- * by the PHP engine.
- */
- static int sapi_capi_header_handler(sapi_header_struct * sapi_header, sapi_headers_struct * sapi_headers TSRMLS_DC)
- {
- char *header_name, *header_content, *p;
- capi_request_context *rc = (capi_request_context *) SG(server_context);
- lstFset_delete_key(rc->t->res_hdrs, "Content-Type");
- header_name = sapi_header->header;
- header_content = p = strchr(header_name, ':');
- if (p == NULL) {
- return 0;
- }
- *p = 0;
- do {
- header_content++;
- } while (*header_content == ' ');
- lstFset_add(rc->t->res_hdrs, header_name, header_content);
- *p = ':'; /* restore '*p' */
- efree(sapi_header->header);
- return 0; /* don't use the default SAPI mechanism, CAPI
- * duplicates this functionality */
- }
- /*
- * sapi_capi_send_headers: Transmit the headers to the client. This has the
- * effect of starting the response under Continuity.
- */
- static int sapi_capi_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC)
- {
- int retval;
- capi_request_context *rc = (capi_request_context *) SG(server_context);
- /*
- * We could probably just do this in the header_handler. But, I don't know
- * what the implication of doing it there is.
- */
- if (SG(sapi_headers).send_default_content_type) {
- /* lstFset_delete_key(rc->t->res_hdrs, "Content-Type"); */
- lstFset_update(rc->t->res_hdrs, "Content-Type", "text/html");
- }
- httpFset_status(rc->t, SG(sapi_headers).http_response_code, NULL);
- httpFstart_response(rc->t);
- return SAPI_HEADER_SENT_SUCCESSFULLY;
- }
- static int sapi_capi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
- {
- unsigned int max_read, total_read = 0;
- capi_request_context *rc = (capi_request_context *) SG(server_context);
- if (rc->read_post_bytes == -1) {
- max_read = MIN(count_bytes, SG(request_info).content_length);
- } else {
- if (rc->read_post_bytes == 0)
- return 0;
- max_read = MIN(count_bytes, (SG(request_info).content_length - rc->read_post_bytes));
- }
- total_read = httpFread(rc->t, buffer, max_read);
- if (total_read < 0)
- total_read = -1;
- else
- rc->read_post_bytes = total_read;
- return total_read;
- }
- /*
- * sapi_capi_read_cookies: Return cookie information into PHP.
- */
- static char *sapi_capi_read_cookies(TSRMLS_D)
- {
- char *cookie_string;
- capi_request_context *rc = (capi_request_context *) SG(server_context);
- cookie_string = lstFset_get(rc->t->req_hdrs, "cookie");
- return cookie_string;
- }
- static void sapi_capi_register_server_variables(zval * track_vars_array TSRMLS_DC)
- {
- capi_request_context *rc = (capi_request_context *) SG(server_context);
- size_t i;
- char *value;
- char buf[128];
- /* PHP_SELF and REQUEST_URI */
- value = lstFset_get(rc->t->vars, "uri");
- if (value != NULL) {
- php_register_variable("PHP_SELF", value, track_vars_array TSRMLS_CC);
- php_register_variable("REQUEST_URI", value, track_vars_array TSRMLS_CC);
- }
-
- /* COUNTRY CODE */
- value = lstFset_get(rc->t->vars, "ccode");
- if(value!=NULL)
- php_register_variable("COUNTRY_CODE", value, track_vars_array TSRMLS_CC);
- /* argv */
- value = lstFset_get(rc->t->vars, "query");
- if (value != NULL)
- php_register_variable("argv", value, track_vars_array TSRMLS_CC);
- /* GATEWAY_INTERFACE */
- php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
- /* SERVER_NAME and HTTP_HOST */
- value = lstFset_get(rc->t->req_hdrs, "host");
- if (value != NULL) {
- php_register_variable("HTTP_HOST", value, track_vars_array TSRMLS_CC);
- /* TODO: This should probably scrub the port value if one is present. */
- php_register_variable("SERVER_NAME", value, track_vars_array TSRMLS_CC);
- }
- /* SERVER_SOFTWARE */
- value = lstFset_get(rc->t->res_hdrs, "Server");
- if (value != NULL)
- php_register_variable("SERVER_SOFTWARE", value, track_vars_array TSRMLS_CC);
- /* SERVER_PROTOCOL */
- value = lstFset_get(rc->t->vars, "protocol");
- if (value != NULL)
- php_register_variable("SERVER_PROTOCOL", value, track_vars_array TSRMLS_CC);
- /* REQUEST_METHOD */
- value = lstFset_get(rc->t->vars, "method");
- if (value != NULL)
- php_register_variable("REQUEST_METHOD", value, track_vars_array TSRMLS_CC);
- /* QUERY_STRING */
- value = lstFset_get(rc->t->vars, "query");
- if (value != NULL)
- php_register_variable("QUERY_STRING", value, track_vars_array TSRMLS_CC);
- /* DOCUMENT_ROOT */
- value = lstFset_get(rc->t->vars, "docroot");
- if (value != NULL)
- php_register_variable("DOCUMENT_ROOT", value, track_vars_array TSRMLS_CC);
- /* HTTP_ACCEPT */
- value = lstFset_get(rc->t->req_hdrs, "accept");
- if (value != NULL)
- php_register_variable("HTTP_ACCEPT", value, track_vars_array TSRMLS_CC);
- /* HTTP_ACCEPT_CHARSET */
- value = lstFset_get(rc->t->req_hdrs, "accept-charset");
- if (value != NULL)
- php_register_variable("HTTP_ACCEPT_CHARSET", value, track_vars_array TSRMLS_CC);
- /* HTTP_ACCEPT_ENCODING */
- value = lstFset_get(rc->t->req_hdrs, "accept-encoding");
- if (value != NULL)
- php_register_variable("HTTP_ACCEPT_ENCODING", value, track_vars_array TSRMLS_CC);
- /* HTTP_ACCEPT_LANGUAGE */
- value = lstFset_get(rc->t->req_hdrs, "accept-language");
- if (value != NULL)
- php_register_variable("HTTP_ACCEPT_LANGUAGE", value, track_vars_array TSRMLS_CC);
- /* HTTP_CONNECTION */
- value = lstFset_get(rc->t->req_hdrs, "connection");
- if (value != NULL)
- php_register_variable("HTTP_CONNECTION", value, track_vars_array TSRMLS_CC);
- /* HTTP_REFERER */
- value = lstFset_get(rc->t->req_hdrs, "referer");
- if (value != NULL)
- php_register_variable("HTTP_REFERER", value, track_vars_array TSRMLS_CC);
- /* HTTP_USER_AGENT */
- value = lstFset_get(rc->t->req_hdrs, "user-agent");
- if (value != NULL)
- php_register_variable("HTTP_USER_AGENT", value, track_vars_array TSRMLS_CC);
- /* REMOTE_ADDR */
- utlFip_to_str(rc->t->cli_ipv4_addr, buf, sizeof(buf));
- php_register_variable("REMOTE_ADDR", buf, track_vars_array TSRMLS_CC);
- /* REMOTE_PORT */
- /* SCRIPT_FILENAME and PATH_TRANSLATED */
- value = lstFset_get(rc->t->vars, "path");
- if (value != NULL) {
- php_register_variable("SCRIPT_FILENAME", value, track_vars_array TSRMLS_CC);
- php_register_variable("PATH_TRANSLATED", value, track_vars_array TSRMLS_CC);
- }
- /* SERVER_ADMIN */
- /* Not applicable */
- /* SERVER_PORT */
- }
- static void capi_log_message(char *message TSRMLS_DC)
- {
- capi_request_context *rc = (capi_request_context *) SG(server_context);
- logFmsg(0, "mod/php: %s", message);
- }
- static int php_capi_startup(sapi_module_struct *sapi_module);
- sapi_module_struct capi_sapi_module = {
- "Continuity", /* name */
- "Continuity Server Enterprise Edition", /* pretty name */
- php_capi_startup, /* startup */
- php_module_shutdown_wrapper, /* shutdown */
- NULL, /* activate */
- NULL, /* deactivate */
- sapi_capi_ub_write, /* unbuffered write */
- NULL, /* flush */
- NULL, /* get uid */
- NULL, /* getenv */
- php_error, /* error handler */
- sapi_capi_header_handler, /* header handler */
- sapi_capi_send_headers, /* send headers handler */
- NULL, /* send header handler */
- sapi_capi_read_post, /* read POST data */
- sapi_capi_read_cookies, /* read Cookies */
- sapi_capi_register_server_variables, /* register server variables */
- capi_log_message, /* Log message */
- NULL, /* Get request time */
- NULL, /* Child terminate */
- NULL, /* Block interruptions */
- NULL, /* Unblock interruptions */
- STANDARD_SAPI_MODULE_PROPERTIES
- };
- static int php_capi_startup(sapi_module_struct *sapi_module) {
- if(php_module_startup(sapi_module,&continuity_module_entry,1)==FAILURE) {
- return FAILURE;
- }
- return SUCCESS;
- }
- static char *
- capi_strdup(char *str)
- {
- if (str != NULL)
- return strFcopy(str);
- return NULL;
- }
- static void capi_free(void *addr)
- {
- if (addr != NULL)
- free(addr);
- }
- static void capi_request_ctor(NSLS_D TSRMLS_DC)
- {
- char *query_string = lstFset_get(NSG(t->vars), "query");
- char *uri = lstFset_get(NSG(t->vars), "uri");
- char *path_info = lstFset_get(NSG(t->vars), "path-info");
- char *path_translated = lstFset_get(NSG(t->vars), "path");
- char *request_method = lstFset_get(NSG(t->vars), "method");
- char *content_type = lstFset_get(NSG(t->req_hdrs), "content-type");
- char *content_length = lstFset_get(NSG(t->req_hdrs), "content-length");
- SG(request_info).query_string = capi_strdup(query_string);
- SG(request_info).request_uri = capi_strdup(uri);
- SG(request_info).request_method = capi_strdup(request_method);
- SG(request_info).path_translated = capi_strdup(path_translated);
- SG(request_info).content_type = capi_strdup(content_type);
- SG(request_info).content_length = (content_length == NULL) ? 0 : strtoul(content_length, 0, 0);
- SG(sapi_headers).http_response_code = 200;
- }
- static void capi_request_dtor(NSLS_D TSRMLS_DC)
- {
- capi_free(SG(request_info).query_string);
- capi_free(SG(request_info).request_uri);
- capi_free(SG(request_info).request_method);
- capi_free(SG(request_info).path_translated);
- capi_free(SG(request_info).content_type);
- }
- int capi_module_main(NSLS_D TSRMLS_DC)
- {
- zend_file_handle file_handle;
- if (php_request_startup(TSRMLS_C) == FAILURE) {
- return FAILURE;
- }
- file_handle.type = ZEND_HANDLE_FILENAME;
- file_handle.filename = SG(request_info).path_translated;
- file_handle.free_filename = 0;
- file_handle.opened_path = NULL;
- php_execute_script(&file_handle TSRMLS_CC);
- php_request_shutdown(NULL);
- return SUCCESS;
- }
- int phpFinit(lstTset * opt)
- {
- php_core_globals *core_globals;
- tsrm_startup(128, 1, 0, NULL);
- core_globals = ts_resource(core_globals_id);
- logFmsg(0, "mod/php: PHP Interface v3 (module)");
- logFmsg(0, "mod/php: Copyright (c) 1999-2016 The PHP Group. All rights reserved.");
- sapi_startup(&capi_sapi_module);
- capi_sapi_module.startup(&capi_sapi_module);
- return STATUS_PROCEED;
- }
- int phpFservice(httpTtrans * t, lstTset * opts)
- {
- int retval;
- capi_request_context *request_context;
- TSRMLS_FETCH();
- request_context = (capi_request_context *) malloc(sizeof(capi_request_context));
- request_context->t = t;
- request_context->read_post_bytes = -1;
- SG(server_context) = request_context;
- capi_request_ctor(NSLS_C TSRMLS_CC);
- retval = capi_module_main(NSLS_C TSRMLS_CC);
- capi_request_dtor(NSLS_C TSRMLS_CC);
- free(request_context);
- /*
- * This call is ostensibly provided to free the memory from PHP/TSRM when
- * the thread terminated, but, it leaks a structure in some hash list
- * according to the developers. Not calling this will leak the entire
- * interpreter, around 100k, but calling it and then terminating the
- * thread will leak the struct (around a k). The only answer with the
- * current TSRM implementation is to reuse the threads that allocate TSRM
- * resources.
- */
- /* ts_free_thread(); */
- if (retval == SUCCESS) {
- return STATUS_EXIT;
- } else {
- return STATUS_ERROR;
- }
- }
|