diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-03-14 05:42:27 +0000 |
---|---|---|
committer | <> | 2013-04-03 16:25:08 +0000 |
commit | c4dd7a1a684490673e25aaf4fabec5df138854c4 (patch) | |
tree | 4d57c44caae4480efff02b90b9be86f44bf25409 /sapi/litespeed | |
download | php2-master.tar.gz |
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'sapi/litespeed')
-rw-r--r-- | sapi/litespeed/CREDITS | 2 | ||||
-rw-r--r-- | sapi/litespeed/Makefile.frag | 9 | ||||
-rw-r--r-- | sapi/litespeed/README | 225 | ||||
-rw-r--r-- | sapi/litespeed/config.m4 | 31 | ||||
-rw-r--r-- | sapi/litespeed/lsapi_main.c | 1118 | ||||
-rw-r--r-- | sapi/litespeed/lsapidef.h | 196 | ||||
-rw-r--r-- | sapi/litespeed/lsapilib.c | 2227 | ||||
-rw-r--r-- | sapi/litespeed/lsapilib.h | 363 |
8 files changed, 4171 insertions, 0 deletions
diff --git a/sapi/litespeed/CREDITS b/sapi/litespeed/CREDITS new file mode 100644 index 0000000..2fa192e --- /dev/null +++ b/sapi/litespeed/CREDITS @@ -0,0 +1,2 @@ +litespeed +George Wang diff --git a/sapi/litespeed/Makefile.frag b/sapi/litespeed/Makefile.frag new file mode 100644 index 0000000..b70e5e8 --- /dev/null +++ b/sapi/litespeed/Makefile.frag @@ -0,0 +1,9 @@ +litespeed: $(SAPI_LITESPEED_PATH) + +$(SAPI_LITESPEED_PATH): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_LITESPEED_OBJS) + $(BUILD_LITESPEED) + +install-litespeed: $(SAPI_LITESPEED_PATH) + @echo "Installing PHP LitSpeed binary: $(INSTALL_ROOT)$(bindir)/" + @$(INSTALL) -m 0755 $(SAPI_LITESPEED_PATH) $(INSTALL_ROOT)$(bindir)/lsphp + diff --git a/sapi/litespeed/README b/sapi/litespeed/README new file mode 100644 index 0000000..e548ec9 --- /dev/null +++ b/sapi/litespeed/README @@ -0,0 +1,225 @@ +Introduction +============ + +LiteSpeed SAPI module is a dedicated interface for PHP integration with +LiteSpeed Web Server. LiteSpeed SAPI has similar architecture to the +FastCGI SAPI with there major enhancements: better performance, dynamic +spawning and PHP configuration modification through web server +configuration and .htaccess files. + +Our simple benchmark test ("hello world") shows that PHP with +LiteSpeed SAPI has 30% better performance over PHP with FastCGI SAPI, +which is nearly twice the performance that Apache mod_php can deliver. + +A major drawback of FastCGI PHP comparing to Apache mod_php is lacking +the flexibilities in PHP configurations. PHP configurations cannot be +changed at runtime via configuration files like .htaccess files or web +server's virtual host configuration. In shared hosting environment, +each hosting account will has its own "open_basedir" overridden in +server configuration to enhance server security when mod_php is used. +usually, FastCGI PHP is not an option in shared hosting environment +due to lacking of this flexibility. LiteSpeed SAPI is carefully designed +to address this issue. PHP configurations can be modified the same way +as that in mod_php with the same configuration directives. + +PHP with LiteSpeed SAPI is highly recommended over FastCGI PHP for +PHP scripting with LiteSpeed web server. + + +Building PHP with LiteSpeed SAPI +================================ + +You need to add "--with-litespeed" to the configure command to build +PHP with LiteSpeed SAPI, all other SAPI related configure options +should be removed. + +For example: + ./configure --with-litespeed + make + +You should find an executable called 'php' under sapi/litespeed/ +directory after the compilation succeeds. Copy it to +'lsws/fcgi-bin/lsphp' or wherever you prefer, if LiteSpeed web server +has been configured to run PHP with LiteSpeed SAPI already, you just +need to overwrite the old executable with this one and you are all +set. + +Start PHP from command line +=========================== + +Usually, lsphp is managed by LiteSpeed web server in a single server +installation. lsphp can be used in clustered environment with one +LiteSpeed web server at the front, load balancing lsphp processes +running on multiple backend servers. In such environment, lsphp can be +start manually from command with option "-b <socket_address>", socket +address can be IPv4, IPv6 or Unix Domain Socket address. +for example: + + ./lsphp -b [::]:3000 + +have lsphp bind to port 3000 on all IPv4 and IPv6 address, + + ./lsphp -b *:3000 + +have lsphp bind to port 300 on all IPv4 address. + + ./lsphp -b 192.168.0.2:3000 + +have lsphp bind to address 192.168.0.2:3000. + + ./lsphp -b /tmp/lsphp_manual.sock + +have lsphp accept request on Unix domain socket "/tmp/lsphp_manual.sock" + + +Using LiteSpeed PHP with LiteSpeed Web Server +============================================= + +Detailed information about how to configure LiteSpeed web server with +PHP support is available from our website, at: + +http://www.litespeedtech.com/docs/HowTo_QA.html + +Usually, PHP support has been configured out of box, you don't need to +change it unless you want to change PHP interface from FastCGI to +LiteSpeed SAPI or vice versa. + +Brief instructions are as follow: + +1) Login to web administration interface, go to 'Server'->'Ext App' tab, + add an external application of type "LSAPI app", "Command" should be + set to a shell command that executes the PHP binary you just built. + "Instances" should be set to "1". Add "LSAPI_CHILDREN" environment + variable to match the value of "Max Connections". More tunable + environment variable described below can be added. + +2) Go to 'Server'->'Script Handler' tab, add a script handler + configuration: set 'suffix' to 'php', 'Handler Type' to 'LiteSpeed + API', 'Handler Name' should be the name of external application + just defined. + + +3) Click 'Apply Changes' link on the top left of the page, then click + 'graceful restart'. Now PHP is running with LiteSpeed SAPI. + +Tunings +------- + +There are a few environment variables that can be tweaked to control the +behavior of LSAPI application. + +* LSAPI_CHILDREN or PHP_LSAPI_CHILDREN (default: 0) + +There are two ways to let PHP handle multiple requests concurrently, +Server Managed Mode and Self Managed Mode. In Server Managed Mode, +LiteSpeed web server dynamically spawn/stop PHP processes, in this mode +"Instances" should match "Max Connections" configuration for PHP +external application. To start PHP in Self Managed Mode, "Instances" +should be set to "1", while "LSAPI_CHILDREN" environment variable should +be set to match the value of "Max Connections" and >1. Web Server will +start one PHP process, this process will start/stop children PHP processes +dynamically based on on demand. If "LSAPI_CHILDREN" <=1, PHP will be +started in server managed mode. + +Self Managed Mode is preferred because all PHP processes can share one +shared memory block for the opcode cache. + +Usually, there is no need to set value of LSAPI_CHILDREN over 100 in +most server environment. + + +* LSAPI_AVOID_FORK (default: 0) + +LSAPI_AVOID_FORK specifies the policy of the internal process manager in +"Self Managed Mode". When set to 0, the internal process manager will stop +and start children process on demand to save system resource. This is +preferred in a shared hosting environment. When set to 1, the internal +process manager will try to avoid freqently stopping and starting children +process. This might be preferred in a dedicate hosting environment. + + +* LSAPI_EXTRA_CHILDREN (default: 1/3 of LSAPI_CHILDREN or 0) + +LSAPI_EXTRA_CHILDREN controls the maximum number of extra children processes +can be started when some or all existing children processes are in +malfunctioning state. Total number of children processes will be reduced to +LSAPI_CHILDREN level as soon as service is back to normal. +When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of +LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is 0. + + +* LSAPI_MAX_REQS or PHP_LSAPI_MAX_REQUESTS (default value: 10000) + +This controls how many requests each child process will handle before +it exits automatically. Several PHP functions have been identified +having memory leaks. This parameter can help reducing memory usage +of leaky PHP functions. + + +* LSAPI_MAX_IDLE (default value: 300 seconds) + +In Self Managed Mode, LSAPI_MAX_IDLE controls how long a idle child +process will wait for a new request before it exits. This option help +releasing system resources taken by idle processes. + + +* LSAPI_MAX_IDLE_CHILDREN + (default value: 1/3 of LSAPI_CHILDREN or LSAPI_CHILDREN) + +In Self Managed Mode, LSAI_MAX_IDLE_CHILDREN controls how many idle +children processes are allowed. Excessive idle children processes +will be killed by the parent process immediately. +When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of +LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value +is LSAPI_CHILDREN. + + +* LSAPI_MAX_PROCESS_TIME (default value: 300 seconds) + +In Self Managed Mode, LSAPI_MAX_PROCESS_TIME controls the maximum +processing time allowed when processing a request. If a child process +can not finish processing of a request in the given time period, it +will be killed by the parent process. This option can help getting rid +of dead or runaway child process. + + +* LSAPI_PGRP_MAX_IDLE (default value: FOREVER ) + +In Self Managed Mode, LSAPI_PGRP_MAX_IDLE controls how long the parent +process will wait before exiting when there is no child process. +This option help releasing system resources taken by an idle parent +process. + + +* LSAPI_PPID_NO_CHECK + +By default a LSAPI application check the existence of its parent process +and exits automatically if the parent process died. This is to reduce +orphan process when web server is restarted. However, it is desireable +to disable this feature, such as when a LSAPI process was started +manually from command line. LSAPI_PPID_NO_CHECK should be set when +you want to disable the checking of existence of parent process. +When PHP started by "-b" option, it is disabled automatically. + + +Compatibility with Apache mod_php +================================= + +LSAPI PHP supports PHP configuration overridden via web server configuration +as well as .htaccess. +Since 4.0 release "apache_response_headers" function is supported. + + + +Contact +======= + +For support questions, please post to our free support forum, at: + +http://www.litespeedtech.com/forum/ + +For bug report, please send bug report to bug [at] litespeedtech.com. + + + + diff --git a/sapi/litespeed/config.m4 b/sapi/litespeed/config.m4 new file mode 100644 index 0000000..268b9ae --- /dev/null +++ b/sapi/litespeed/config.m4 @@ -0,0 +1,31 @@ +dnl +dnl $Id$ +dnl + +AC_MSG_CHECKING(for LiteSpeed support) + +PHP_ARG_WITH(litespeed,, +[ --with-litespeed Build PHP as litespeed module], no) + +if test "$PHP_LITESPEED" != "no"; then + PHP_ADD_MAKEFILE_FRAGMENT($abs_srcdir/sapi/litespeed/Makefile.frag,$abs_srcdir/sapi/litespeed,sapi/litespeed) + SAPI_LITESPEED_PATH=sapi/litespeed/php + PHP_SELECT_SAPI(litespeed, program, lsapi_main.c lsapilib.c, "", '$(SAPI_LITESPEED_PATH)') + case $host_alias in + *darwin*) + BUILD_LITESPEED="\$(CC) \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(NATIVE_RPATHS) \$(PHP_GLOBAL_OBJS:.lo=.o) \$(PHP_BINARY_OBJS:.lo=.o) \$(PHP_LITESPEED_OBJS:.lo=.o) \$(PHP_FRAMEWORKS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_LITESPEED_PATH)" + ;; + *cygwin*) + SAPI_LITESPEED_PATH=sapi/litespeed/php.exe + BUILD_LITESPEED="\$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \$(PHP_GLOBAL_OBJS) \$(PHP_BINARY_OBJS) \$(PHP_LITESPEED_OBJS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_LITESPEED_PATH)" + ;; + *) + BUILD_LITESPEED="\$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \$(PHP_GLOBAL_OBJS) \$(PHP_BINARY_OBJS) \$(PHP_LITESPEED_OBJS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_LITESPEED_PATH)" + ;; + esac + + PHP_SUBST(SAPI_LITESPEED_PATH) + PHP_SUBST(BUILD_LITESPEED) +fi + +AC_MSG_RESULT($PHP_LITESPEED) diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c new file mode 100644 index 0000000..f33b049 --- /dev/null +++ b/sapi/litespeed/lsapi_main.c @@ -0,0 +1,1118 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 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 at 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: George Wang <gwang@litespeedtech.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "php.h" +#include "SAPI.h" +#include "php_main.h" +#include "php_ini.h" +#include "php_variables.h" +#include "zend_highlight.h" +#include "zend.h" + +#include "lsapilib.h" + +#include <stdio.h> + +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef PHP_WIN32 + +#include <io.h> +#include <fcntl.h> +#include "win32/php_registry.h" + +#else + +#include <sys/wait.h> + +#endif + +#include <sys/stat.h> + +#if HAVE_SYS_TYPES_H + +#include <sys/types.h> + +#endif + +#if HAVE_SIGNAL_H + +#include <signal.h> + +#endif + +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> + + +#define SAPI_LSAPI_MAX_HEADER_LENGTH 2048 + +static int lsapi_mode = 1; +static char *php_self = ""; +static char *script_filename = ""; +static int source_highlight = 0; +static char * argv0 = NULL; +static int engine = 1; +#ifdef ZTS +zend_compiler_globals *compiler_globals; +zend_executor_globals *executor_globals; +php_core_globals *core_globals; +sapi_globals_struct *sapi_globals; +void ***tsrm_ls; +#endif + +zend_module_entry litespeed_module_entry; + +/* {{{ php_lsapi_startup + */ +static int php_lsapi_startup(sapi_module_struct *sapi_module) +{ + if (php_module_startup(sapi_module, NULL, 0)==FAILURE) { + return FAILURE; + } + argv0 = sapi_module->executable_location; + return SUCCESS; +} +/* }}} */ + +/* {{{ sapi_lsapi_ini_defaults */ + +/* overwriteable ini defaults must be set in sapi_cli_ini_defaults() */ +#define INI_DEFAULT(name,value)\ + ZVAL_STRING(tmp, value, 0);\ + zend_hash_update(configuration_hash, name, sizeof(name), tmp, sizeof(zval), (void**)&entry);\ + Z_STRVAL_P(entry) = zend_strndup(Z_STRVAL_P(entry), Z_STRLEN_P(entry)) + +static void sapi_lsapi_ini_defaults(HashTable *configuration_hash) +{ + zval *tmp, *entry; + +#if PHP_MAJOR_VERSION > 4 +/* + MAKE_STD_ZVAL(tmp); + + INI_DEFAULT("register_long_arrays", "0"); + + FREE_ZVAL(tmp); +*/ +#endif + +} +/* }}} */ + + +/* {{{ sapi_lsapi_ub_write + */ +static int sapi_lsapi_ub_write(const char *str, uint str_length TSRMLS_DC) +{ + int ret; + int remain; + if ( lsapi_mode ) { + ret = LSAPI_Write( str, str_length ); + if ( ret < str_length ) { + php_handle_aborted_connection(); + return str_length - ret; + } + } else { + remain = str_length; + while( remain > 0 ) { + ret = write( 1, str, remain ); + if ( ret <= 0 ) { + php_handle_aborted_connection(); + return str_length - remain; + } + str += ret; + remain -= ret; + } + } + return str_length; +} +/* }}} */ + + +/* {{{ sapi_lsapi_flush + */ +static void sapi_lsapi_flush( void * server_context ) +{ + if ( lsapi_mode ) { + if ( LSAPI_Flush() == -1) { + php_handle_aborted_connection(); + } + } +} +/* }}} */ + + +/* {{{ sapi_lsapi_deactivate + */ +static int sapi_lsapi_deactivate(TSRMLS_D) +{ + if ( SG(request_info).path_translated ) + { + efree( SG(request_info).path_translated ); + } + + return SUCCESS; +} +/* }}} */ + + + + +/* {{{ sapi_lsapi_getenv + */ +static char *sapi_lsapi_getenv( char * name, size_t name_len TSRMLS_DC ) +{ + if ( lsapi_mode ) { + return LSAPI_GetEnv( name ); + } else { + return getenv( name ); + } +} +/* }}} */ + + +/* +static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen, + void * arg ) +{ + php_register_variable_safe((char *)pKey, (char *)pValue, valLen, (zval *)arg TSRMLS_CC); + return 1; +} +*/ + +static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen, + void * arg ) +{ + zval * gpc_element, **gpc_element_p; + HashTable * symtable1 = Z_ARRVAL_P((zval * )arg); + register char * pKey1 = (char *)pKey; + + MAKE_STD_ZVAL(gpc_element); + Z_STRLEN_P( gpc_element ) = valLen; + Z_STRVAL_P( gpc_element ) = estrndup(pValue, valLen); + Z_TYPE_P( gpc_element ) = IS_STRING; +#if PHP_MAJOR_VERSION > 4 + zend_symtable_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p ); +#else + zend_hash_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p ); +#endif + return 1; +} + + +#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5) +static int add_variable_magic_quote( const char * pKey, int keyLen, const char * pValue, int valLen, + void * arg ) +{ + zval * gpc_element, **gpc_element_p; + HashTable * symtable1 = Z_ARRVAL_P((zval * )arg); + register char * pKey1 = (char *)pKey; + + MAKE_STD_ZVAL(gpc_element); + Z_STRLEN_P( gpc_element ) = valLen; + Z_STRVAL_P( gpc_element ) = php_addslashes((char *)pValue, valLen, &Z_STRLEN_P( gpc_element ), 0 ); + Z_TYPE_P( gpc_element ) = IS_STRING; +#if PHP_MAJOR_VERSION > 4 + zend_symtable_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p ); +#else + zend_hash_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p ); +#endif + return 1; +} + +#endif + +/* {{{ sapi_lsapi_register_variables + */ +static void sapi_lsapi_register_variables(zval *track_vars_array TSRMLS_DC) +{ + char * php_self = ""; + if ( lsapi_mode ) { + if ( (SG(request_info).request_uri ) ) + php_self = (SG(request_info).request_uri ); + +#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5) + if (!PG(magic_quotes_gpc)) { +#endif + LSAPI_ForeachHeader( add_variable, track_vars_array ); + LSAPI_ForeachEnv( add_variable, track_vars_array ); + add_variable("PHP_SELF", 8, php_self, strlen( php_self ), track_vars_array ); +#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5) + } else { + LSAPI_ForeachHeader( add_variable_magic_quote, track_vars_array ); + LSAPI_ForeachEnv( add_variable_magic_quote, track_vars_array ); + add_variable_magic_quote("PHP_SELF", 8, php_self, strlen( php_self ), track_vars_array ); + } +#endif + php_import_environment_variables(track_vars_array TSRMLS_CC); + } else { + php_import_environment_variables(track_vars_array TSRMLS_CC); + + php_register_variable("PHP_SELF", php_self, track_vars_array TSRMLS_CC); + php_register_variable("SCRIPT_NAME", php_self, track_vars_array TSRMLS_CC); + php_register_variable("SCRIPT_FILENAME", script_filename, track_vars_array TSRMLS_CC); + php_register_variable("PATH_TRANSLATED", script_filename, track_vars_array TSRMLS_CC); + php_register_variable("DOCUMENT_ROOT", "", track_vars_array TSRMLS_CC); + + } +} +/* }}} */ + + +/* {{{ sapi_lsapi_read_post + */ +static int sapi_lsapi_read_post(char *buffer, uint count_bytes TSRMLS_DC) +{ + if ( lsapi_mode ) { + return LSAPI_ReadReqBody( buffer, count_bytes ); + } else { + return 0; + } +} +/* }}} */ + + + + +/* {{{ sapi_lsapi_read_cookies + */ +static char *sapi_lsapi_read_cookies(TSRMLS_D) +{ + if ( lsapi_mode ) { + return LSAPI_GetHeader( H_COOKIE ); + } else { + return NULL; + } +} +/* }}} */ + + +/* {{{ sapi_lsapi_send_headers + */ +static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) +{ + sapi_header_struct *h; + zend_llist_position pos; + if ( lsapi_mode ) { + LSAPI_SetRespStatus( SG(sapi_headers).http_response_code ); + + h = zend_llist_get_first_ex(&sapi_headers->headers, &pos); + while (h) { + if ( h->header_len > 0 ) { + LSAPI_AppendRespHeader(h->header, h->header_len); + } + h = zend_llist_get_next_ex(&sapi_headers->headers, &pos); + } + if (SG(sapi_headers).send_default_content_type) { + char *hd; + int len; + char headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH]; + + hd = sapi_get_default_content_type(TSRMLS_C); + len = snprintf( headerBuf, SAPI_LSAPI_MAX_HEADER_LENGTH - 1, + "Content-type: %s", hd ); + efree(hd); + + LSAPI_AppendRespHeader( headerBuf, len ); + } + } + LSAPI_FinalizeRespHeaders(); + return SAPI_HEADER_SENT_SUCCESSFULLY; + + +} +/* }}} */ + + +/* {{{ sapi_lsapi_send_headers + */ +static void sapi_lsapi_log_message(char *message TSRMLS_DC) +{ + int len = strlen( message ); + LSAPI_Write_Stderr( message, len); +} +/* }}} */ + + +/* {{{ sapi_module_struct cgi_sapi_module + */ +static sapi_module_struct lsapi_sapi_module = +{ + "litespeed", + "LiteSpeed V5.5", + + php_lsapi_startup, /* startup */ + php_module_shutdown_wrapper, /* shutdown */ + + NULL, /* activate */ + sapi_lsapi_deactivate, /* deactivate */ + + sapi_lsapi_ub_write, /* unbuffered write */ + sapi_lsapi_flush, /* flush */ + NULL, /* get uid */ + sapi_lsapi_getenv, /* getenv */ + + php_error, /* error handler */ + + NULL, /* header handler */ + sapi_lsapi_send_headers, /* send headers handler */ + NULL, /* send header handler */ + + sapi_lsapi_read_post, /* read POST data */ + sapi_lsapi_read_cookies, /* read Cookies */ + + sapi_lsapi_register_variables, /* register server variables */ + sapi_lsapi_log_message, /* Log message */ + + NULL, /* php.ini path override */ + NULL, /* block interruptions */ + NULL, /* unblock interruptions */ + NULL, /* default post reader */ + NULL, /* treat data */ + NULL, /* executable location */ + + 0, /* php.ini ignore */ + + STANDARD_SAPI_MODULE_PROPERTIES + +}; +/* }}} */ + +static int init_request_info( TSRMLS_D ) +{ + char * pContentType = LSAPI_GetHeader( H_CONTENT_TYPE ); + char * pAuth; + + SG(request_info).content_type = pContentType ? pContentType : ""; + SG(request_info).request_method = LSAPI_GetRequestMethod(); + SG(request_info).query_string = LSAPI_GetQueryString(); + SG(request_info).request_uri = LSAPI_GetScriptName(); + SG(request_info).content_length = LSAPI_GetReqBodyLen(); + SG(request_info).path_translated = estrdup( LSAPI_GetScriptFileName()); + + /* It is not reset by zend engine, set it to 0. */ + SG(sapi_headers).http_response_code = 0; + + pAuth = LSAPI_GetHeader( H_AUTHORIZATION ); + php_handle_auth_data(pAuth TSRMLS_CC); +} + +static char s_cur_chdir[4096] = ""; + +static int lsapi_chdir_primary_script( zend_file_handle * file_handle ) +{ +#if PHP_MAJOR_VERSION > 4 + char * p; + char ch; + + SG(options) |= SAPI_OPTION_NO_CHDIR; + getcwd( s_cur_chdir, sizeof( s_cur_chdir ) ); + + p = strrchr( file_handle->filename, '/' ); + if ( *p ) + { + *p = 0; + if ( strcmp( file_handle->filename, s_cur_chdir ) != 0 ) { + chdir( file_handle->filename ); + } + *p++ = '/'; + ch = *p; + *p = 0; + if ( !CWDG(cwd).cwd || + ( strcmp( file_handle->filename, CWDG(cwd).cwd ) != 0 ) ) { + CWDG(cwd).cwd_length = p - file_handle->filename; + CWDG(cwd).cwd = (char *) realloc(CWDG(cwd).cwd, CWDG(cwd).cwd_length+1); + memmove( CWDG(cwd).cwd, file_handle->filename, CWDG(cwd).cwd_length+1 ); + } + *p = ch; + } + /* virtual_file_ex(&CWDG(cwd), file_handle->filename, NULL, CWD_REALPATH); */ +#else + VCWD_CHDIR_FILE( file_handle->filename ); +#endif + return 0; +} + +static int lsapi_fopen_primary_script( zend_file_handle * file_handle ) +{ + FILE * fp; + char * p; + fp = fopen( SG(request_info).path_translated, "rb" ); + if ( !fp ) + { + return -1; + } + file_handle->type = ZEND_HANDLE_FP; + file_handle->handle.fp = fp; + file_handle->filename = SG(request_info).path_translated; + file_handle->free_filename = 0; + file_handle->opened_path = NULL; + + lsapi_chdir_primary_script( file_handle ); + + return 0; +} + +static int lsapi_execute_script( zend_file_handle * file_handle TSRMLS_DC) +{ + char *p; + int len; + file_handle->type = ZEND_HANDLE_FILENAME; + file_handle->handle.fd = 0; + file_handle->filename = SG(request_info).path_translated; + file_handle->free_filename = 0; + file_handle->opened_path = NULL; + + p = argv0; + *p++ = ':'; + len = strlen( SG(request_info).path_translated ); + if ( len > 45 ) + len = len - 45; + else + len = 0; + memccpy( p, SG(request_info).path_translated + len, 0, 46 ); + + php_execute_script(file_handle TSRMLS_CC); + return 0; + +} + + +static int lsapi_module_main(int show_source TSRMLS_DC) +{ + zend_file_handle file_handle = {0}; + + if (php_request_startup(TSRMLS_C) == FAILURE ) { + return -1; + } + if (show_source) { + zend_syntax_highlighter_ini syntax_highlighter_ini; + + php_get_highlight_struct(&syntax_highlighter_ini); + highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC); + } else { + lsapi_execute_script( &file_handle TSRMLS_CC); + } + zend_try { + php_request_shutdown(NULL); + *argv0 = 0; + } zend_end_try(); + return 0; +} + + +static int alter_ini( const char * pKey, int keyLen, const char * pValue, int valLen, + void * arg ) +{ + int type = ZEND_INI_PERDIR; + if ( '\001' == *pKey ) { + ++pKey; + if ( *pKey == 4 ) { + type = ZEND_INI_SYSTEM; + } + ++pKey; + --keyLen; + if (( keyLen == 7 )&&( strncasecmp( pKey, "engine", 6 )== 0 )) + { + if ( *pValue == '0' ) + engine = 0; + } + else + zend_alter_ini_entry((char *)pKey, keyLen, + (char *)pValue, valLen, + type, PHP_INI_STAGE_ACTIVATE); + } + return 1; +} + + +static void override_ini() +{ + + LSAPI_ForeachSpecialEnv( alter_ini, NULL ); + +} + +static int processReq( TSRMLS_D ) +{ + int ret = 0; + zend_first_try { + /* avoid server_context==NULL checks */ + SG(server_context) = (void *) 1; + + engine = 1; + override_ini(); + + if ( engine ) { + init_request_info( TSRMLS_C ); + + if ( lsapi_module_main( source_highlight TSRMLS_CC ) == -1 ) { + ret = -1; + } + } else { + LSAPI_AppendRespHeader( "status: 403", 11 ); + LSAPI_AppendRespHeader( "content-type: text/html", 23 ); + LSAPI_Write( "Forbidden: PHP engine is disable.\n", 34 ); + } + } zend_end_try(); + return ret; +} + +static void cli_usage( TSRMLS_D ) +{ + static const char * usage = + "Usage: php\n" + " php -[b|c|h|i|q|s|v|?] [<file>] [args...]\n" + " Run in LSAPI mode, only '-b', '-s' and '-c' are effective\n" + " Run in Command Line Interpreter mode when parameters are specified\n" + "\n" + " -b <address:port>|<port> Bind Path for external LSAPI Server mode\n" + " -c <path>|<file> Look for php.ini file in this directory\n" + " -h This help\n" + " -i PHP information\n" + " -q Quiet-mode. Suppress HTTP Header output.\n" + " -s Display colour syntax highlighted source.\n" + " -v Version number\n" + " -? This help\n" + "\n" + " args... Arguments passed to script.\n"; + php_output_startup(); + php_output_activate(TSRMLS_C); + php_printf( "%s", usage ); +#ifdef PHP_OUTPUT_NEWAPI + php_output_end_all(TSRMLS_C); +#else + php_end_ob_buffers(1 TSRMLS_CC); +#endif +} + +static int parse_opt( int argc, char * argv[], int *climode, + char **php_ini_path, char ** php_bind ) +{ + char ** p = &argv[1]; + char ** argend= &argv[argc]; + int c; + while (( p < argend )&&(**p == '-' )) { + c = *((*p)+1); + ++p; + switch( c ) { + case 'b': + if ( p >= argend ) { + fprintf( stderr, "TCP or socket address must be specified following '-b' option.\n"); + return -1; + } + *php_bind = *p++; + break; + + case 'c': + if ( p >= argend ) { + fprintf( stderr, "<path> or <file> must be specified following '-c' option.\n"); + + return -1; + } + *php_ini_path = *p++; + break; + case 's': + source_highlight = 1; + break; + case 'h': + case 'i': + case 'q': + case 'v': + case '?': + default: + *climode = 1; + break; + } + } + if ( p - argv < argc ) { + *climode = 1; + } + return 0; +} + +static int cli_main( int argc, char * argv[] ) +{ + + static const char * ini_defaults[] = { + "report_zend_debug", "0", + "display_errors", "1", + "register_argc_argv", "1", + "html_errors", "0", + "implicit_flush", "1", + "output_buffering", "0", + "max_execution_time", "0", + "max_input_time", "-1", + NULL + }; + + const char ** ini; + char ** p = &argv[1]; + char ** argend= &argv[argc]; + int ret = 0; + int c; + lsapi_mode = 0; /* enter CLI mode */ + +#ifdef PHP_WIN32 + _fmode = _O_BINARY; /*sets default for file streams to binary */ + setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */ + setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */ + setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */ +#endif + + zend_first_try { + SG(server_context) = (void *) 1; + + zend_uv.html_errors = 0; /* tell the engine we're in non-html mode */ + CG(in_compilation) = 0; /* not initialized but needed for several options */ + EG(uninitialized_zval_ptr) = NULL; + + for( ini = ini_defaults; *ini; ini+=2 ) { + zend_alter_ini_entry( (char *)*ini, strlen( *ini )+1, + (char *)*(ini+1), strlen( *(ini+1) ), + PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); + } + + while (( p < argend )&&(**p == '-' )) { + c = *((*p)+1); + ++p; + switch( c ) { + case 'q': + break; + case 'i': + if (php_request_startup(TSRMLS_C) != FAILURE) { + php_print_info(0xFFFFFFFF TSRMLS_CC); +#ifdef PHP_OUTPUT_NEWAPI + php_output_end_all(TSRMLS_C); +#else + php_end_ob_buffers(1 TSRMLS_CC); +#endif + php_request_shutdown( NULL ); + } + ret = 1; + break; + case 'v': + if (php_request_startup(TSRMLS_C) != FAILURE) { +#if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); +#else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); +#endif +#ifdef PHP_OUTPUT_NEWAPI + php_output_end_all(TSRMLS_C); +#else + php_end_ob_buffers(1 TSRMLS_CC); +#endif + php_request_shutdown( NULL ); + } + ret = 1; + break; + case 'c': + ++p; + /* fall through */ + case 's': + break; + + case 'h': + case '?': + default: + cli_usage(TSRMLS_C); + ret = 1; + break; + + } + } + if ( !ret ) { + if ( *p ) { + zend_file_handle file_handle = {0}; + + file_handle.type = ZEND_HANDLE_FP; + file_handle.handle.fp = VCWD_FOPEN(*p, "rb"); + + if ( file_handle.handle.fp ) { + script_filename = *p; + php_self = *p; + + SG(request_info).path_translated = estrdup(*p); + SG(request_info).argc = argc - (p - argv); + SG(request_info).argv = p; + + if (php_request_startup(TSRMLS_C) == FAILURE ) { + fclose( file_handle.handle.fp ); + ret = 2; + } else { + if (source_highlight) { + zend_syntax_highlighter_ini syntax_highlighter_ini; + + php_get_highlight_struct(&syntax_highlighter_ini); + highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC); + } else { + file_handle.filename = *p; + file_handle.free_filename = 0; + file_handle.opened_path = NULL; + + php_execute_script(&file_handle TSRMLS_CC); + } + + php_request_shutdown( NULL ); + } + } else { + php_printf("Could not open input file: %s.\n", *p); + } + } else { + cli_usage(TSRMLS_C); + } + } + + }zend_end_try(); + + php_module_shutdown(TSRMLS_C); + +#ifdef ZTS + tsrm_shutdown(); +#endif + return ret; +} + +static int s_stop; +void litespeed_cleanup(int signal) +{ + s_stop = signal; +} + + +void start_children( int children ) +{ + struct sigaction act, old_term, old_quit, old_int, old_usr1; + int running = 0; + int status; + pid_t pid; + + /* Create a process group */ + setsid(); + + /* Set up handler to kill children upon exit */ + act.sa_flags = 0; + act.sa_handler = litespeed_cleanup; + if( sigaction( SIGTERM, &act, &old_term ) || + sigaction( SIGINT, &act, &old_int ) || + sigaction( SIGUSR1, &act, &old_usr1 ) || + sigaction( SIGQUIT, &act, &old_quit )) { + perror( "Can't set signals" ); + exit( 1 ); + } + s_stop = 0; + while( 1 ) { + while((!s_stop )&&( running < children )) { + pid = fork(); + switch( pid ) { + case 0: /* children process */ + + /* don't catch our signals */ + sigaction( SIGTERM, &old_term, 0 ); + sigaction( SIGQUIT, &old_quit, 0 ); + sigaction( SIGINT, &old_int, 0 ); + sigaction( SIGUSR1, &old_usr1, 0 ); + return ; + case -1: + perror( "php (pre-forking)" ); + exit( 1 ); + break; + default: /* parent process */ + running++; + break; + } + } + if ( s_stop ) { + break; + } + pid = wait( &status ); + running--; + } + kill( -getpgrp(), SIGUSR1 ); + exit( 0 ); +} + + + +#include <fcntl.h> +int main( int argc, char * argv[] ) +{ + int ret; + int bindFd; + + char * php_ini_path = NULL; + char * php_bind = NULL; + char * p; + int n; + int climode = 0; + struct timeval tv_req_begin; + struct timeval tv_req_end; + int slow_script_msec = 0; + char time_buf[40]; + +#ifdef HAVE_SIGNAL_H +#if defined(SIGPIPE) && defined(SIG_IGN) + signal(SIGPIPE, SIG_IGN); +#endif +#endif + +#ifdef ZTS + tsrm_startup(1, 1, 0, NULL); +#endif + + if (argc > 1 ) { + if ( parse_opt( argc, argv, &climode, + &php_ini_path, &php_bind ) == -1 ) { + return 1; + } + } + if ( climode ) { + lsapi_sapi_module.phpinfo_as_text = 1; + } + argv0 = argv[0] + strlen( argv[0] ); + sapi_startup(&lsapi_sapi_module); + +#ifdef ZTS + compiler_globals = ts_resource(compiler_globals_id); + executor_globals = ts_resource(executor_globals_id); + core_globals = ts_resource(core_globals_id); + sapi_globals = ts_resource(sapi_globals_id); + tsrm_ls = ts_resource(0); + + SG(request_info).path_translated = NULL; +#endif + + lsapi_sapi_module.executable_location = argv[0]; + + if ( php_ini_path ) { + lsapi_sapi_module.php_ini_path_override = php_ini_path; + } + + + lsapi_sapi_module.ini_defaults = sapi_lsapi_ini_defaults; + + if (php_module_startup(&lsapi_sapi_module, &litespeed_module_entry, 1) == FAILURE) { +#ifdef ZTS + tsrm_shutdown(); +#endif + return FAILURE; + } + + if ( climode ) { + return cli_main(argc, argv); + } + + if ( php_bind ) { + bindFd = LSAPI_CreateListenSock( php_bind, 10 ); + if ( bindFd == -1 ) { + fprintf( stderr, + "Failed to bind socket [%s]: %s\n", php_bind, strerror( errno ) ); + exit( 2 ); + } + if ( bindFd != 0 ) { + dup2( bindFd, 0 ); + close( bindFd ); + } + } + + LSAPI_Init(); + + LSAPI_Init_Env_Parameters( NULL ); + + slow_script_msec = LSAPI_Get_Slow_Req_Msecs(); + + if ( php_bind ) { + LSAPI_No_Check_ppid(); + } + + while( LSAPI_Prefork_Accept_r( &g_req ) >= 0 ) { + if ( slow_script_msec ) { + gettimeofday( &tv_req_begin, NULL ); + } + ret = processReq(TSRMLS_C); + if ( slow_script_msec ) { + gettimeofday( &tv_req_end, NULL ); + n = ((long) tv_req_end.tv_sec - tv_req_begin.tv_sec ) * 1000 + + (tv_req_end.tv_usec - tv_req_begin.tv_usec) / 1000; + if ( n > slow_script_msec ) + { + strftime( time_buf, 30, "%d/%b/%Y:%H:%M:%S", localtime( &tv_req_end.tv_sec ) ); + fprintf( stderr, "[%s] Slow PHP script: %d ms\n URL: %s %s\n Query String: %s\n Script: %s\n", + time_buf, n, LSAPI_GetRequestMethod(), + LSAPI_GetScriptName(), LSAPI_GetQueryString(), + LSAPI_GetScriptFileName() ); + + } + } + LSAPI_Finish(); + if ( ret ) { + break; + } + } + php_module_shutdown(TSRMLS_C); + +#ifdef ZTS + tsrm_shutdown(); +#endif + return ret; +} + + +/* LiteSpeed PHP module starts here */ + +#if PHP_MAJOR_VERSION > 4 + +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO(arginfo_litespeed__void, 0) +ZEND_END_ARG_INFO() +/* }}} */ + +#else +#define arginfo_litespeed__void NULL +#endif + +PHP_FUNCTION(litespeed_request_headers); +PHP_FUNCTION(litespeed_response_headers); + +PHP_MINFO_FUNCTION(litespeed); + +zend_function_entry litespeed_functions[] = { + PHP_FE(litespeed_request_headers, arginfo_litespeed__void) + PHP_FE(litespeed_response_headers, arginfo_litespeed__void) + PHP_FALIAS(getallheaders, litespeed_request_headers, arginfo_litespeed__void) + PHP_FALIAS(apache_request_headers, litespeed_request_headers, arginfo_litespeed__void) + PHP_FALIAS(apache_response_headers, litespeed_response_headers, arginfo_litespeed__void) + {NULL, NULL, NULL} +}; + +static PHP_MINIT_FUNCTION(litespeed) +{ + /* REGISTER_INI_ENTRIES(); */ + return SUCCESS; +} + + +static PHP_MSHUTDOWN_FUNCTION(litespeed) +{ + /* UNREGISTER_INI_ENTRIES(); */ + return SUCCESS; +} + +zend_module_entry litespeed_module_entry = { + STANDARD_MODULE_HEADER, + "litespeed", + litespeed_functions, + PHP_MINIT(litespeed), + PHP_MSHUTDOWN(litespeed), + NULL, + NULL, + NULL, + NO_VERSION_YET, + STANDARD_MODULE_PROPERTIES +}; + +static int add_associate_array( const char * pKey, int keyLen, const char * pValue, int valLen, + void * arg ) +{ + add_assoc_string_ex( (zval *)arg, (char *)pKey, keyLen+1, (char *)pValue, 1 ); + return 1; +} + + +/* {{{ proto array litespeed_request_headers(void) + Fetch all HTTP request headers */ +PHP_FUNCTION(litespeed_request_headers) +{ + /* TODO: */ + if (ZEND_NUM_ARGS() > 0) { + WRONG_PARAM_COUNT; + } + array_init(return_value); + + if ( lsapi_mode ) + LSAPI_ForeachOrgHeader( add_associate_array, return_value ); + +} +/* }}} */ + + + +/* {{{ proto array litespeed_response_headers(void) + Fetch all HTTP response headers */ +PHP_FUNCTION(litespeed_response_headers) +{ + sapi_header_struct *h; + zend_llist_position pos; + char * p; + int len; + char headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH]; + + if (ZEND_NUM_ARGS() > 0) { + WRONG_PARAM_COUNT; + } + + if (!&SG(sapi_headers).headers) { + RETURN_FALSE; + } + array_init(return_value); + + h = zend_llist_get_first_ex(&SG(sapi_headers).headers, &pos); + while (h) { + if ( h->header_len > 0 ) { + p = strchr( h->header, ':' ); + len = p - h->header; + if (( p )&&( len > 0 )) { + memmove( headerBuf, h->header, len ); + while( len > 0 && (isspace( headerBuf[len-1])) ) { + --len; + } + headerBuf[len] = 0; + if ( len ) { + while( isspace(*++p)); + add_assoc_string_ex(return_value, headerBuf, len+1, p, 1 ); + } + } + } + h = zend_llist_get_next_ex(&SG(sapi_headers).headers, &pos); + } +} + +/* }}} */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ + + diff --git a/sapi/litespeed/lsapidef.h b/sapi/litespeed/lsapidef.h new file mode 100644 index 0000000..c8940a9 --- /dev/null +++ b/sapi/litespeed/lsapidef.h @@ -0,0 +1,196 @@ + +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 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 at 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: George Wang <gwang@litespeedtech.com> | + +----------------------------------------------------------------------+ +*/ + + +/* +Copyright (c) 2007, Lite Speed Technologies Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the Lite Speed Technologies Inc nor the + names of its contributors may be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef _LSAPIDEF_H_ +#define _LSAPIDEF_H_ + +#include <inttypes.h> + +#if defined (c_plusplus) || defined (__cplusplus) +extern "C" { +#endif + +enum +{ + H_ACCEPT = 0, + H_ACC_CHARSET, + H_ACC_ENCODING, + H_ACC_LANG, + H_AUTHORIZATION, + H_CONNECTION, + H_CONTENT_TYPE, + H_CONTENT_LENGTH, + H_COOKIE, + H_COOKIE2, + H_HOST, + H_PRAGMA, + H_REFERER, + H_USERAGENT, + H_CACHE_CTRL, + H_IF_MODIFIED_SINCE, + H_IF_MATCH, + H_IF_NO_MATCH, + H_IF_RANGE, + H_IF_UNMOD_SINCE, + H_KEEP_ALIVE, + H_RANGE, + H_X_FORWARDED_FOR, + H_VIA, + H_TRANSFER_ENCODING + +}; +#define LSAPI_SOCK_FILENO 0 + +#define LSAPI_VERSION_B0 'L' +#define LSAPI_VERSION_B1 'S' + +/* Values for m_flag in lsapi_packet_header */ +#define LSAPI_ENDIAN_LITTLE 0 +#define LSAPI_ENDIAN_BIG 1 +#define LSAPI_ENDIAN_BIT 1 + +#if defined(__i386__)||defined( __x86_64 )||defined( __x86_64__ ) +#define LSAPI_ENDIAN LSAPI_ENDIAN_LITTLE +#else +#define LSAPI_ENDIAN LSAPI_ENDIAN_BIG +#endif + +/* Values for m_type in lsapi_packet_header */ +#define LSAPI_BEGIN_REQUEST 1 +#define LSAPI_ABORT_REQUEST 2 +#define LSAPI_RESP_HEADER 3 +#define LSAPI_RESP_STREAM 4 +#define LSAPI_RESP_END 5 +#define LSAPI_STDERR_STREAM 6 +#define LSAPI_REQ_RECEIVED 7 + + +#define LSAPI_MAX_HEADER_LEN 65535 +#define LSAPI_MAX_DATA_PACKET_LEN 16384 + +#define LSAPI_RESP_HTTP_HEADER_MAX 4096 +#define LSAPI_PACKET_HEADER_LEN 8 + + +struct lsapi_packet_header +{ + char m_versionB0; /* LSAPI protocol version */ + char m_versionB1; + char m_type; + char m_flag; + union + { + int32_t m_iLen; /* include this header */ + char m_bytes[4]; + }m_packetLen; +}; + +/* + LSAPI request header packet + + 1. struct lsapi_req_header + 2. struct lsapi_http_header_index + 3. lsapi_header_offset * unknownHeaders + 4. org http request header + 5. request body if available +*/ + +struct lsapi_req_header +{ + struct lsapi_packet_header m_pktHeader; + + int32_t m_httpHeaderLen; + int32_t m_reqBodyLen; + int32_t m_scriptFileOff; /* path to the script file. */ + int32_t m_scriptNameOff; /* decrypted URI, without pathinfo, */ + int32_t m_queryStringOff; /* Query string inside env */ + int32_t m_requestMethodOff; + int32_t m_cntUnknownHeaders; + int32_t m_cntEnv; + int32_t m_cntSpecialEnv; +} ; + + +struct lsapi_http_header_index +{ + int16_t m_headerLen[H_TRANSFER_ENCODING+1]; + int32_t m_headerOff[H_TRANSFER_ENCODING+1]; +} ; + +struct lsapi_header_offset +{ + int32_t nameOff; + int32_t nameLen; + int32_t valueOff; + int32_t valueLen; +} ; + +struct lsapi_resp_info +{ + int32_t m_cntHeaders; + int32_t m_status; +}; + +struct lsapi_resp_header +{ + struct lsapi_packet_header m_pktHeader; + struct lsapi_resp_info m_respInfo; +}; + +#if defined (c_plusplus) || defined (__cplusplus) +} +#endif + + +#endif + diff --git a/sapi/litespeed/lsapilib.c b/sapi/litespeed/lsapilib.c new file mode 100644 index 0000000..10ea749 --- /dev/null +++ b/sapi/litespeed/lsapilib.c @@ -0,0 +1,2227 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 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 at 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: George Wang <gwang@litespeedtech.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +/* +Copyright (c) 2007, Lite Speed Technologies Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the Lite Speed Technologies Inc nor the + names of its contributors may be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <lsapilib.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> + +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/un.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +#define LSAPI_ST_REQ_HEADER 1 +#define LSAPI_ST_REQ_BODY 2 +#define LSAPI_ST_RESP_HEADER 4 +#define LSAPI_ST_RESP_BODY 8 + +#define LSAPI_RESP_BUF_SIZE 8192 +#define LSAPI_INIT_RESP_HEADER_LEN 4096 + + +static int g_inited = 0; +static int g_running = 1; +static int s_ppid; +static int s_slow_req_msecs = 0; +LSAPI_Request g_req = { -1, -1 }; + +void Flush_RespBuf_r( LSAPI_Request * pReq ); + +static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] = +{ + "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", + "HTTP_ACCEPT_ENCODING", + "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHORIZATION", + "HTTP_CONNECTION", "CONTENT_TYPE", + "CONTENT_LENGTH", "HTTP_COOKIE", "HTTP_COOKIE2", + "HTTP_HOST", "HTTP_PRAGMA", + "HTTP_REFERER", "HTTP_USER_AGENT", + "HTTP_CACHE_CONTROL", + "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_MATCH", + "HTTP_IF_NONE_MATCH", + "HTTP_IF_RANGE", + "HTTP_IF_UNMODIFIED_SINCE", + "HTTP_KEEP_ALIVE", + "HTTP_RANGE", + "HTTP_X_FORWARDED_FOR", + "HTTP_VIA", + "HTTP_TRANSFER_ENCODING" +}; + +static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] = { + 11, 19, 20, 20, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 18, + 22, 13, 18, 13, 24, 15, 10, 20, 8, 22 +}; + + +static const char *HTTP_HEADERS[H_TRANSFER_ENCODING+1] = { + "Accept", "Accept-Charset", + "Accept-Encoding", + "Accept-Language", "Authorization", + "Connection", "Content-Type", + "Content-Length", "Cookie", "Cookie2", + "Host", "Pragma", + "Referer", "User-Agent", + "Cache-Control", + "If-Modified-Since", "If-Match", + "If-None-Match", + "If-Range", + "If-Unmodified-Since", + "Keep-Alive", + "Range", + "X-Forwarded-For", + "Via", + "Transfer-Encoding" +}; + +static int HTTP_HEADER_LEN[H_TRANSFER_ENCODING+1] = { + 6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10, /* user-agent */ + 13,17, 8, 13, 8, 19, 10, 5, 15, 3, 17 +}; + +static void lsapi_sigpipe( int sig ) +{ +} +static void lsapi_siguser1( int sig ) +{ + g_running = 0; +} + +#ifndef sighandler_t +typedef void (*sighandler_t)(int); +#endif + +static void lsapi_signal(int signo, sighandler_t handler) +{ + struct sigaction sa; + + sigaction(signo, NULL, &sa); + + if (sa.sa_handler == SIG_DFL) { + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = handler; + sigaction(signo, &sa, NULL); + } +} + + +static inline void lsapi_buildPacketHeader( struct lsapi_packet_header * pHeader, + char type, int len ) +{ + pHeader->m_versionB0 = LSAPI_VERSION_B0; /* LSAPI protocol version */ + pHeader->m_versionB1 = LSAPI_VERSION_B1; + pHeader->m_type = type; + pHeader->m_flag = LSAPI_ENDIAN; + pHeader->m_packetLen.m_iLen = len; +} + +static int lsapi_set_nblock( int fd, int nonblock ) +{ + int val = fcntl( fd, F_GETFL, 0 ); + if ( nonblock ) + { + if (!( val & O_NONBLOCK )) + { + return fcntl( fd, F_SETFL, val | O_NONBLOCK ); + } + } + else + { + if ( val & O_NONBLOCK ) + { + return fcntl( fd, F_SETFL, val &(~O_NONBLOCK) ); + } + } + return 0; +} + + +static int lsapi_close( int fd ) +{ + int ret; + while( 1 ) { + ret = close( fd ); + if (( ret == -1 )&&( errno == EINTR )&&(g_running)) { + continue; + } + return ret; + } +} + +static inline int lsapi_read( int fd, void * pBuf, int len ) +{ + int ret; + while( 1 ) { + ret = read( fd, (char *)pBuf, len ); + if (( ret == -1 )&&( errno == EINTR )&&(g_running)) { + continue; + } + return ret; + } +} + + +static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen ) +{ + int ret; + int left = totalLen; + int n = count; + while(( left > 0 )&&g_running ) { + ret = writev( fd, *pVec, n ); + if ( ret > 0 ) { + left -= ret; + if (( left <= 0)||( !g_running )) { + return totalLen - left; + } + while( ret > 0 ) { + if ( (*pVec)->iov_len <= ret ) { + ret -= (*pVec)->iov_len; + ++(*pVec); + } else { + (*pVec)->iov_base = (char *)(*pVec)->iov_base + ret; + (*pVec)->iov_len -= ret; + break; + } + } + } else if ( ret == -1 ) { + if ( errno == EAGAIN ) { + if ( totalLen - left > 0 ) { + return totalLen - left; + } else { + return -1; + } + } else { + if ( errno != EINTR ) { + return ret; + } + } + } + } + return totalLen - left; +} + +static inline int allocateBuf( LSAPI_Request * pReq, int size ) +{ + char * pBuf = (char *)realloc( pReq->m_pReqBuf, size ); + if ( pBuf ) { + pReq->m_pReqBuf = pBuf; + pReq->m_reqBufSize = size; + pReq->m_pHeader = (struct lsapi_req_header *)pReq->m_pReqBuf; + return 0; + } + return -1; +} + + +static int allocateIovec( LSAPI_Request * pReq, int n ) +{ + struct iovec * p = (struct iovec *)realloc( + pReq->m_pIovec, sizeof(struct iovec) * n ); + if ( !p ) { + return -1; + } + pReq->m_pIovecToWrite = p + ( pReq->m_pIovecToWrite - pReq->m_pIovec ); + pReq->m_pIovecCur = p + ( pReq->m_pIovecCur - pReq->m_pIovec ); + pReq->m_pIovec = p; + pReq->m_pIovecEnd = p + n; + return 0; +} + +static int allocateRespHeaderBuf( LSAPI_Request * pReq, int size ) +{ + char * p = (char *)realloc( pReq->m_pRespHeaderBuf, size ); + if ( !p ) { + return -1; + } + pReq->m_pRespHeaderBufPos = p + ( pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf ); + pReq->m_pRespHeaderBuf = p; + pReq->m_pRespHeaderBufEnd = p + size; + return 0; +} + + +static inline int verifyHeader( struct lsapi_packet_header * pHeader, char pktType ) +{ + if (( LSAPI_VERSION_B0 != pHeader->m_versionB0 )|| + ( LSAPI_VERSION_B1 != pHeader->m_versionB1 )|| + ( pktType != pHeader->m_type )) { + return -1; + } + if ( LSAPI_ENDIAN != (pHeader->m_flag & LSAPI_ENDIAN_BIT )) { + register char b; + b = pHeader->m_packetLen.m_bytes[0]; + pHeader->m_packetLen.m_bytes[0] = pHeader->m_packetLen.m_bytes[3]; + pHeader->m_packetLen.m_bytes[3] = b; + b = pHeader->m_packetLen.m_bytes[1]; + pHeader->m_packetLen.m_bytes[1] = pHeader->m_packetLen.m_bytes[2]; + pHeader->m_packetLen.m_bytes[2] = b; + } + return pHeader->m_packetLen.m_iLen; +} + +static int allocateEnvList( struct LSAPI_key_value_pair ** pEnvList, + int *curSize, int newSize ) +{ + struct LSAPI_key_value_pair * pBuf; + if ( *curSize >= newSize ) { + return 0; + } + if ( newSize > 8192 ) { + return -1; + } + pBuf = (struct LSAPI_key_value_pair *)realloc( *pEnvList, newSize * + sizeof(struct LSAPI_key_value_pair) ); + if ( pBuf ) { + *pEnvList = pBuf; + *curSize = newSize; + return 0; + } else { + return -1; + } + +} + +static inline int isPipe( int fd ) +{ + char achPeer[128]; + socklen_t len = 128; + if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&& + ( errno == ENOTCONN )) { + return 0; + } else { + return 1; + } +} + +static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count, + char **pBegin, char * pEnd ) +{ + struct LSAPI_key_value_pair * pEnvEnd; + int keyLen = 0, valLen = 0; + if ( count > 8192 ) { + return -1; + } + pEnvEnd = pEnvList + count; + while( pEnvList != pEnvEnd ) { + if ( pEnd - *pBegin < 4 ) { + return -1; + } + keyLen = *((unsigned char *)((*pBegin)++)); + keyLen = (keyLen << 8) + *((unsigned char *)((*pBegin)++)); + valLen = *((unsigned char *)((*pBegin)++)); + valLen = (valLen << 8) + *((unsigned char *)((*pBegin)++)); + if ( *pBegin + keyLen + valLen > pEnd ) { + return -1; + } + if (( !keyLen )||( !valLen )) { + return -1; + } + + pEnvList->pKey = *pBegin; + *pBegin += keyLen; + pEnvList->pValue = *pBegin; + *pBegin += valLen; + + pEnvList->keyLen = keyLen - 1; + pEnvList->valLen = valLen - 1; + ++pEnvList; + } + if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 ) { + return -1; + } + *pBegin += 4; + return 0; +} + +static inline void swapIntEndian( int * pInteger ) +{ + char * p = (char *)pInteger; + register char b; + b = p[0]; + p[0] = p[3]; + p[3] = b; + b = p[1]; + p[1] = p[2]; + p[2] = b; + +} + +static inline void fixEndian( LSAPI_Request * pReq ) +{ + struct lsapi_req_header *p= pReq->m_pHeader; + swapIntEndian( &p->m_httpHeaderLen ); + swapIntEndian( &p->m_reqBodyLen ); + swapIntEndian( &p->m_scriptFileOff ); + swapIntEndian( &p->m_scriptNameOff ); + swapIntEndian( &p->m_queryStringOff ); + swapIntEndian( &p->m_requestMethodOff ); + swapIntEndian( &p->m_cntUnknownHeaders ); + swapIntEndian( &p->m_cntEnv ); + swapIntEndian( &p->m_cntSpecialEnv ); +} + +static void fixHeaderIndexEndian( LSAPI_Request * pReq ) +{ + int i; + for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { + if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { + register char b; + char * p = (char *)(&pReq->m_pHeaderIndex->m_headerLen[i]); + b = p[0]; + p[0] = p[1]; + p[1] = b; + swapIntEndian( &pReq->m_pHeaderIndex->m_headerOff[i] ); + } + } + if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { + struct lsapi_header_offset * pCur, *pEnd; + pCur = pReq->m_pUnknownHeader; + pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; + while( pCur < pEnd ) { + swapIntEndian( &pCur->nameOff ); + swapIntEndian( &pCur->nameLen ); + swapIntEndian( &pCur->valueOff ); + swapIntEndian( &pCur->valueLen ); + ++pCur; + } + } +} + +static int parseRequest( LSAPI_Request * pReq, int totalLen ) +{ + int shouldFixEndian; + char * pBegin = pReq->m_pReqBuf + sizeof( struct lsapi_req_header ); + char * pEnd = pReq->m_pReqBuf + totalLen; + shouldFixEndian = ( LSAPI_ENDIAN != ( + pReq->m_pHeader->m_pktHeader.m_flag & LSAPI_ENDIAN_BIT ) ); + if ( shouldFixEndian ) { + fixEndian( pReq ); + } + if ( (pReq->m_specialEnvListSize < pReq->m_pHeader->m_cntSpecialEnv )&& + allocateEnvList( &pReq->m_pSpecialEnvList, + &pReq->m_specialEnvListSize, + pReq->m_pHeader->m_cntSpecialEnv ) == -1 ) { + return -1; + } + if ( (pReq->m_envListSize < pReq->m_pHeader->m_cntEnv )&& + allocateEnvList( &pReq->m_pEnvList, &pReq->m_envListSize, + pReq->m_pHeader->m_cntEnv ) == -1 ) { + return -1; + } + if ( parseEnv( pReq->m_pSpecialEnvList, + pReq->m_pHeader->m_cntSpecialEnv, + &pBegin, pEnd ) == -1 ) { + return -1; + } + if ( parseEnv( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv, + &pBegin, pEnd ) == -1 ) { + return -1; + } + pReq->m_pScriptFile = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptFileOff; + pReq->m_pScriptName = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptNameOff; + pReq->m_pQueryString = pReq->m_pReqBuf + pReq->m_pHeader->m_queryStringOff; + pReq->m_pRequestMethod = pReq->m_pReqBuf + pReq->m_pHeader->m_requestMethodOff; + + pBegin = pReq->m_pReqBuf + (( pBegin - pReq->m_pReqBuf + 7 ) & (~0x7)); + pReq->m_pHeaderIndex = ( struct lsapi_http_header_index * )pBegin; + pBegin += sizeof( struct lsapi_http_header_index ); + + pReq->m_pUnknownHeader = (struct lsapi_header_offset *)pBegin; + pBegin += sizeof( struct lsapi_header_offset) * + pReq->m_pHeader->m_cntUnknownHeaders; + + pReq->m_pHttpHeader = pBegin; + pBegin += pReq->m_pHeader->m_httpHeaderLen; + if ( pBegin != pEnd ) { + return -1; + } + + if ( shouldFixEndian ) { + fixHeaderIndexEndian( pReq ); + } + + return 0; +} + +static int s_accept_notify = 0; + +static struct lsapi_packet_header ack = {'L', 'S', + LSAPI_REQ_RECEIVED, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; +static inline int notify_req_received( int fd ) +{ + if ( write( fd, &ack, LSAPI_PACKET_HEADER_LEN ) + < LSAPI_PACKET_HEADER_LEN ) { + return -1; + } + return 0; +} + + +static int readReq( LSAPI_Request * pReq ) +{ + int len; + int packetLen; + if ( !pReq ) { + return -1; + } + if ( pReq->m_reqBufSize < 8192 ) { + if ( allocateBuf( pReq, 8192 ) == -1 ) { + return -1; + } + } + + while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN ) { + len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf, pReq->m_reqBufSize ); + if ( len <= 0 ) { + return -1; + } + pReq->m_bufRead += len; + } + pReq->m_reqState = LSAPI_ST_REQ_HEADER; + + packetLen = verifyHeader( &pReq->m_pHeader->m_pktHeader, LSAPI_BEGIN_REQUEST ); + if ( packetLen < 0 ) { + return -1; + } + if ( packetLen > LSAPI_MAX_HEADER_LEN ) { + return -1; + } + + if ( packetLen + 1024 > pReq->m_reqBufSize ) { + if ( allocateBuf( pReq, packetLen + 1024 ) == -1 ) { + return -1; + } + } + while( packetLen > pReq->m_bufRead ) { + len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, packetLen - pReq->m_bufRead ); + if ( len <= 0 ) { + return -1; + } + pReq->m_bufRead += len; + } + if ( parseRequest( pReq, packetLen ) < 0 ) { + return -1; + } + pReq->m_bufProcessed = packetLen; + pReq->m_reqState = LSAPI_ST_REQ_BODY | LSAPI_ST_RESP_HEADER; + + if ( !s_accept_notify ) + return notify_req_received( pReq->m_fd ); + else + return 0; +} + + + +int LSAPI_Init(void) +{ + if ( !g_inited ) { + lsapi_signal(SIGPIPE, lsapi_sigpipe); + lsapi_signal(SIGUSR1, lsapi_siguser1); + +#if defined(SIGXFSZ) && defined(SIG_IGN) + signal(SIGXFSZ, SIG_IGN); +#endif + /* let STDOUT function as STDERR, + just in case writing to STDOUT directly */ + dup2( 2, 1 ); + + if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 ) { + return -1; + } + g_inited = 1; + s_ppid = getppid(); + } + return 0; +} + +void LSAPI_Stop(void) +{ + g_running = 0; +} + +int LSAPI_IsRunning(void) +{ + return g_running; +} + +int LSAPI_InitRequest( LSAPI_Request * pReq, int fd ) +{ + if ( !pReq ) { + return -1; + } + memset( pReq, 0, sizeof( LSAPI_Request ) ); + if ( allocateIovec( pReq, 16 ) == -1 ) { + return -1; + } + pReq->m_pRespBuf = pReq->m_pRespBufPos = (char *)malloc( LSAPI_RESP_BUF_SIZE ); + if ( !pReq->m_pRespBuf ) { + return -1; + } + pReq->m_pRespBufEnd = pReq->m_pRespBuf + LSAPI_RESP_BUF_SIZE; + pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1; + pReq->m_respPktHeaderEnd = &pReq->m_respPktHeader[5]; + if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 ) { + return -1; + } + + if ( isPipe( fd ) ) { + pReq->m_fdListen = -1; + pReq->m_fd = fd; + } else { + pReq->m_fdListen = fd; + pReq->m_fd = -1; + lsapi_set_nblock( fd, 1 ); + } + return 0; +} + +int LSAPI_Is_Listen( void ) +{ + return LSAPI_Is_Listen_r( &g_req ); +} + +int LSAPI_Is_Listen_r( LSAPI_Request * pReq) +{ + return pReq->m_fdListen != -1; +} + + + +int LSAPI_Accept_r( LSAPI_Request * pReq ) +{ + char achPeer[128]; + socklen_t len; + int nodelay = 1; + + if ( !pReq ) { + return -1; + } + if ( LSAPI_Finish_r( pReq ) == -1 ) { + return -1; + } + while( g_running ) { + if ( pReq->m_fd == -1 ) { + if ( pReq->m_fdListen != -1) { + len = sizeof( achPeer ); + pReq->m_fd = accept( pReq->m_fdListen, + (struct sockaddr *)&achPeer, &len ); + if ( pReq->m_fd == -1 ) { + if (( errno == EINTR )||( errno == EAGAIN)) { + continue; + } else { + return -1; + } + } else { + lsapi_set_nblock( pReq->m_fd , 0 ); + if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) { + setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY, + (char *)&nodelay, sizeof(nodelay)); + } + + if ( s_accept_notify ) + return notify_req_received( pReq->m_fd ); + + } + } else { + return -1; + } + } + if ( !readReq( pReq ) ) { + break; + } + lsapi_close( pReq->m_fd ); + pReq->m_fd = -1; + LSAPI_Reset_r( pReq ); + } + return 0; +} + +static struct lsapi_packet_header finish = {'L', 'S', + LSAPI_RESP_END, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; + +int LSAPI_Finish_r( LSAPI_Request * pReq ) +{ + /* finish req body */ + if ( !pReq ) { + return -1; + } + if (pReq->m_reqState) { + if ( pReq->m_fd != -1 ) { + if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { + LSAPI_FinalizeRespHeaders_r( pReq ); + } + if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { + Flush_RespBuf_r( pReq ); + } + + pReq->m_pIovecCur->iov_base = (void *)&finish; + pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; + pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN; + ++pReq->m_pIovecCur; + LSAPI_Flush_r( pReq ); + } + LSAPI_Reset_r( pReq ); + } + return 0; +} + + +void LSAPI_Reset_r( LSAPI_Request * pReq ) +{ + pReq->m_pRespBufPos = pReq->m_pRespBuf; + pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1; + pReq->m_pRespHeaderBufPos = pReq->m_pRespHeaderBuf; + + memset( &pReq->m_pHeaderIndex, 0, + (char *)(pReq->m_respHeaderLen) - (char *)&pReq->m_pHeaderIndex ); +} + + +int LSAPI_Release_r( LSAPI_Request * pReq ) +{ + if ( pReq->m_pReqBuf ) { + free( pReq->m_pReqBuf ); + } + if ( pReq->m_pSpecialEnvList ) { + free( pReq->m_pSpecialEnvList ); + } + if ( pReq->m_pEnvList ) { + free( pReq->m_pEnvList ); + } + if ( pReq->m_pRespHeaderBuf ) { + free( pReq->m_pRespHeaderBuf ); + } + return 0; +} + + +char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex ) +{ + int off; + if ( !pReq || ((unsigned int)headerIndex > H_TRANSFER_ENCODING) ) { + return NULL; + } + off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ]; + if ( !off ) { + return NULL; + } + if ( *(pReq->m_pHttpHeader + off + + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) ) { + *( pReq->m_pHttpHeader + off + + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0; + } + return pReq->m_pHttpHeader + off; +} + +static int readBodyToReqBuf( LSAPI_Request * pReq ) +{ + int bodyLeft; + int len = pReq->m_bufRead - pReq->m_bufProcessed; + if ( len > 0 ) { + return len; + } + pReq->m_bufRead = pReq->m_bufProcessed = pReq->m_pHeader->m_pktHeader.m_packetLen.m_iLen; + + bodyLeft = pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead; + len = pReq->m_reqBufSize - pReq->m_bufRead; + if ( len < 0 ) { + return -1; + } + if ( len > bodyLeft ) { + len = bodyLeft; + } + len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, len ); + if ( len > 0 ) { + pReq->m_bufRead += len; + } + return len; +} + + +int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq ) +{ + if (!pReq || (pReq->m_fd ==-1) ) { + return EOF; + } + if ( pReq->m_bufProcessed >= pReq->m_bufRead ) { + if ( readBodyToReqBuf( pReq ) <= 0 ) { + return EOF; + } + } + ++pReq->m_reqBodyRead; + return (unsigned char)*(pReq->m_pReqBuf + pReq->m_bufProcessed++); +} + + + +int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, int bufLen, int *getLF ) +{ + int len; + int left; + char * pBufEnd = pBuf + bufLen - 1; + char * pBufCur = pBuf; + char * pCur; + char * p; + if (!pReq || (pReq->m_fd ==-1) ||( !pBuf )||(bufLen < 0 )|| !getLF ) { + return -1; + } + *getLF = 0; + while( (left = pBufEnd - pBufCur ) > 0 ) { + + len = pReq->m_bufRead - pReq->m_bufProcessed; + if ( len <= 0 ) { + if ( (len = readBodyToReqBuf( pReq )) <= 0 ) { + *getLF = 1; + break; + } + } + if ( len > left ) { + len = left; + } + pCur = pReq->m_pReqBuf + pReq->m_bufProcessed; + p = memchr( pCur, '\n', len ); + if ( p ) { + len = p - pCur + 1; + } + memmove( pBufCur, pCur, len ); + pBufCur += len; + pReq->m_bufProcessed += len; + + pReq->m_reqBodyRead += len; + + if ( p ) { + *getLF = 1; + break; + } + } + *pBufCur = 0; + + return pBufCur - pBuf; +} + + +int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int bufLen ) +{ + int len; + int total; + /* char *pOldBuf = pBuf; */ + if (!pReq || (pReq->m_fd ==-1) || ( !pBuf )||(bufLen < 0 )) { + return -1; + } + total = pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead; + + if ( total <= 0 ) { + return 0; + } + if ( total < bufLen ) { + bufLen = total; + } + + total = 0; + len = pReq->m_bufRead - pReq->m_bufProcessed; + if ( len > 0 ) { + if ( len > bufLen ) { + len = bufLen; + } + memmove( pBuf, pReq->m_pReqBuf + pReq->m_bufProcessed, len ); + pReq->m_bufProcessed += len; + total += len; + pBuf += len; + bufLen -= len; + } + while( bufLen > 0 ) { + len = lsapi_read( pReq->m_fd, pBuf, bufLen ); + if ( len > 0 ) { + total += len; + pBuf += len; + bufLen -= len; + } else { + if ( len <= 0 ) { + if ( !total) { + return -1; + } + break; + } + } + } + pReq->m_reqBodyRead += total; + return total; + +} + + +int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len ) +{ + struct lsapi_packet_header * pHeader; + const char * pEnd; + const char * p; + int bufLen; + int toWrite; + int packetLen; + + if ( !pReq || !pBuf || (pReq->m_fd == -1) ) { + return -1; + } + if ( len < pReq->m_pRespBufEnd - pReq->m_pRespBufPos ) { + memmove( pReq->m_pRespBufPos, pBuf, len ); + pReq->m_pRespBufPos += len; + return len; + } + + if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { + LSAPI_FinalizeRespHeaders_r( pReq ); + } + pReq->m_reqState |= LSAPI_ST_RESP_BODY; + + pHeader = pReq->m_respPktHeader; + p = pBuf; + pEnd = pBuf + len; + bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf; + + while( ( toWrite = pEnd - p ) > 0 ) { + packetLen = toWrite + bufLen; + if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) { + packetLen = LSAPI_MAX_DATA_PACKET_LEN; + toWrite = packetLen - bufLen; + } + + lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, + packetLen + LSAPI_PACKET_HEADER_LEN ); + pReq->m_totalLen += packetLen + LSAPI_PACKET_HEADER_LEN; + + pReq->m_pIovecCur->iov_base = (void *)pHeader; + pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; + ++pReq->m_pIovecCur; + ++pHeader; + if ( bufLen > 0 ) { + pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf; + pReq->m_pIovecCur->iov_len = bufLen; + pReq->m_pRespBufPos = pReq->m_pRespBuf; + ++pReq->m_pIovecCur; + bufLen = 0; + } + + pReq->m_pIovecCur->iov_base = (void *)p; + pReq->m_pIovecCur->iov_len = toWrite; + ++pReq->m_pIovecCur; + p += toWrite; + + if ( pHeader >= pReq->m_respPktHeaderEnd - 1) { + if ( LSAPI_Flush_r( pReq ) == -1 ) { + return -1; + } + pHeader = pReq->m_respPktHeader; + } + } + if ( pHeader != pReq->m_respPktHeader ) { + if ( LSAPI_Flush_r( pReq ) == -1 ) { + return -1; + } + } + return p - pBuf; +} + +void Flush_RespBuf_r( LSAPI_Request * pReq ) +{ + struct lsapi_packet_header * pHeader = pReq->m_respPktHeader; + int bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf; + pReq->m_reqState |= LSAPI_ST_RESP_BODY; + lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM, + bufLen + LSAPI_PACKET_HEADER_LEN ); + pReq->m_totalLen += bufLen + LSAPI_PACKET_HEADER_LEN; + + pReq->m_pIovecCur->iov_base = (void *)pHeader; + pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN; + ++pReq->m_pIovecCur; + ++pHeader; + if ( bufLen > 0 ) { + pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf; + pReq->m_pIovecCur->iov_len = bufLen; + pReq->m_pRespBufPos = pReq->m_pRespBuf; + ++pReq->m_pIovecCur; + bufLen = 0; + } +} + + + + +int LSAPI_Flush_r( LSAPI_Request * pReq ) +{ + int ret = 0; + int n; + if ( !pReq ) { + return -1; + } + n = pReq->m_pIovecCur - pReq->m_pIovecToWrite; + if (( 0 == n )&&( pReq->m_pRespBufPos == pReq->m_pRespBuf )) { + return 0; + } + if ( pReq->m_fd == -1 ) { + pReq->m_pRespBufPos = pReq->m_pRespBuf; + pReq->m_totalLen = 0; + pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec; + return -1; + } + if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) { + LSAPI_FinalizeRespHeaders_r( pReq ); + } + if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { + Flush_RespBuf_r( pReq ); + } + + n = pReq->m_pIovecCur - pReq->m_pIovecToWrite; + if ( n > 0 ) { + + ret = lsapi_writev( pReq->m_fd, &pReq->m_pIovecToWrite, + n, pReq->m_totalLen ); + if ( ret < pReq->m_totalLen ) { + lsapi_close( pReq->m_fd ); + pReq->m_fd = -1; + ret = -1; + } + pReq->m_totalLen = 0; + pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec; + } + return ret; +} + + +int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len ) +{ + struct lsapi_packet_header header; + const char * pEnd; + const char * p; + int packetLen; + int totalLen; + int ret; + struct iovec iov[2]; + struct iovec *pIov; + + if ( !pReq ) { + return -1; + } + if (( pReq->m_fd == -1 )||(pReq->m_fd == pReq->m_fdListen )) { + return write( 2, pBuf, len ); + } + if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) { + LSAPI_Flush_r( pReq ); + } + + p = pBuf; + pEnd = pBuf + len; + + while( ( packetLen = pEnd - p ) > 0 ) { + if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) { + packetLen = LSAPI_MAX_DATA_PACKET_LEN; + } + + lsapi_buildPacketHeader( &header, LSAPI_STDERR_STREAM, + packetLen + LSAPI_PACKET_HEADER_LEN ); + totalLen = packetLen + LSAPI_PACKET_HEADER_LEN; + + iov[0].iov_base = (void *)&header; + iov[0].iov_len = LSAPI_PACKET_HEADER_LEN; + + iov[1].iov_base = (void *)p; + iov[1].iov_len = packetLen; + p += packetLen; + pIov = iov; + ret = lsapi_writev( pReq->m_fd, &pIov, + 2, totalLen ); + if ( ret < totalLen ) { + lsapi_close( pReq->m_fd ); + pReq->m_fd = -1; + ret = -1; + } + } + return p - pBuf; +} + +static char * GetHeaderVar( LSAPI_Request * pReq, const char * name ) +{ + int i; + for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { + if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { + if ( strcmp( name, CGI_HEADERS[i] ) == 0 ) { + return pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; + } + } + } + if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { + const char *p; + char *pKey; + char *pKeyEnd; + int keyLen; + struct lsapi_header_offset * pCur, *pEnd; + pCur = pReq->m_pUnknownHeader; + pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; + while( pCur < pEnd ) { + pKey = pReq->m_pHttpHeader + pCur->nameOff; + keyLen = pCur->nameLen; + pKeyEnd = pKey + keyLen; + p = &name[5]; + + while(( pKey < pKeyEnd )&&( *p )) { + char ch = toupper( *pKey ); + if ((ch != *p )||(( *p == '_' )&&( ch != '-'))) { + break; + } + ++p; ++pKey; + } + if (( pKey == pKeyEnd )&& (!*p )) { + return pReq->m_pHttpHeader + pCur->valueOff; + } + ++pCur; + } + } + return NULL; +} + + +char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name ) +{ + struct LSAPI_key_value_pair * pBegin = pReq->m_pEnvList; + struct LSAPI_key_value_pair * pEnd = pBegin + pReq->m_pHeader->m_cntEnv; + if ( !pReq || !name ) { + return NULL; + } + if ( strncmp( name, "HTTP_", 5 ) == 0 ) { + return GetHeaderVar( pReq, name ); + } + while( pBegin < pEnd ) { + if ( strcmp( name, pBegin->pKey ) == 0 ) { + return pBegin->pValue; + } + ++pBegin; + } + return NULL; +} + +int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq, + LSAPI_CB_EnvHandler fn, void * arg ) +{ + int i; + int len = 0; + char * pValue; + int ret; + int count = 0; + if ( !pReq || !fn ) { + return -1; + } + for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { + if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { + len = pReq->m_pHeaderIndex->m_headerLen[i]; + pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; + *(pValue + len ) = 0; + ret = (*fn)( HTTP_HEADERS[i], HTTP_HEADER_LEN[i], + pValue, len, arg ); + ++count; + if ( ret <= 0 ) { + return ret; + } + } + } + if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { + char *pKey; + int keyLen; + struct lsapi_header_offset * pCur, *pEnd; + pCur = pReq->m_pUnknownHeader; + pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; + while( pCur < pEnd ) { + pKey = pReq->m_pHttpHeader + pCur->nameOff; + keyLen = pCur->nameLen; + + pValue = pReq->m_pHttpHeader + pCur->valueOff; + *(pValue + pCur->valueLen ) = 0; + ret = (*fn)( pKey, keyLen, + pValue, pCur->valueLen, arg ); + if ( ret <= 0 ) { + return ret; + } + ++pCur; + } + } + return count + pReq->m_pHeader->m_cntUnknownHeaders; + +} + + +int LSAPI_ForeachHeader_r( LSAPI_Request * pReq, + LSAPI_CB_EnvHandler fn, void * arg ) +{ + int i; + int len = 0; + char * pValue; + int ret; + int count = 0; + if ( !pReq || !fn ) { + return -1; + } + for( i = 0; i < H_TRANSFER_ENCODING; ++i ) { + if ( pReq->m_pHeaderIndex->m_headerOff[i] ) { + len = pReq->m_pHeaderIndex->m_headerLen[i]; + pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; + *(pValue + len ) = 0; + ret = (*fn)( CGI_HEADERS[i], CGI_HEADER_LEN[i], + pValue, len, arg ); + ++count; + if ( ret <= 0 ) { + return ret; + } + } + } + if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) { + char achHeaderName[256]; + char *p; + char *pKey; + char *pKeyEnd ; + int keyLen; + struct lsapi_header_offset * pCur, *pEnd; + pCur = pReq->m_pUnknownHeader; + pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders; + while( pCur < pEnd ) { + pKey = pReq->m_pHttpHeader + pCur->nameOff; + keyLen = pCur->nameLen; + if ( keyLen > 250 ) { + keyLen = 250; + } + + pKeyEnd = pKey + keyLen; + memcpy( achHeaderName, "HTTP_", 5 ); + p = &achHeaderName[5]; + + while( pKey < pKeyEnd ) { + char ch = *pKey++; + if ( ch == '-' ) { + *p++ = '_'; + } else { + *p++ = toupper( ch ); + } + } + *p = 0; + keyLen += 5; + + pValue = pReq->m_pHttpHeader + pCur->valueOff; + *(pValue + pCur->valueLen ) = 0; + ret = (*fn)( achHeaderName, keyLen, + pValue, pCur->valueLen, arg ); + if ( ret <= 0 ) { + return ret; + } + ++pCur; + } + } + return count + pReq->m_pHeader->m_cntUnknownHeaders; + +} + +static int EnvForeach( struct LSAPI_key_value_pair * pEnv, + int n, LSAPI_CB_EnvHandler fn, void * arg ) +{ + struct LSAPI_key_value_pair * pEnd = pEnv + n; + int ret; + if ( !pEnv || !fn ) { + return -1; + } + while( pEnv < pEnd ) { + ret = (*fn)( pEnv->pKey, pEnv->keyLen, + pEnv->pValue, pEnv->valLen, arg ); + if ( ret <= 0 ) { + return ret; + } + ++pEnv; + } + return n; +} + + + +int LSAPI_ForeachEnv_r( LSAPI_Request * pReq, + LSAPI_CB_EnvHandler fn, void * arg ) +{ + if ( !pReq || !fn ) { + return -1; + } + if ( pReq->m_pHeader->m_cntEnv > 0 ) { + return EnvForeach( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv, + fn, arg ); + } + return 0; +} + + + +int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq, + LSAPI_CB_EnvHandler fn, void * arg ) +{ + if ( !pReq || !fn ) { + return -1; + } + if ( pReq->m_pHeader->m_cntSpecialEnv > 0 ) { + return EnvForeach( pReq->m_pSpecialEnvList, + pReq->m_pHeader->m_cntSpecialEnv, + fn, arg ); + } + return 0; + +} + + + +int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq ) +{ + if ( !pReq || !pReq->m_pIovec ) { + return -1; + } + if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) ) { + return 0; + } + pReq->m_reqState &= ~LSAPI_ST_RESP_HEADER; + if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf ) { + pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespHeaderBuf; + pReq->m_pIovecCur->iov_len = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf; + pReq->m_totalLen += pReq->m_pIovecCur->iov_len; + ++pReq->m_pIovecCur; + } + + pReq->m_pIovec->iov_len = sizeof( struct lsapi_resp_header) + + pReq->m_respHeader.m_respInfo.m_cntHeaders * sizeof( short ); + pReq->m_totalLen += pReq->m_pIovec->iov_len; + + lsapi_buildPacketHeader( &pReq->m_respHeader.m_pktHeader, + LSAPI_RESP_HEADER, pReq->m_totalLen ); + pReq->m_pIovec->iov_base = (void *)&pReq->m_respHeader; + pReq->m_pIovecToWrite = pReq->m_pIovec; + return 0; +} + + + + +int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, char * pBuf, int len ) +{ + if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX ) { + return -1; + } + if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) { + return -1; + } + if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) { + return -1; + } + if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) { + int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf; + newlen -= newlen % 4096; + if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) { + return -1; + } + } + memmove( pReq->m_pRespHeaderBufPos, pBuf, len ); + pReq->m_pRespHeaderBufPos += len; + *pReq->m_pRespHeaderBufPos++ = 0; + ++len; /* add one byte padding for \0 */ + pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len; + ++pReq->m_respHeader.m_respInfo.m_cntHeaders; + return 0; +} + + +int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog ) +{ + int ret; + int fd; + int flag = 1; + int addr_len; + + switch( pServerAddr->sa_family ) { + case AF_INET: + addr_len = 16; + break; + case AF_INET6: + addr_len = sizeof( struct sockaddr_in6 ); + break; + case AF_UNIX: + addr_len = sizeof( struct sockaddr_un ); + unlink( ((struct sockaddr_un *)pServerAddr)->sun_path ); + break; + default: + return -1; + } + + fd = socket( pServerAddr->sa_family, SOCK_STREAM, 0 ); + if ( fd == -1 ) { + return -1; + } + + fcntl( fd, F_SETFD, FD_CLOEXEC ); + + if(setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, + (char *)( &flag ), sizeof(flag)) == 0) { + ret = bind( fd, pServerAddr, addr_len ); + if ( !ret ) { + ret = listen( fd, backlog ); + if ( !ret ) { + return fd; + } + } + } + + ret = errno; + close(fd); + errno = ret; + return -1; + +} + +int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr ) +{ + char achAddr[256]; + char * p = achAddr; + char * pEnd; + struct addrinfo *res, hints; + int doAddrInfo = 0; + int port; + + if ( !pBind ) { + return -1; + } + + while( isspace( *pBind ) ) { + ++pBind; + } + + strncpy( achAddr, pBind, 256 ); + + switch( *p ) { + case '/': + pAddr->sa_family = AF_UNIX; + strncpy( ((struct sockaddr_un *)pAddr)->sun_path, p, + sizeof(((struct sockaddr_un *)pAddr)->sun_path) ); + return 0; + + case '[': + pAddr->sa_family = AF_INET6; + ++p; + pEnd = strchr( p, ']' ); + if ( !pEnd ) + return -1; + *pEnd++ = 0; + + if ( *p == '*' ) { + strcpy( achAddr, "::" ); + p = achAddr; + } + doAddrInfo = 1; + break; + + default: + pAddr->sa_family = AF_INET; + pEnd = strchr( p, ':' ); + if ( !pEnd ) { + return -1; + } + *pEnd++ = 0; + + doAddrInfo = 0; + if ( *p == '*' ) { + ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY); + } else { + if (!strcasecmp( p, "localhost" ) ) { + ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK ); + } else { + ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p ); + if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST) { + doAddrInfo = 1; + } + } + } + break; + } + if ( *pEnd == ':' ) { + ++pEnd; + } + + port = atoi( pEnd ); + if (( port <= 0 )||( port > 65535 )) { + return -1; + } + if ( doAddrInfo ) { + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = pAddr->sa_family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if ( getaddrinfo(p, NULL, &hints, &res) ) { + return -1; + } + + memcpy(pAddr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + } + + if ( pAddr->sa_family == AF_INET ) { + ((struct sockaddr_in *)pAddr)->sin_port = htons( port ); + } else { + ((struct sockaddr_in6 *)pAddr)->sin6_port = htons( port ); + } + return 0; + +} + +int LSAPI_CreateListenSock( const char * pBind, int backlog ) +{ + char serverAddr[128]; + int ret; + int fd = -1; + ret = LSAPI_ParseSockAddr( pBind, (struct sockaddr *)serverAddr ); + if ( !ret ) { + fd = LSAPI_CreateListenSock2( (struct sockaddr *)serverAddr, backlog ); + } + return fd; +} + +static fn_select_t g_fnSelect = select; + +typedef struct _lsapi_child_status +{ + int m_pid; + + volatile short m_iKillSent; + volatile short m_inProcess; + + volatile long m_tmWaitBegin; + volatile long m_tmReqBegin; + volatile long m_tmLastCheckPoint; +} +lsapi_child_status; + +static lsapi_child_status * s_pChildStatus = NULL; + +typedef struct _lsapi_prefork_server +{ + int m_fd; + int m_iMaxChildren; + int m_iExtraChildren; + int m_iCurChildren; + int m_iMaxIdleChildren; + int m_iServerMaxIdle; + int m_iChildrenMaxIdleTime; + int m_iMaxReqProcessTime; + int m_iAvoidFork; + + lsapi_child_status * m_pChildrenStatus; + +}lsapi_prefork_server; + +static lsapi_prefork_server * g_prefork_server = NULL; + +int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork ) +{ + if ( g_prefork_server ) { + return 0; + } + if ( max_children <= 1 ) { + return -1; + } + if ( max_children >= 10000) { + max_children = 10000; + } + + + g_prefork_server = (lsapi_prefork_server *)malloc( sizeof( lsapi_prefork_server ) ); + if ( !g_prefork_server ) { + return -1; + } + memset( g_prefork_server, 0, sizeof( lsapi_prefork_server ) ); + + if ( fp != NULL ) { + g_fnSelect = fp; + } + + s_ppid = getppid(); + g_prefork_server->m_iAvoidFork = avoidFork; + g_prefork_server->m_iMaxChildren = max_children; + + g_prefork_server->m_iExtraChildren = ( avoidFork ) ? 0 : (max_children / 3) ; + g_prefork_server->m_iMaxIdleChildren = ( avoidFork ) ? (max_children + 1) : (max_children / 3); + g_prefork_server->m_iChildrenMaxIdleTime = 300; + g_prefork_server->m_iMaxReqProcessTime = 300; + return 0; +} + +void LSAPI_Set_Server_fd( int fd ) +{ + if( g_prefork_server ) { + g_prefork_server->m_fd = fd; + } +} + + +static int lsapi_accept( int fdListen ) +{ + int fd; + int nodelay = 1; + socklen_t len; + char achPeer[128]; + + len = sizeof( achPeer ); + fd = accept( fdListen, (struct sockaddr *)&achPeer, &len ); + if ( fd != -1 ) { + if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) { + setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, + (char *)&nodelay, sizeof(nodelay)); + } + + if ( s_accept_notify ) + notify_req_received( fd ); + } + return fd; + +} + + + + +static int s_req_processed = 0; +static int s_max_reqs = 10000; +static int s_max_idle_secs = 300; + +static int s_stop; + +static void lsapi_cleanup(int signal) +{ + s_stop = signal; +} + +static lsapi_child_status * find_child_status( int pid ) +{ + lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; + lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatus + g_prefork_server->m_iMaxChildren * 2; + while( pStatus < pEnd ) { + if ( pStatus->m_pid == pid ) { + return pStatus; + } + ++pStatus; + } + return NULL; +} + + + +static void lsapi_sigchild( int signal ) +{ + int status, pid; + lsapi_child_status * child_status; + while( 1 ) { + pid = waitpid( -1, &status, WNOHANG|WUNTRACED ); + if ( pid <= 0 ) { + break; + } + child_status = find_child_status( pid ); + if ( child_status ) { + child_status->m_pid = 0; + } + --g_prefork_server->m_iCurChildren; + } + +} + +static int lsapi_init_children_status() +{ + int size = 4096; + + char * pBuf; + size = g_prefork_server->m_iMaxChildren * sizeof( lsapi_child_status ) * 2; + size = (size + 4095 ) / 4096 * 4096; + pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_SHARED, -1, 0 ); + if ( pBuf == MAP_FAILED ) { + perror( "Anonymous mmap() failed" ); + return -1; + } + memset( pBuf, 0, size ); + g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf; + return 0; +} + +static void lsapi_check_child_status( long tmCur ) +{ + int idle = 0; + int tobekilled; + int dying = 0; + lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus; + lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatus + g_prefork_server->m_iMaxChildren * 2; + while( pStatus < pEnd ) { + tobekilled = pStatus->m_iKillSent; + if ( pStatus->m_pid != 0 ) { + if ( !tobekilled ) { + if ( !pStatus->m_inProcess ) { + + if (( g_prefork_server->m_iCurChildren - dying > g_prefork_server->m_iMaxChildren)|| + ( idle >= g_prefork_server->m_iMaxIdleChildren )) { + + tobekilled = 1; + } else { + if (( s_max_idle_secs> 0)&&(tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5 )) { + tobekilled = 1; + } + } + if ( !tobekilled ) { + ++idle; + } + } else { + if ( tmCur - pStatus->m_tmReqBegin > + g_prefork_server->m_iMaxReqProcessTime ) { + tobekilled = 1; + } + } + } else { + if ( pStatus->m_inProcess ) { + tobekilled = pStatus->m_iKillSent = 0; + } + } + if ( tobekilled ) { + tobekilled = 0; + if ( pStatus->m_iKillSent > 5 ) { + tobekilled = SIGKILL; + } else { + if ( pStatus->m_iKillSent == 3 ) { + tobekilled = SIGTERM; + } else { + if ( pStatus->m_iKillSent == 1 ) { + tobekilled = SIGUSR1; + } + } + } + if ( tobekilled ) { + kill( pStatus->m_pid, tobekilled ); + } + ++pStatus->m_iKillSent; + ++dying; + } + + } else { + ++dying; + } + ++pStatus; + } +} + +static int lsapi_all_children_must_die() +{ + int maxWait; + int sec =0; + g_prefork_server->m_iMaxReqProcessTime = 10; + g_prefork_server->m_iMaxIdleChildren = -1; + maxWait = 15; + + while( g_prefork_server->m_iCurChildren && (sec < maxWait) ) { + lsapi_check_child_status(time(NULL)); + sleep( 1 ); + sec++; + } + if ( g_prefork_server->m_iCurChildren != 0 ) { + kill( -getpgrp(), SIGKILL ); + } + return 0; +} + + + +static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Request * pReq ) +{ + struct sigaction act, old_term, old_quit, old_int, + old_usr1, old_child; + lsapi_child_status * child_status; + int wait_secs = 0; + int ret = 0; + int pid; + time_t lastTime = 0; + time_t curTime = 0; + fd_set readfds; + struct timeval timeout; + + lsapi_init_children_status(); + + setsid(); + + act.sa_flags = 0; + act.sa_handler = lsapi_sigchild; + if( sigaction( SIGCHLD, &act, &old_child ) ) { + perror( "Can't set signal handler for SIGCHILD" ); + return -1; + } + + /* Set up handler to kill children upon exit */ + act.sa_flags = 0; + act.sa_handler = lsapi_cleanup; + if( sigaction( SIGTERM, &act, &old_term ) || + sigaction( SIGINT, &act, &old_int ) || + sigaction( SIGUSR1, &act, &old_usr1 ) || + sigaction( SIGQUIT, &act, &old_quit )) { + perror( "Can't set signals" ); + return -1; + } + s_stop = 0; + while( !s_stop ) { + if ( ret ) { + curTime = time( NULL ); + } else { + ++curTime; + } + if (curTime != lastTime ) { + lastTime = curTime; + if (s_ppid && (getppid() != s_ppid )) { + break; + } + lsapi_check_child_status(curTime ); + if (pServer->m_iServerMaxIdle) { + if ( pServer->m_iCurChildren <= 0 ) { + ++wait_secs; + if ( wait_secs > pServer->m_iServerMaxIdle ) { + return -1; + } + } else { + wait_secs = 0; + } + } + } + + if ( pServer->m_iCurChildren >= (pServer->m_iMaxChildren + pServer->m_iExtraChildren ) ) { + usleep( 100000 ); + continue; + } + + FD_ZERO( &readfds ); + FD_SET( pServer->m_fd, &readfds ); + timeout.tv_sec = 1; timeout.tv_usec = 0; + if ((ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout)) == 1 ) { + if ( pServer->m_iCurChildren >= 0 ) { + usleep( 10 ); + FD_ZERO( &readfds ); + FD_SET( pServer->m_fd, &readfds ); + timeout.tv_sec = 0; timeout.tv_usec = 0; + if ( (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout) == 0 ) { + continue; + } + } + } else { + if ( ret == -1 ) { + if ( errno == EINTR ) { + continue; + } + /* perror( "select()" ); */ + break; + } else { + continue; + } + } + + pReq->m_fd = lsapi_accept( pServer->m_fd ); + if ( pReq->m_fd != -1 ) { + child_status = find_child_status( 0 ); + pid = fork(); + if ( !pid ) { + g_prefork_server = NULL; + s_ppid = getppid(); + s_req_processed = 0; + s_pChildStatus = child_status; + child_status->m_iKillSent = 0; + lsapi_set_nblock( pReq->m_fd, 0 ); + + /* don't catch our signals */ + sigaction( SIGCHLD, &old_child, 0 ); + sigaction( SIGTERM, &old_term, 0 ); + sigaction( SIGQUIT, &old_quit, 0 ); + sigaction( SIGINT, &old_int, 0 ); + sigaction( SIGUSR1, &old_usr1, 0 ); + return 0; + } else { + if ( pid == -1 ) { + perror( "fork() failed, please increase process limit" ); + } else { + ++pServer->m_iCurChildren; + if ( child_status ) { + child_status->m_pid = pid; + child_status->m_iKillSent = 0; + child_status->m_tmWaitBegin = time(NULL); + } + } + } + close( pReq->m_fd ); + pReq->m_fd = -1; + + } else { + if (( errno == EINTR )||( errno == EAGAIN)) { + continue; + } + perror( "accept() failed" ); + return -1; + } + } + sigaction( SIGUSR1, &old_usr1, 0 ); + kill( -getpgrp(), SIGUSR1 ); + lsapi_all_children_must_die(); /* Sorry, children ;-) */ + return -1; + +} + +int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq ) +{ + int fd; + int ret; + int wait_secs; + fd_set readfds; + struct timeval timeout; + + LSAPI_Finish_r( pReq ); + + + if ( g_prefork_server ) { + if ( g_prefork_server->m_fd != -1 ) { + if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 ) { + return -1; + } + } + } + if ( s_req_processed >= s_max_reqs ) { + return -1; + } + + if ( s_pChildStatus ) { + s_pChildStatus->m_tmWaitBegin = time( NULL ); + } + + while( g_running ) { + if ( pReq->m_fd != -1 ) { + fd = pReq->m_fd; + } else { + if ( pReq->m_fdListen != -1 ) { + fd = pReq->m_fdListen; + } else { + return -1; + } + } + wait_secs = 0; + while( 1 ) { + if ( !g_running ) { + return -1; + } + if (( s_pChildStatus )&&( s_pChildStatus->m_iKillSent )) { + return -1; + } + FD_ZERO( &readfds ); + FD_SET( fd, &readfds ); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + ret = (*g_fnSelect)(fd+1, &readfds, NULL, NULL, &timeout); + if ( ret == 0 ) { + if ( s_pChildStatus ) { + s_pChildStatus->m_inProcess = 0; + } + ++wait_secs; + if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs )) { + return -1; + } + if ( s_ppid &&( getppid() != s_ppid)) { + return -1; + } + } else { + if ( ret == -1 ) { + if ( errno == EINTR ) { + continue; + } else { + return -1; + } + } else { + if ( ret >= 1 ) { + if (( s_pChildStatus )&&( s_pChildStatus->m_iKillSent )) { + return -1; + } + if ( fd == pReq->m_fdListen ) { + pReq->m_fd = lsapi_accept( pReq->m_fdListen ); + if ( pReq->m_fd != -1 ) { + fd = pReq->m_fd; + lsapi_set_nblock( fd, 0 ); + } else { + if (( errno == EINTR )||( errno == EAGAIN)) { + continue; + } + return -1; + } + } else { + break; + } + } + } + } + } + if ( !readReq( pReq ) ) { + if ( s_pChildStatus ) { + s_pChildStatus->m_inProcess = 1; + s_pChildStatus->m_tmReqBegin = s_pChildStatus->m_tmLastCheckPoint = time(NULL); + } + ++s_req_processed; + return 0; + } + lsapi_close( pReq->m_fd ); + pReq->m_fd = -1; + LSAPI_Reset_r( pReq ); + } + return -1; + +} + +void LSAPI_Set_Max_Reqs( int reqs ) +{ + s_max_reqs = reqs; +} + +void LSAPI_Set_Max_Idle( int secs ) +{ + s_max_idle_secs = secs; +} + +void LSAPI_Set_Max_Children( int maxChildren ) +{ + if ( g_prefork_server ) { + g_prefork_server->m_iMaxChildren = maxChildren; + } +} + +void LSAPI_Set_Extra_Children( int extraChildren ) +{ + if (( g_prefork_server )&&( extraChildren >= 0 )) { + g_prefork_server->m_iExtraChildren = extraChildren; + } +} + +void LSAPI_Set_Max_Process_Time( int secs ) +{ + if (( g_prefork_server )&&( secs > 0 )) { + g_prefork_server->m_iMaxReqProcessTime = secs; + } +} + + +void LSAPI_Set_Max_Idle_Children( int maxIdleChld ) +{ + if (( g_prefork_server )&&( maxIdleChld > 0 )) { + g_prefork_server->m_iMaxIdleChildren = maxIdleChld; + } +} + +void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle ) +{ + if ( g_prefork_server ) { + g_prefork_server->m_iServerMaxIdle = serverMaxIdle; + } +} + +void LSAPI_Set_Slow_Req_Msecs( int msecs ) +{ + s_slow_req_msecs = msecs; +} + +int LSAPI_Get_Slow_Req_Msecs() +{ + return s_slow_req_msecs; +} + +void LSAPI_No_Check_ppid() +{ + s_ppid = 0; +} + +#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +#include <crt_externs.h> +#else +extern char ** environ; +#endif +static void unset_lsapi_envs() +{ + char **env; +#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + env = *_NSGetEnviron(); +#else + env = environ; +#endif + while( env != NULL && *env != NULL ) { + if ( !strncmp(*env, "LSAPI_", 6) || + !strncmp( *env, "PHP_LSAPI_", 10 ) ) { + char ** del = env; + do { + *del = del[1]; + } while( *del++ ); + } else { + ++env; + } + } +} + +void LSAPI_Init_Env_Parameters( fn_select_t fp ) +{ + const char *p; + int n; + int avoidFork = 0; + p = getenv( "PHP_LSAPI_MAX_REQUESTS" ); + if ( !p ) { + p = getenv( "LSAPI_MAX_REQS" ); + } + if ( p ) { + n = atoi( p ); + if ( n > 0 ) { + LSAPI_Set_Max_Reqs( n ); + } + } + + p = getenv( "LSAPI_AVOID_FORK" ); + if ( p ) { + avoidFork = atoi( p ); + } + + p = getenv( "LSAPI_ACCEPT_NOTIFY" ); + if ( p ) { + s_accept_notify = atoi( p ); + } + + p = getenv( "LSAPI_SLOW_REQ_MSECS" ); + if ( p ) { + n = atoi( p ); + LSAPI_Set_Slow_Req_Msecs( n ); + } + + +#if defined( RLIMIT_CORE ) + p = getenv( "LSAPI_ALLOW_CORE_DUMP" ); + if ( !p ) { + struct rlimit limit = { 0, 0 }; + setrlimit( RLIMIT_CORE, &limit ); + } +#endif + + p = getenv( "LSAPI_MAX_IDLE" ); + if ( p ) { + n = atoi( p ); + LSAPI_Set_Max_Idle( n ); + } + + if ( LSAPI_Is_Listen() ) { + n = 0; + p = getenv( "PHP_LSAPI_CHILDREN" ); + if ( !p ) { + p = getenv( "LSAPI_CHILDREN" ); + } + if ( p ) { + n = atoi( p ); + } + if ( n > 1 ) { + LSAPI_Init_Prefork_Server( n, fp, avoidFork ); + LSAPI_Set_Server_fd( g_req.m_fdListen ); + } + + p = getenv( "LSAPI_EXTRA_CHILDREN" ); + if ( p ) { + LSAPI_Set_Extra_Children( atoi( p ) ); + } + + p = getenv( "LSAPI_MAX_IDLE_CHILDREN" ); + if ( p ) { + LSAPI_Set_Max_Idle_Children( atoi( p ) ); + } + p = getenv( "LSAPI_PGRP_MAX_IDLE" ); + if ( p ) { + LSAPI_Set_Server_Max_Idle_Secs( atoi( p ) ); + } + + p = getenv( "LSAPI_MAX_PROCESS_TIME" ); + if ( p ) { + LSAPI_Set_Max_Process_Time( atoi( p ) ); + } + if ( getenv( "LSAPI_PPID_NO_CHECK" ) ) { + LSAPI_No_Check_ppid(); + } + } + unset_lsapi_envs(); +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ + + diff --git a/sapi/litespeed/lsapilib.h b/sapi/litespeed/lsapilib.h new file mode 100644 index 0000000..3a987b4 --- /dev/null +++ b/sapi/litespeed/lsapilib.h @@ -0,0 +1,363 @@ + +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 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 at 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: George Wang <gwang@litespeedtech.com> | + +----------------------------------------------------------------------+ +*/ + +/* +Copyright (c) 2007, Lite Speed Technologies Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the Lite Speed Technologies Inc nor the + names of its contributors may be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + + +#ifndef _LSAPILIB_H_ +#define _LSAPILIB_H_ + +#if defined (c_plusplus) || defined (__cplusplus) +extern "C" { +#endif + +#include <stddef.h> +#include <lsapidef.h> + +#include <sys/time.h> +#include <sys/types.h> + +struct LSAPI_key_value_pair +{ + char * pKey; + char * pValue; + int keyLen; + int valLen; +}; + + +#define LSAPI_MAX_RESP_HEADERS 100 + +typedef struct lsapi_request +{ + int m_fdListen; + int m_fd; + + long m_lLastActive; + long m_lReqBegin; + + char * m_pReqBuf; + int m_reqBufSize; + + char * m_pRespBuf; + char * m_pRespBufEnd; + char * m_pRespBufPos; + + char * m_pRespHeaderBuf; + char * m_pRespHeaderBufEnd; + char * m_pRespHeaderBufPos; + + + struct iovec * m_pIovec; + struct iovec * m_pIovecEnd; + struct iovec * m_pIovecCur; + struct iovec * m_pIovecToWrite; + + struct lsapi_packet_header * m_respPktHeaderEnd; + + struct lsapi_req_header * m_pHeader; + struct LSAPI_key_value_pair * m_pEnvList; + struct LSAPI_key_value_pair * m_pSpecialEnvList; + int m_envListSize; + int m_specialEnvListSize; + + struct lsapi_http_header_index * m_pHeaderIndex; + struct lsapi_header_offset * m_pUnknownHeader; + + char * m_pScriptFile; + char * m_pScriptName; + char * m_pQueryString; + char * m_pHttpHeader; + char * m_pRequestMethod; + int m_totalLen; + int m_reqState; + int m_reqBodyRead; + int m_bufProcessed; + int m_bufRead; + + struct lsapi_packet_header m_respPktHeader[5]; + + struct lsapi_resp_header m_respHeader; + short m_respHeaderLen[LSAPI_MAX_RESP_HEADERS]; + +}LSAPI_Request; + +extern LSAPI_Request g_req; + + +/* return: >0 continue, ==0 stop, -1 failed */ +typedef int (*LSAPI_CB_EnvHandler )( const char * pKey, int keyLen, + const char * pValue, int valLen, void * arg ); + + +int LSAPI_Init(void); + +void LSAPI_Stop(void); + +int LSAPI_Is_Listen_r( LSAPI_Request * pReq); + +int LSAPI_InitRequest( LSAPI_Request * pReq, int fd ); + +int LSAPI_Accept_r( LSAPI_Request * pReq ); + +void LSAPI_Reset_r( LSAPI_Request * pReq ); + +int LSAPI_Finish_r( LSAPI_Request * pReq ); + +int LSAPI_Release_r( LSAPI_Request * pReq ); + +char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex ); + +int LSAPI_ForeachHeader_r( LSAPI_Request * pReq, + LSAPI_CB_EnvHandler fn, void * arg ); + +int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq, + LSAPI_CB_EnvHandler fn, void * arg ); + +int LSAPI_ForeachEnv_r( LSAPI_Request * pReq, + LSAPI_CB_EnvHandler fn, void * arg ); + +int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq, + LSAPI_CB_EnvHandler fn, void * arg ); + +char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name ); + + +int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int len ); + +int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq ); + +int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, int bufLen, int *getLF ); + + +int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq ); + +int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len ); + +int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len ); + +int LSAPI_Flush_r( LSAPI_Request * pReq ); + +int LSAPI_AppendRespHeader_r( LSAPI_Request * pHeader, char * pBuf, int len ); + +static inline int LSAPI_SetRespStatus_r( LSAPI_Request * pReq, int code ) +{ + if ( !pReq ) + return -1; + pReq->m_respHeader.m_respInfo.m_status = code; + return 0; +} + +static inline char * LSAPI_GetQueryString_r( LSAPI_Request * pReq ) +{ + if ( pReq ) + return pReq->m_pQueryString; + return NULL; +} + + +static inline char * LSAPI_GetScriptFileName_r( LSAPI_Request * pReq ) +{ + if ( pReq ) + return pReq->m_pScriptFile; + return NULL; +} + + +static inline char * LSAPI_GetScriptName_r( LSAPI_Request * pReq ) +{ + if ( pReq ) + return pReq->m_pScriptName; + return NULL; +} + + +static inline char * LSAPI_GetRequestMethod_r( LSAPI_Request * pReq) +{ + if ( pReq ) + return pReq->m_pRequestMethod; + return NULL; +} + + + +static inline int LSAPI_GetReqBodyLen_r( LSAPI_Request * pReq ) +{ + if ( pReq ) + return pReq->m_pHeader->m_reqBodyLen; + return -1; +} + +static inline int LSAPI_GetReqBodyRemain_r( LSAPI_Request * pReq ) +{ + if ( pReq ) + return pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead; + return -1; +} + + +int LSAPI_Is_Listen(void); + +static inline int LSAPI_Accept( void ) +{ return LSAPI_Accept_r( &g_req ); } + +static inline int LSAPI_Finish(void) +{ return LSAPI_Finish_r( &g_req ); } + +static inline char * LSAPI_GetHeader( int headerIndex ) +{ return LSAPI_GetHeader_r( &g_req, headerIndex ); } + +static inline int LSAPI_ForeachHeader( LSAPI_CB_EnvHandler fn, void * arg ) +{ return LSAPI_ForeachHeader_r( &g_req, fn, arg ); } + +static inline int LSAPI_ForeachOrgHeader( + LSAPI_CB_EnvHandler fn, void * arg ) +{ return LSAPI_ForeachOrgHeader_r( &g_req, fn, arg ); } + +static inline int LSAPI_ForeachEnv( LSAPI_CB_EnvHandler fn, void * arg ) +{ return LSAPI_ForeachEnv_r( &g_req, fn, arg ); } + +static inline int LSAPI_ForeachSpecialEnv( LSAPI_CB_EnvHandler fn, void * arg ) +{ return LSAPI_ForeachSpecialEnv_r( &g_req, fn, arg ); } + +static inline char * LSAPI_GetEnv( const char * name ) +{ return LSAPI_GetEnv_r( &g_req, name ); } + +static inline char * LSAPI_GetQueryString() +{ return LSAPI_GetQueryString_r( &g_req ); } + +static inline char * LSAPI_GetScriptFileName() +{ return LSAPI_GetScriptFileName_r( &g_req ); } + +static inline char * LSAPI_GetScriptName() +{ return LSAPI_GetScriptName_r( &g_req ); } + +static inline char * LSAPI_GetRequestMethod() +{ return LSAPI_GetRequestMethod_r( &g_req ); } + +static inline int LSAPI_GetReqBodyLen() +{ return LSAPI_GetReqBodyLen_r( &g_req ); } + +static inline int LSAPI_GetReqBodyRemain() +{ return LSAPI_GetReqBodyRemain_r( &g_req ); } + +static inline int LSAPI_ReadReqBody( char * pBuf, int len ) +{ return LSAPI_ReadReqBody_r( &g_req, pBuf, len ); } + +static inline int LSAPI_ReqBodyGetChar() +{ return LSAPI_ReqBodyGetChar_r( &g_req ); } + +static inline int LSAPI_ReqBodyGetLine( char * pBuf, int len, int *getLF ) +{ return LSAPI_ReqBodyGetLine_r( &g_req, pBuf, len, getLF ); } + + + +static inline int LSAPI_FinalizeRespHeaders(void) +{ return LSAPI_FinalizeRespHeaders_r( &g_req ); } + +static inline int LSAPI_Write( const char * pBuf, int len ) +{ return LSAPI_Write_r( &g_req, pBuf, len ); } + +static inline int LSAPI_Write_Stderr( const char * pBuf, int len ) +{ return LSAPI_Write_Stderr_r( &g_req, pBuf, len ); } + +static inline int LSAPI_Flush() +{ return LSAPI_Flush_r( &g_req ); } + +static inline int LSAPI_AppendRespHeader( char * pBuf, int len ) +{ return LSAPI_AppendRespHeader_r( &g_req, pBuf, len ); } + +static inline int LSAPI_SetRespStatus( int code ) +{ return LSAPI_SetRespStatus_r( &g_req, code ); } + +int LSAPI_IsRunning(void); + +int LSAPI_CreateListenSock( const char * pBind, int backlog ); + +typedef int (*fn_select_t)( int, fd_set *, fd_set *, fd_set *, struct timeval * ); + +int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork ); + +void LSAPI_Set_Server_fd( int fd ); + +int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq ); + +void LSAPI_Set_Max_Reqs( int reqs ); + +void LSAPI_Set_Max_Idle( int secs ); + +void LSAPI_Set_Max_Children( int maxChildren ); + +void LSAPI_Set_Max_Idle_Children( int maxIdleChld ); + +void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle ); + +void LSAPI_Set_Max_Process_Time( int secs ); + +void LSAPI_Init_Env_Parameters( fn_select_t fp ); + +void LSAPI_Set_Slow_Req_Msecs( int msecs ); + +int LSAPI_Get_Slow_Req_Msecs( ); + + +#if defined (c_plusplus) || defined (__cplusplus) +} +#endif + + +#endif + + + + + + + |