Skip to content

Commit 32af676

Browse files
author
George Wang
committed
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
1 parent 0e48e35 commit 32af676

File tree

2 files changed

+268
-4
lines changed

2 files changed

+268
-4
lines changed

sapi/litespeed/lsapi_main.c

Lines changed: 267 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,8 @@ static void sapi_lsapi_register_variables(zval *track_vars_array)
311311
static size_t sapi_lsapi_read_post(char *buffer, size_t count_bytes)
312312
{
313313
if ( lsapi_mode ) {
314-
return LSAPI_ReadReqBody( buffer, (unsigned long long)count_bytes );
314+
ssize_t rv = LSAPI_ReadReqBody(buffer, (unsigned long long)count_bytes);
315+
return (rv >= 0) ? (size_t)rv : 0;
315316
} else {
316317
return 0;
317318
}
@@ -334,12 +335,165 @@ static char *sapi_lsapi_read_cookies(void)
334335
/* }}} */
335336

336337

338+
typedef struct _http_error {
339+
int code;
340+
const char* msg;
341+
} http_error;
342+
343+
static const http_error http_error_codes[] = {
344+
{100, "Continue"},
345+
{101, "Switching Protocols"},
346+
{200, "OK"},
347+
{201, "Created"},
348+
{202, "Accepted"},
349+
{203, "Non-Authoritative Information"},
350+
{204, "No Content"},
351+
{205, "Reset Content"},
352+
{206, "Partial Content"},
353+
{300, "Multiple Choices"},
354+
{301, "Moved Permanently"},
355+
{302, "Moved Temporarily"},
356+
{303, "See Other"},
357+
{304, "Not Modified"},
358+
{305, "Use Proxy"},
359+
{400, "Bad Request"},
360+
{401, "Unauthorized"},
361+
{402, "Payment Required"},
362+
{403, "Forbidden"},
363+
{404, "Not Found"},
364+
{405, "Method Not Allowed"},
365+
{406, "Not Acceptable"},
366+
{407, "Proxy Authentication Required"},
367+
{408, "Request Time-out"},
368+
{409, "Conflict"},
369+
{410, "Gone"},
370+
{411, "Length Required"},
371+
{412, "Precondition Failed"},
372+
{413, "Request Entity Too Large"},
373+
{414, "Request-URI Too Large"},
374+
{415, "Unsupported Media Type"},
375+
{428, "Precondition Required"},
376+
{429, "Too Many Requests"},
377+
{431, "Request Header Fields Too Large"},
378+
{451, "Unavailable For Legal Reasons"},
379+
{500, "Internal Server Error"},
380+
{501, "Not Implemented"},
381+
{502, "Bad Gateway"},
382+
{503, "Service Unavailable"},
383+
{504, "Gateway Time-out"},
384+
{505, "HTTP Version not supported"},
385+
{511, "Network Authentication Required"},
386+
{0, NULL}
387+
};
388+
389+
390+
static int sapi_lsapi_send_headers_like_cgi(sapi_headers_struct *sapi_headers)
391+
{
392+
char buf[SAPI_LSAPI_MAX_HEADER_LENGTH];
393+
sapi_header_struct *h;
394+
zend_llist_position pos;
395+
zend_bool ignore_status = 0;
396+
int response_status = SG(sapi_headers).http_response_code;
397+
398+
if (SG(request_info).no_headers == 1) {
399+
LSAPI_FinalizeRespHeaders();
400+
return SAPI_HEADER_SENT_SUCCESSFULLY;
401+
}
402+
403+
if (SG(sapi_headers).http_response_code != 200)
404+
{
405+
int len;
406+
zend_bool has_status = 0;
407+
408+
char *s;
409+
410+
if (SG(sapi_headers).http_status_line &&
411+
(s = strchr(SG(sapi_headers).http_status_line, ' ')) != 0 &&
412+
(s - SG(sapi_headers).http_status_line) >= 5 &&
413+
strncasecmp(SG(sapi_headers).http_status_line, "HTTP/", 5) == 0
414+
) {
415+
len = slprintf(buf, sizeof(buf), "Status:%s", s);
416+
response_status = atoi((s + 1));
417+
} else {
418+
h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
419+
while (h) {
420+
if (h->header_len > sizeof("Status:")-1 &&
421+
strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0
422+
) {
423+
has_status = 1;
424+
break;
425+
}
426+
h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
427+
}
428+
if (!has_status) {
429+
http_error *err = (http_error*)http_error_codes;
430+
431+
while (err->code != 0) {
432+
if (err->code == SG(sapi_headers).http_response_code) {
433+
break;
434+
}
435+
err++;
436+
}
437+
if (err->msg) {
438+
len = slprintf(buf, sizeof(buf), "Status: %d %s", SG(sapi_headers).http_response_code, err->msg);
439+
} else {
440+
len = slprintf(buf, sizeof(buf), "Status: %d", SG(sapi_headers).http_response_code);
441+
}
442+
}
443+
}
444+
445+
if (!has_status) {
446+
LSAPI_AppendRespHeader( buf, len );
447+
ignore_status = 1;
448+
}
449+
}
450+
451+
h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
452+
while (h) {
453+
/* prevent CRLFCRLF */
454+
if (h->header_len) {
455+
if (h->header_len > sizeof("Status:")-1 &&
456+
strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0
457+
) {
458+
if (!ignore_status) {
459+
ignore_status = 1;
460+
LSAPI_AppendRespHeader(h->header, h->header_len);
461+
}
462+
} else if (response_status == 304 && h->header_len > sizeof("Content-Type:")-1 &&
463+
strncasecmp(h->header, "Content-Type:", sizeof("Content-Type:")-1) == 0
464+
) {
465+
h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
466+
continue;
467+
} else {
468+
LSAPI_AppendRespHeader(h->header, h->header_len);
469+
}
470+
}
471+
h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
472+
}
473+
474+
LSAPI_FinalizeRespHeaders();
475+
return SAPI_HEADER_SENT_SUCCESSFULLY;
476+
}
477+
478+
/*
479+
mod_lsapi mode or legacy LS mode
480+
*/
481+
static int mod_lsapi_mode = 0;
482+
483+
337484
/* {{{ sapi_lsapi_send_headers
338485
*/
339486
static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers)
340487
{
341488
sapi_header_struct *h;
342489
zend_llist_position pos;
490+
491+
if ( mod_lsapi_mode ) {
492+
/* mod_lsapi mode */
493+
return sapi_lsapi_send_headers_like_cgi(sapi_headers);
494+
}
495+
496+
/* Legacy mode */
343497
if ( lsapi_mode ) {
344498
LSAPI_SetRespStatus( SG(sapi_headers).http_response_code );
345499

@@ -466,7 +620,7 @@ static int sapi_lsapi_activate()
466620
static sapi_module_struct lsapi_sapi_module =
467621
{
468622
"litespeed",
469-
"LiteSpeed V7.3.2",
623+
"LiteSpeed V7.4.3",
470624

471625
php_lsapi_startup, /* startup */
472626
php_module_shutdown_wrapper, /* shutdown */
@@ -541,6 +695,66 @@ static int lsapi_execute_script( zend_file_handle * file_handle)
541695

542696
}
543697

698+
static void lsapi_sigsegv( int signal )
699+
{
700+
//fprintf(stderr, "lsapi_sigsegv: %d: Segmentation violation signal is caught during request shutdown\n", getpid());
701+
_exit(1);
702+
}
703+
704+
static int clean_onexit = 1;
705+
706+
static void lsapi_sigterm( int signal )
707+
{
708+
struct sigaction act, old_act;
709+
int sa_rc;
710+
711+
// fprintf(stderr, "lsapi_sigterm: %d: clean_onexit %d\n", getpid(), clean_onexit );
712+
if(!clean_onexit)
713+
{
714+
clean_onexit = 1;
715+
act.sa_flags = 0;
716+
act.sa_handler = lsapi_sigsegv;
717+
sa_rc = sigaction( SIGINT, &act, &old_act );
718+
sa_rc = sigaction( SIGQUIT, &act, &old_act );
719+
sa_rc = sigaction( SIGILL, &act, &old_act );
720+
sa_rc = sigaction( SIGABRT, &act, &old_act );
721+
sa_rc = sigaction( SIGBUS, &act, &old_act );
722+
sa_rc = sigaction( SIGSEGV, &act, &old_act );
723+
sa_rc = sigaction( SIGTERM, &act, &old_act );
724+
725+
zend_try {
726+
php_request_shutdown(NULL);
727+
} zend_end_try();
728+
}
729+
exit(1);
730+
}
731+
732+
static void lsapi_atexit( void )
733+
{
734+
struct sigaction act, old_act;
735+
int sa_rc;
736+
737+
//fprintf(stderr, "lsapi_atexit: %d: clean_onexit %d\n", getpid(), clean_onexit );
738+
if(!clean_onexit)
739+
{
740+
clean_onexit = 1;
741+
act.sa_flags = 0;
742+
act.sa_handler = lsapi_sigsegv;
743+
sa_rc = sigaction( SIGINT, &act, &old_act );
744+
sa_rc = sigaction( SIGQUIT, &act, &old_act );
745+
sa_rc = sigaction( SIGILL, &act, &old_act );
746+
sa_rc = sigaction( SIGABRT, &act, &old_act );
747+
sa_rc = sigaction( SIGBUS, &act, &old_act );
748+
sa_rc = sigaction( SIGSEGV, &act, &old_act );
749+
sa_rc = sigaction( SIGTERM, &act, &old_act );
750+
751+
//fprintf(stderr, "lsapi_atexit: %d: before php_request_shutdown\n", getpid(), clean_onexit );
752+
zend_try {
753+
php_request_shutdown(NULL);
754+
} zend_end_try();
755+
}
756+
}
757+
544758
static int lsapi_module_main(int show_source)
545759
{
546760
zend_file_handle file_handle;
@@ -549,6 +763,8 @@ static int lsapi_module_main(int show_source)
549763
return -1;
550764
}
551765

766+
clean_onexit = 0;
767+
552768
if (show_source) {
553769
zend_syntax_highlighter_ini syntax_highlighter_ini;
554770

@@ -559,6 +775,9 @@ static int lsapi_module_main(int show_source)
559775
}
560776
zend_try {
561777
php_request_shutdown(NULL);
778+
779+
clean_onexit = 1;
780+
562781
memset( argv0, 0, 46 );
563782
} zend_end_try();
564783
return 0;
@@ -576,7 +795,16 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va
576795
++pKey;
577796
if ( *pKey == 4 ) {
578797
type = ZEND_INI_SYSTEM;
579-
stage = PHP_INI_STAGE_ACTIVATE;
798+
/*
799+
Use ACTIVATE stage in legacy mode only.
800+
801+
RUNTIME stage should be used here,
802+
as with ACTIVATE it's impossible to change the option from script with ini_set
803+
*/
804+
if(!mod_lsapi_mode)
805+
{
806+
stage = PHP_INI_STAGE_ACTIVATE;
807+
}
580808
}
581809
else
582810
{
@@ -1245,6 +1473,16 @@ int main( int argc, char * argv[] )
12451473
int slow_script_msec = 0;
12461474
char time_buf[40];
12471475

1476+
struct sigaction act, old_act;
1477+
struct sigaction INT_act;
1478+
struct sigaction QUIT_act;
1479+
struct sigaction ILL_act;
1480+
struct sigaction ABRT_act;
1481+
struct sigaction BUS_act;
1482+
struct sigaction SEGV_act;
1483+
struct sigaction TERM_act;
1484+
int sa_rc;
1485+
12481486
#ifdef HAVE_SIGNAL_H
12491487
#if defined(SIGPIPE) && defined(SIG_IGN)
12501488
signal(SIGPIPE, SIG_IGN);
@@ -1346,6 +1584,17 @@ int main( int argc, char * argv[] )
13461584
int iRequestsProcessed = 0;
13471585
int result;
13481586

1587+
act.sa_flags = SA_NODEFER;
1588+
act.sa_handler = lsapi_sigterm;
1589+
sa_rc = sigaction( SIGINT, &act, &INT_act );
1590+
sa_rc = sigaction( SIGQUIT, &act, &QUIT_act );
1591+
sa_rc = sigaction( SIGILL, &act, &ILL_act );
1592+
sa_rc = sigaction( SIGABRT, &act, &ABRT_act );
1593+
sa_rc = sigaction( SIGBUS, &act, &BUS_act );
1594+
sa_rc = sigaction( SIGSEGV, &act, &SEGV_act );
1595+
sa_rc = sigaction( SIGTERM, &act, &TERM_act );
1596+
atexit(lsapi_atexit);
1597+
13491598
while( ( result = LSAPI_Prefork_Accept_r( &g_req )) >= 0 ) {
13501599
#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
13511600
if (is_criu && !result) {
@@ -1375,6 +1624,15 @@ int main( int argc, char * argv[] )
13751624
break;
13761625
}
13771626
}
1627+
1628+
sa_rc = sigaction( SIGINT, &INT_act, &old_act );
1629+
sa_rc = sigaction( SIGQUIT, &QUIT_act, &old_act );
1630+
sa_rc = sigaction( SIGILL, &ILL_act, &old_act );
1631+
sa_rc = sigaction( SIGABRT, &ABRT_act, &old_act );
1632+
sa_rc = sigaction( SIGBUS, &BUS_act, &old_act );
1633+
sa_rc = sigaction( SIGSEGV, &SEGV_act, &old_act );
1634+
sa_rc = sigaction( SIGTERM, &TERM_act, &old_act );
1635+
13781636
php_module_shutdown();
13791637

13801638
#ifdef ZTS
@@ -1417,6 +1675,12 @@ static PHP_MINIT_FUNCTION(litespeed)
14171675
if (p && 0 == strcasecmp(p, "on"))
14181676
parse_user_ini = 1;
14191677

1678+
/*
1679+
* mod_lsapi always sets this env var,
1680+
* so we can detect mod_lsapi mode with its presense.
1681+
*/
1682+
mod_lsapi_mode = ( getenv("LSAPI_DISABLE_CPAN_BEHAV") != NULL );
1683+
14201684
/* REGISTER_INI_ENTRIES(); */
14211685
return SUCCESS;
14221686
}

sapi/litespeed/lsapilib.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ struct LSAPI_key_value_pair
7171
};
7272

7373

74-
#define LSAPI_MAX_RESP_HEADERS 100
74+
#define LSAPI_MAX_RESP_HEADERS 1000
7575

7676
typedef struct lsapi_request
7777
{

0 commit comments

Comments
 (0)