From: George Wang Date: Fri, 13 Jan 2006 03:21:51 +0000 (+0000) Subject: Initial checkin of LiteSpeed SAPI module X-Git-Tag: RELEASE_1_0_4~40 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=18d36265fde4c7c1ecad1e2399e67b98f8292be2;p=php Initial checkin of LiteSpeed SAPI module --- diff --git a/sapi/litespeed/Makefile.frag b/sapi/litespeed/Makefile.frag new file mode 100644 index 0000000000..e1af2b90ca --- /dev/null +++ b/sapi/litespeed/Makefile.frag @@ -0,0 +1,3 @@ +$(SAPI_LITESPEED_PATH): $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) + $(BUILD_LITESPEED) + diff --git a/sapi/litespeed/README b/sapi/litespeed/README new file mode 100644 index 0000000000..bd57f1f315 --- /dev/null +++ b/sapi/litespeed/README @@ -0,0 +1,118 @@ +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 two major enhancements: better performance and +support for dynamic PHP configuration changes 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 mod_php is that "php.ini" +is the only way to set PHP configuration, and cannot be changed at +runtime via configuration files like .htaccess files or web server's +virtual host configuration. As FastCGI PHP is usually shared at server +level by all virtual hosts, it is big security concern to use it in a +shared hosting environment. LiteSpeed SAPI is carefully designed to +address this issue. It accepts same flexible configuration overridden +methods as those supported in mod_php. LiteSpeed SAPI also uses the +same configuration directives as Apache mod_php. + +Therefore, with above enhancements, LiteSpeed SAPI is highly +recommended over FastCGI SAPI for using PHP 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. + + +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 admin 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 match the value of "Max + Connections". + +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. + +Tuning +------ + +There are two environment variables that can be tweaked to control the +behavior of LiteSpeed PHP. + +PHP_LSAPI_CHILDREN (no default) + +In order to handle multiple requests concurrently, LiteSpeed web +server can either spawn multiple PHP processes; or spawn one process, +and this process will create a number of child processes to handle +multiple requests simultaneously. + +The web server will create PHP processes specified by "Instance" in +LSAPI application configuration. For one PHP process launched by the +server, if PHP_LSAPI_CHILDREN is not set, it will not create any child +process; if PHP_LSAPI_CHILDREN is set, it will spawn a number of child +processes specified by PHP_LSAPI_CHILDREN. Usually, it should match +"Max Connections" configured for the LSAPI application, and both +values should not be set over 100 in most cases. + +PHP_LSAPI_MAX_REQUESTS (default value: 500) + +This controls how many requests each child process will handle before +exit. When one process exits, another will be created. This tuning is +necessary because several PHP functions have been identified having +memory leaks. If the PHP processes were left around forever, they +could become very inefficient. + + +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 0000000000..e34d4dcdb5 --- /dev/null +++ b/sapi/litespeed/config.m4 @@ -0,0 +1,36 @@ +dnl +dnl $Id$ +dnl + +AC_MSG_CHECKING(for LiteSpeed support) + +AC_ARG_WITH(litespeed, +[ --with-litespeed Build PHP as litespeed module], +[ + PHP_SAPI_LITESPEED=$withval +],[ + PHP_SAPI_LITESPEED=no +]) + +if test "$PHP_SAPI_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_SUBST(SAPI_LITESPEED_PATH) + 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_SAPI_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_SAPI_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_SAPI_OBJS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_LITESPEED_PATH)" + ;; + esac + + PHP_SUBST(BUILD_LITESPEED) +fi + +AC_MSG_RESULT($PHP_SAPI_LITESPEED) diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c new file mode 100644 index 0000000000..c8c84201c5 --- /dev/null +++ b/sapi/litespeed/lsapi_main.c @@ -0,0 +1,781 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 4 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2005 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.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 | + +----------------------------------------------------------------------+ +*/ + + +#include "php.h" +#include "SAPI.h" +#include "php_main.h" +#include "php_ini.h" +#include "php_variables.h" +#include "zend_highlight.h" + +#include "lsapilib.h" + +#include +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#ifdef PHP_WIN32 +#include +#include +#include "win32/php_registry.h" +#else +#include +#endif +#include + +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SIGNAL_H +#include +#endif + +#include +#include +#include + + +#define SAPI_LSAPI_MAX_HEADER_LENGTH 2048 +static char s_headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH]; + +static int lsapi_mode = 1; +static char *php_self = ""; +static char *script_filename = ""; + +#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 + + +/* {{{ php_lsapi_startup + */ +static int php_lsapi_startup(sapi_module_struct *sapi_module) +{ + if (php_module_startup(sapi_module, NULL, 0)==FAILURE) { + return FAILURE; + } + return SUCCESS; +} +/* }}} */ + + + +/* {{{ 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) +{ + LSAPI_Finish(); + 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; +} + + + +/* {{{ sapi_lsapi_register_variables + */ +static void sapi_lsapi_register_variables(zval *track_vars_array TSRMLS_DC) +{ + + if ( lsapi_mode ) + { + LSAPI_ForeachHeader( add_variable, track_vars_array ); + LSAPI_ForeachEnv( add_variable, track_vars_array ); + php_import_environment_variables(track_vars_array TSRMLS_CC); + + php_register_variable("PHP_SELF", (SG(request_info).request_uri ? SG(request_info).request_uri:""), 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) { + 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; + + hd = sapi_get_default_content_type(TSRMLS_C); + len = snprintf( s_headerBuf, SAPI_LSAPI_MAX_HEADER_LENGTH - 1, + "Content-type: %s", hd ); + efree(hd); + + LSAPI_AppendRespHeader( s_headerBuf, len ); + } + } + LSAPI_FinalizeRespHeaders(); + return SAPI_HEADER_SENT_SUCCESSFULLY; + + +} +/* }}} */ + + +/* {{{ sapi_lsapi_send_headers + */ +static void sapi_lsapi_log_message(char *message) +{ + int len = strlen( message ); + LSAPI_Write_Stderr( message, len); +} +/* }}} */ + + +/* {{{ sapi_module_struct cgi_sapi_module + */ +static sapi_module_struct lsapi_sapi_module = +{ + "litespeed", + "LiteSpeed", + + 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 = LSAPI_GetScriptFileName(); + SG(sapi_headers).http_response_code = 0; //It is not reset by zend engine, set it to 0. + + pAuth = LSAPI_GetHeader( H_AUTHORIZATION ); + php_handle_auth_data(pAuth TSRMLS_CC); +} + +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 + { + 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; + + php_execute_script(&file_handle TSRMLS_CC); + } + zend_try + { + php_request_shutdown(NULL); + } 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; + 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; + + init_request_info( TSRMLS_C ); + + override_ini(); + + if ( lsapi_module_main( 0 TSRMLS_CC ) == -1 ) + ret = -1; + + } zend_end_try(); + return ret; +} + +static void cli_usage( TSRMLS_D ) +{ + static const char * usage = + "Usage: php\n" + " php -[h|i|q|v|?] [] [args...]\n" + " Run in LSAPI mode when no parameter or only '-c' is specified\n" + " Run in Command Line Interpreter mode when parameters are specified" + "\n" + " -c | 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" + " -v Version number\n" + " -? This help\n" + "\n" + " args... Arguments passed to script.\n"; + php_output_startup(); + php_output_activate(TSRMLS_C); +// SG(headers_sent) = 1; + php_printf( usage ); + php_end_ob_buffers(1 TSRMLS_CC); +} + +static int parse_opt( int argc, char * argv[], int *climode, + char **php_ini_path ) +{ + char ** p = &argv[1]; + char ** argend= &argv[argc]; + int c; + while (( p < argend )&&(**p == '-' )) + { + c = *((*p)+1); + ++p; + switch( c ) + { + case 'c': + if ( p >= argend ) + { + fprintf( stderr, " or must be specified following '-c' option.\n"); + + return -1; + } + *php_ini_path = *p++; + 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", + 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': +// SG(headers_sent) = 1; +// SG(request_info).no_headers = 1; + break; + case 'i': + if (php_request_startup(TSRMLS_C) != FAILURE) + { +// SG(headers_sent) = 1; +// SG(request_info).no_headers = 1; + php_print_info(0xFFFFFFFF TSRMLS_CC); + php_end_ob_buffers(1 TSRMLS_CC); + php_request_shutdown( NULL ); + } + ret = 1; + break; + case 'v': + if (php_request_startup(TSRMLS_C) != FAILURE) + { +// SG(headers_sent) = 1; +// SG(request_info).no_headers = 1; +#if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 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-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); +#endif + php_end_ob_buffers(1 TSRMLS_CC); + php_request_shutdown( NULL ); + } + ret = 1; + break; + case 'c': + ++p; + 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 = *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 + { + + 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(), s_stop ); + exit( 0 ); +} + + + +#include +int main( int argc, char * argv[] ) +{ + int ret; + int max_requests = 500; + int requests = 0; + + char * php_ini_path = NULL; + int climode = 0; + +#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 ) == -1 ) + return 1; + } + if ( climode ) + lsapi_sapi_module.phpinfo_as_text = 1; + 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; + + if (php_module_startup(&lsapi_sapi_module, NULL, 0) == FAILURE) { +#ifdef ZTS + tsrm_shutdown(); +#endif + return FAILURE; + } + + if ( climode ) + { + return cli_main(argc, argv); + } + + if( getenv( "PHP_LSAPI_MAX_REQUESTS" )) + { + max_requests = atoi( getenv( "PHP_LSAPI_MAX_REQUESTS" )); + if( !max_requests ) + { + fprintf( stderr, + "PHP_LSAPI_MAX_REQUESTS is not valid\n" ); + exit( 1 ); + } + } + + LSAPI_Init(); + + if (( getenv( "PHP_LSAPI_CHILDREN" ) )&& LSAPI_Is_Listen() ) + { + int children = atoi( getenv( "PHP_LSAPI_CHILDREN" )); + if ( children > 0 ) + start_children( children ); + } + + while( LSAPI_Accept() >= 0 ) + { + ret = processReq(TSRMLS_C); + LSAPI_Finish(); + if ( ret ) + break; + requests++; + if( max_requests && ( requests == max_requests )) + { + break; + } + } + php_module_shutdown(TSRMLS_C); + +#ifdef ZTS + tsrm_shutdown(); +#endif + return ret; +} + +/* + * 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 0000000000..420f3ed3b4 --- /dev/null +++ b/sapi/litespeed/lsapidef.h @@ -0,0 +1,181 @@ +/* +Copyright (c) 2005, 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. +*/ + +/*************************************************************************** + $Id$ + ------------------- + begin : Thu Feb 10 2005 + author : George Wang + email : gwang@litespeedtech.com + ***************************************************************************/ + +#ifndef _LSAPIDEF_H_ +#define _LSAPIDEF_H_ + +#include + +#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 0000000000..53232694e7 --- /dev/null +++ b/sapi/litespeed/lsapilib.c @@ -0,0 +1,1127 @@ +/* +Copyright (c) 2005, 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. +*/ + +/*************************************************************************** + lsapilib.c - description + ------------------- + begin : Mon Feb 21 2005 + copyright : (C) 2005 by George Wang + email : gwang@litespeedtech.com + ***************************************************************************/ + + +#include + +#include +#include +#include + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +LSAPI_Request g_req; + +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_LANG", "HTTP_AUTHORIZATION", + "HTTP_CONNECTION", "CONTENT_TYPE", + "CONTENT_LENGTH", "HTTP_COOKIE", "HTTP_COOKIE2", + "HTTP_HOST", "HTTP_PRAGMA", + "HTTP_REFERER", "HTTP_USER_AGENT", + "HTTP_CACHE_CTRL", + "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_MATCH", + "HTTP_IF_NONE_MATCH", + "HTTP_IF_RANGE", + "HTTP_IF_UNMODIFIED_SINCE", + "HTTP_KEEPALIVE", + "HTTP_RANGE", + "HTTP_X_FORWARDED_FOR", + "HTTP_VIA", + "HTTP_TRANSFER_ENCODING" +}; + +static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] = +{ 11, 19, 20, 16, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 15, + 22, 13, 18, 13, 24, 14, 10, 20, 8, 22 }; + +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_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_write( int fd, const void * pBuf, int len ) +//{ +// int ret; +// const char * pCur; +// const char * pEnd; +// if ( len == 0 ) +// return 0; +// pCur = (const char *)pBuf; +// pEnd = pCur + len; +// while( g_running && (pCur < pEnd) ) +// { +// ret = write( fd, pCur, pEnd - pCur ); +// if ( ret >= 0) +// pCur += ret; +// else if (( ret == -1 )&&( errno != EINTR )) +// return ret; +// } +// return pCur - (const char *)pBuf; +//} + +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 )&&( errno != EINTR )) + return ret; + } + return totalLen - left; +} + +//static int getTotalLen( struct iovec * pVec, int count ) +//{ +// struct iovec * pEnd = pVec + count; +// int total = 0; +// while( pVec < pEnd ) +// { +// total += pVec->iov_len; +// ++pVec; +// } +// return total; +//} + + +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]; + int 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 struct lsapi_packet_header ack = {'L', 'S', + LSAPI_REQ_RECEIVED, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} }; +static inline int notify_req_received( LSAPI_Request * pReq ) +{ + if ( write( pReq->m_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 > pReq->m_reqBufSize ) + { + if ( allocateBuf( pReq, packetLen ) == -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; + + return notify_req_received( pReq ); +} + + + +int LSAPI_Init(void) +{ + if ( !g_inited ) + { + lsapi_signal(SIGPIPE, lsapi_sigpipe); + lsapi_signal(SIGUSR1, lsapi_siguser1); + + if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 ) + return -1; + g_inited = 1; + } + return 0; +} + +void LSAPI_stop(void) +{ + g_running = 0; +} + +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; + } + 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]; + int 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 )&&( errno == EINTR )) + continue; + if (( pReq->m_fd != -1 )&& + (((struct sockaddr *)&achPeer)->sa_family == AF_INET )) + { + setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY, + (char *)&nodelay, sizeof(nodelay)); + } + } + 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; +} + + + +int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int bufLen ) +{ + int len; + int total; + //char *pOldBuf = pBuf; + if (!pReq || ( !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 ) + return -1; + } + pReq->m_reqBodyRead += total; + return total; + +} + + +//int LSAPI_Write( const char * pBuf, int len ) +//{ +// return LSAPI_Write_r( &g_req, pBuf, len ); +//} + +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 ) + 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; + 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->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; +} + + +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; + while( pBegin < pEnd ) + { + if ( strcmp( name, pBegin->pKey ) == 0 ) + return pBegin->pValue; + ++pBegin; + } + return NULL; +} + + +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; + pKeyEnd = pKey + keyLen; + memcpy( achHeaderName, "HTTP_", 5 ); + p = &achHeaderName[5]; + if ( keyLen > 250 ) + keyLen = 250; + + 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, pCur->valueLen, + pValue, len, 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; +} + + + + + + diff --git a/sapi/litespeed/lsapilib.h b/sapi/litespeed/lsapilib.h new file mode 100644 index 0000000000..e1c156fa51 --- /dev/null +++ b/sapi/litespeed/lsapilib.h @@ -0,0 +1,287 @@ +/* +Copyright (c) 2005, 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. +*/ + +/*************************************************************************** + lsapilib.h - description + ------------------- + begin : Mon Feb 21 2005 + copyright : (C) 2005 by George Wang + email : gwang@litespeedtech.com + ***************************************************************************/ + + +#ifndef _LSAPILIB_H_ +#define _LSAPILIB_H_ + +#if defined (c_plusplus) || defined (__cplusplus) +extern "C" { +#endif + +#include +#include + +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; + + 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_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_GetContentLen_r( LSAPI_Request * pReq ); + +int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int len ); + +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; +} + + +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_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_ReadReqBody( char * pBuf, int len ) +{ return LSAPI_ReadReqBody_r( &g_req, pBuf, len ); } + +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 ); } + + +#if defined (c_plusplus) || defined (__cplusplus) +} +#endif + + +#endif + + + + + + +