]> granicus.if.org Git - php/commitdiff
Initial checkin of LiteSpeed SAPI module
authorGeorge Wang <gwang@php.net>
Fri, 13 Jan 2006 03:21:51 +0000 (03:21 +0000)
committerGeorge Wang <gwang@php.net>
Fri, 13 Jan 2006 03:21:51 +0000 (03:21 +0000)
sapi/litespeed/Makefile.frag [new file with mode: 0644]
sapi/litespeed/README [new file with mode: 0644]
sapi/litespeed/config.m4 [new file with mode: 0644]
sapi/litespeed/lsapi_main.c [new file with mode: 0644]
sapi/litespeed/lsapidef.h [new file with mode: 0644]
sapi/litespeed/lsapilib.c [new file with mode: 0644]
sapi/litespeed/lsapilib.h [new file with mode: 0644]

diff --git a/sapi/litespeed/Makefile.frag b/sapi/litespeed/Makefile.frag
new file mode 100644 (file)
index 0000000..e1af2b9
--- /dev/null
@@ -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 (file)
index 0000000..bd57f1f
--- /dev/null
@@ -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 (file)
index 0000000..e34d4dc
--- /dev/null
@@ -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 (file)
index 0000000..c8c8420
--- /dev/null
@@ -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 <gwang@litespeedtech.com>                        |
+   +----------------------------------------------------------------------+
+*/
+
+
+#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 <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 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|?] [<file>] [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 <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"
+        "  -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, "<path> or <file> 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 <fcntl.h>
+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 (file)
index 0000000..420f3ed
--- /dev/null
@@ -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 <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 (file)
index 0000000..5323269
--- /dev/null
@@ -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 <lsapilib.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+
+//#include <arpa/inet.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/uio.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;
+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 (file)
index 0000000..e1c156f
--- /dev/null
@@ -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 <stddef.h>
+#include <lsapidef.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;
+    
+    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
+
+
+
+
+
+
+