Updated to LiteSpeed SAPI V7.4.3

Increased response header count limit from 100 to 1000.
Added crash handler to cleanly shutdown PHP request.
Added CloudLinux mod_lsapi mode
Fixed bug #76058
This commit is contained in:
George Wang 2019-07-04 12:03:21 -04:00
parent 0e48e35e04
commit 32af676bd9
2 changed files with 268 additions and 4 deletions

View File

@ -311,7 +311,8 @@ static void sapi_lsapi_register_variables(zval *track_vars_array)
static size_t sapi_lsapi_read_post(char *buffer, size_t count_bytes) static size_t sapi_lsapi_read_post(char *buffer, size_t count_bytes)
{ {
if ( lsapi_mode ) { if ( lsapi_mode ) {
return LSAPI_ReadReqBody( buffer, (unsigned long long)count_bytes ); ssize_t rv = LSAPI_ReadReqBody(buffer, (unsigned long long)count_bytes);
return (rv >= 0) ? (size_t)rv : 0;
} else { } else {
return 0; return 0;
} }
@ -334,12 +335,165 @@ static char *sapi_lsapi_read_cookies(void)
/* }}} */ /* }}} */
typedef struct _http_error {
int code;
const char* msg;
} http_error;
static const http_error http_error_codes[] = {
{100, "Continue"},
{101, "Switching Protocols"},
{200, "OK"},
{201, "Created"},
{202, "Accepted"},
{203, "Non-Authoritative Information"},
{204, "No Content"},
{205, "Reset Content"},
{206, "Partial Content"},
{300, "Multiple Choices"},
{301, "Moved Permanently"},
{302, "Moved Temporarily"},
{303, "See Other"},
{304, "Not Modified"},
{305, "Use Proxy"},
{400, "Bad Request"},
{401, "Unauthorized"},
{402, "Payment Required"},
{403, "Forbidden"},
{404, "Not Found"},
{405, "Method Not Allowed"},
{406, "Not Acceptable"},
{407, "Proxy Authentication Required"},
{408, "Request Time-out"},
{409, "Conflict"},
{410, "Gone"},
{411, "Length Required"},
{412, "Precondition Failed"},
{413, "Request Entity Too Large"},
{414, "Request-URI Too Large"},
{415, "Unsupported Media Type"},
{428, "Precondition Required"},
{429, "Too Many Requests"},
{431, "Request Header Fields Too Large"},
{451, "Unavailable For Legal Reasons"},
{500, "Internal Server Error"},
{501, "Not Implemented"},
{502, "Bad Gateway"},
{503, "Service Unavailable"},
{504, "Gateway Time-out"},
{505, "HTTP Version not supported"},
{511, "Network Authentication Required"},
{0, NULL}
};
static int sapi_lsapi_send_headers_like_cgi(sapi_headers_struct *sapi_headers)
{
char buf[SAPI_LSAPI_MAX_HEADER_LENGTH];
sapi_header_struct *h;
zend_llist_position pos;
zend_bool ignore_status = 0;
int response_status = SG(sapi_headers).http_response_code;
if (SG(request_info).no_headers == 1) {
LSAPI_FinalizeRespHeaders();
return SAPI_HEADER_SENT_SUCCESSFULLY;
}
if (SG(sapi_headers).http_response_code != 200)
{
int len;
zend_bool has_status = 0;
char *s;
if (SG(sapi_headers).http_status_line &&
(s = strchr(SG(sapi_headers).http_status_line, ' ')) != 0 &&
(s - SG(sapi_headers).http_status_line) >= 5 &&
strncasecmp(SG(sapi_headers).http_status_line, "HTTP/", 5) == 0
) {
len = slprintf(buf, sizeof(buf), "Status:%s", s);
response_status = atoi((s + 1));
} else {
h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
while (h) {
if (h->header_len > sizeof("Status:")-1 &&
strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0
) {
has_status = 1;
break;
}
h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
}
if (!has_status) {
http_error *err = (http_error*)http_error_codes;
while (err->code != 0) {
if (err->code == SG(sapi_headers).http_response_code) {
break;
}
err++;
}
if (err->msg) {
len = slprintf(buf, sizeof(buf), "Status: %d %s", SG(sapi_headers).http_response_code, err->msg);
} else {
len = slprintf(buf, sizeof(buf), "Status: %d", SG(sapi_headers).http_response_code);
}
}
}
if (!has_status) {
LSAPI_AppendRespHeader( buf, len );
ignore_status = 1;
}
}
h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
while (h) {
/* prevent CRLFCRLF */
if (h->header_len) {
if (h->header_len > sizeof("Status:")-1 &&
strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0
) {
if (!ignore_status) {
ignore_status = 1;
LSAPI_AppendRespHeader(h->header, h->header_len);
}
} else if (response_status == 304 && h->header_len > sizeof("Content-Type:")-1 &&
strncasecmp(h->header, "Content-Type:", sizeof("Content-Type:")-1) == 0
) {
h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
continue;
} else {
LSAPI_AppendRespHeader(h->header, h->header_len);
}
}
h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
}
LSAPI_FinalizeRespHeaders();
return SAPI_HEADER_SENT_SUCCESSFULLY;
}
/*
mod_lsapi mode or legacy LS mode
*/
static int mod_lsapi_mode = 0;
/* {{{ sapi_lsapi_send_headers /* {{{ sapi_lsapi_send_headers
*/ */
static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers) static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers)
{ {
sapi_header_struct *h; sapi_header_struct *h;
zend_llist_position pos; zend_llist_position pos;
if ( mod_lsapi_mode ) {
/* mod_lsapi mode */
return sapi_lsapi_send_headers_like_cgi(sapi_headers);
}
/* Legacy mode */
if ( lsapi_mode ) { if ( lsapi_mode ) {
LSAPI_SetRespStatus( SG(sapi_headers).http_response_code ); LSAPI_SetRespStatus( SG(sapi_headers).http_response_code );
@ -466,7 +620,7 @@ static int sapi_lsapi_activate()
static sapi_module_struct lsapi_sapi_module = static sapi_module_struct lsapi_sapi_module =
{ {
"litespeed", "litespeed",
"LiteSpeed V7.3.2", "LiteSpeed V7.4.3",
php_lsapi_startup, /* startup */ php_lsapi_startup, /* startup */
php_module_shutdown_wrapper, /* shutdown */ php_module_shutdown_wrapper, /* shutdown */
@ -541,6 +695,66 @@ static int lsapi_execute_script( zend_file_handle * file_handle)
} }
static void lsapi_sigsegv( int signal )
{
//fprintf(stderr, "lsapi_sigsegv: %d: Segmentation violation signal is caught during request shutdown\n", getpid());
_exit(1);
}
static int clean_onexit = 1;
static void lsapi_sigterm( int signal )
{
struct sigaction act, old_act;
int sa_rc;
// fprintf(stderr, "lsapi_sigterm: %d: clean_onexit %d\n", getpid(), clean_onexit );
if(!clean_onexit)
{
clean_onexit = 1;
act.sa_flags = 0;
act.sa_handler = lsapi_sigsegv;
sa_rc = sigaction( SIGINT, &act, &old_act );
sa_rc = sigaction( SIGQUIT, &act, &old_act );
sa_rc = sigaction( SIGILL, &act, &old_act );
sa_rc = sigaction( SIGABRT, &act, &old_act );
sa_rc = sigaction( SIGBUS, &act, &old_act );
sa_rc = sigaction( SIGSEGV, &act, &old_act );
sa_rc = sigaction( SIGTERM, &act, &old_act );
zend_try {
php_request_shutdown(NULL);
} zend_end_try();
}
exit(1);
}
static void lsapi_atexit( void )
{
struct sigaction act, old_act;
int sa_rc;
//fprintf(stderr, "lsapi_atexit: %d: clean_onexit %d\n", getpid(), clean_onexit );
if(!clean_onexit)
{
clean_onexit = 1;
act.sa_flags = 0;
act.sa_handler = lsapi_sigsegv;
sa_rc = sigaction( SIGINT, &act, &old_act );
sa_rc = sigaction( SIGQUIT, &act, &old_act );
sa_rc = sigaction( SIGILL, &act, &old_act );
sa_rc = sigaction( SIGABRT, &act, &old_act );
sa_rc = sigaction( SIGBUS, &act, &old_act );
sa_rc = sigaction( SIGSEGV, &act, &old_act );
sa_rc = sigaction( SIGTERM, &act, &old_act );
//fprintf(stderr, "lsapi_atexit: %d: before php_request_shutdown\n", getpid(), clean_onexit );
zend_try {
php_request_shutdown(NULL);
} zend_end_try();
}
}
static int lsapi_module_main(int show_source) static int lsapi_module_main(int show_source)
{ {
zend_file_handle file_handle; zend_file_handle file_handle;
@ -549,6 +763,8 @@ static int lsapi_module_main(int show_source)
return -1; return -1;
} }
clean_onexit = 0;
if (show_source) { if (show_source) {
zend_syntax_highlighter_ini syntax_highlighter_ini; zend_syntax_highlighter_ini syntax_highlighter_ini;
@ -559,6 +775,9 @@ static int lsapi_module_main(int show_source)
} }
zend_try { zend_try {
php_request_shutdown(NULL); php_request_shutdown(NULL);
clean_onexit = 1;
memset( argv0, 0, 46 ); memset( argv0, 0, 46 );
} zend_end_try(); } zend_end_try();
return 0; return 0;
@ -576,7 +795,16 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va
++pKey; ++pKey;
if ( *pKey == 4 ) { if ( *pKey == 4 ) {
type = ZEND_INI_SYSTEM; type = ZEND_INI_SYSTEM;
stage = PHP_INI_STAGE_ACTIVATE; /*
Use ACTIVATE stage in legacy mode only.
RUNTIME stage should be used here,
as with ACTIVATE it's impossible to change the option from script with ini_set
*/
if(!mod_lsapi_mode)
{
stage = PHP_INI_STAGE_ACTIVATE;
}
} }
else else
{ {
@ -1245,6 +1473,16 @@ int main( int argc, char * argv[] )
int slow_script_msec = 0; int slow_script_msec = 0;
char time_buf[40]; char time_buf[40];
struct sigaction act, old_act;
struct sigaction INT_act;
struct sigaction QUIT_act;
struct sigaction ILL_act;
struct sigaction ABRT_act;
struct sigaction BUS_act;
struct sigaction SEGV_act;
struct sigaction TERM_act;
int sa_rc;
#ifdef HAVE_SIGNAL_H #ifdef HAVE_SIGNAL_H
#if defined(SIGPIPE) && defined(SIG_IGN) #if defined(SIGPIPE) && defined(SIG_IGN)
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
@ -1346,6 +1584,17 @@ int main( int argc, char * argv[] )
int iRequestsProcessed = 0; int iRequestsProcessed = 0;
int result; int result;
act.sa_flags = SA_NODEFER;
act.sa_handler = lsapi_sigterm;
sa_rc = sigaction( SIGINT, &act, &INT_act );
sa_rc = sigaction( SIGQUIT, &act, &QUIT_act );
sa_rc = sigaction( SIGILL, &act, &ILL_act );
sa_rc = sigaction( SIGABRT, &act, &ABRT_act );
sa_rc = sigaction( SIGBUS, &act, &BUS_act );
sa_rc = sigaction( SIGSEGV, &act, &SEGV_act );
sa_rc = sigaction( SIGTERM, &act, &TERM_act );
atexit(lsapi_atexit);
while( ( result = LSAPI_Prefork_Accept_r( &g_req )) >= 0 ) { while( ( result = LSAPI_Prefork_Accept_r( &g_req )) >= 0 ) {
#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__) #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
if (is_criu && !result) { if (is_criu && !result) {
@ -1375,6 +1624,15 @@ int main( int argc, char * argv[] )
break; break;
} }
} }
sa_rc = sigaction( SIGINT, &INT_act, &old_act );
sa_rc = sigaction( SIGQUIT, &QUIT_act, &old_act );
sa_rc = sigaction( SIGILL, &ILL_act, &old_act );
sa_rc = sigaction( SIGABRT, &ABRT_act, &old_act );
sa_rc = sigaction( SIGBUS, &BUS_act, &old_act );
sa_rc = sigaction( SIGSEGV, &SEGV_act, &old_act );
sa_rc = sigaction( SIGTERM, &TERM_act, &old_act );
php_module_shutdown(); php_module_shutdown();
#ifdef ZTS #ifdef ZTS
@ -1417,6 +1675,12 @@ static PHP_MINIT_FUNCTION(litespeed)
if (p && 0 == strcasecmp(p, "on")) if (p && 0 == strcasecmp(p, "on"))
parse_user_ini = 1; parse_user_ini = 1;
/*
* mod_lsapi always sets this env var,
* so we can detect mod_lsapi mode with its presense.
*/
mod_lsapi_mode = ( getenv("LSAPI_DISABLE_CPAN_BEHAV") != NULL );
/* REGISTER_INI_ENTRIES(); */ /* REGISTER_INI_ENTRIES(); */
return SUCCESS; return SUCCESS;
} }

View File

@ -71,7 +71,7 @@ struct LSAPI_key_value_pair
}; };
#define LSAPI_MAX_RESP_HEADERS 100 #define LSAPI_MAX_RESP_HEADERS 1000
typedef struct lsapi_request typedef struct lsapi_request
{ {