@ -139,7 +139,7 @@ void uh_cgi_request(
struct client * cl , struct http_request * req ,
struct client * cl , struct http_request * req ,
struct path_info * pi , struct interpreter * ip
struct path_info * pi , struct interpreter * ip
) {
) {
int i , hdroff , bufoff ;
int i , hdroff , bufoff , rv ;
int hdrlen = 0 ;
int hdrlen = 0 ;
int buflen = 0 ;
int buflen = 0 ;
int fd_max = 0 ;
int fd_max = 0 ;
@ -376,12 +376,6 @@ void uh_cgi_request(
memset ( hdr , 0 , sizeof ( hdr ) ) ;
memset ( hdr , 0 , sizeof ( hdr ) ) ;
timeout . tv_sec = cl - > server - > conf - > script_timeout ;
timeout . tv_usec = 0 ;
# define ensure(x) \
do { if ( x < 0 ) goto out ; } while ( 0 )
/* I/O loop, watch our pipe ends and dispatch child reads/writes from/to socket */
/* I/O loop, watch our pipe ends and dispatch child reads/writes from/to socket */
while ( 1 )
while ( 1 )
{
{
@ -391,11 +385,21 @@ void uh_cgi_request(
FD_SET ( rfd [ 0 ] , & reader ) ;
FD_SET ( rfd [ 0 ] , & reader ) ;
FD_SET ( wfd [ 1 ] , & writer ) ;
FD_SET ( wfd [ 1 ] , & writer ) ;
timeout . tv_sec = ( header_sent < 1 ) ? cl - > server - > conf - > script_timeout : 3 ;
timeout . tv_usec = 0 ;
ensure_out ( rv = select_intr ( fd_max , & reader ,
( content_length > - 1 ) ? & writer : NULL , NULL , & timeout ) ) ;
/* timeout */
if ( rv = = 0 )
{
ensure_out ( kill ( child , 0 ) ) ;
}
/* wait until we can read or write or both */
/* wait until we can read or write or both */
if ( select_intr ( fd_max , & reader ,
else if ( rv > 0 )
( content_length > - 1 ) ? & writer : NULL , NULL ,
{
( header_sent < 1 ) ? & timeout : NULL ) > 0
) {
/* ready to write to cgi program */
/* ready to write to cgi program */
if ( FD_ISSET ( wfd [ 1 ] , & writer ) )
if ( FD_ISSET ( wfd [ 1 ] , & writer ) )
{
{
@ -403,7 +407,10 @@ void uh_cgi_request(
if ( content_length > 0 )
if ( content_length > 0 )
{
{
/* read it from socket ... */
/* read it from socket ... */
if ( ( buflen = uh_tcp_recv ( cl , buf , min ( content_length , sizeof ( buf ) ) ) ) > 0 )
ensure_out ( buflen = uh_tcp_recv ( cl , buf ,
min ( content_length , sizeof ( buf ) ) ) ) ;
if ( buflen > 0 )
{
{
/* ... and write it to child's stdin */
/* ... and write it to child's stdin */
if ( write ( wfd [ 1 ] , buf , buflen ) < 0 )
if ( write ( wfd [ 1 ] , buf , buflen ) < 0 )
@ -456,7 +463,7 @@ void uh_cgi_request(
if ( ( res = uh_cgi_header_parse ( hdr , hdrlen , & hdroff ) ) ! = NULL )
if ( ( res = uh_cgi_header_parse ( hdr , hdrlen , & hdroff ) ) ! = NULL )
{
{
/* write status */
/* write status */
ensure ( uh_http_sendf ( cl , NULL ,
ensure_out ( uh_http_sendf ( cl , NULL ,
" HTTP/%.1f %03d %s \r \n "
" HTTP/%.1f %03d %s \r \n "
" Connection: close \r \n " ,
" Connection: close \r \n " ,
req - > version , res - > statuscode ,
req - > version , res - > statuscode ,
@ -466,7 +473,7 @@ void uh_cgi_request(
if ( ! uh_cgi_header_lookup ( res , " Location " ) & &
if ( ! uh_cgi_header_lookup ( res , " Location " ) & &
! uh_cgi_header_lookup ( res , " Content-Type " )
! uh_cgi_header_lookup ( res , " Content-Type " )
) {
) {
ensure ( uh_http_send ( cl , NULL ,
ensure_out ( uh_http_send ( cl , NULL ,
" Content-Type: text/plain \r \n " , - 1 ) ) ;
" Content-Type: text/plain \r \n " , - 1 ) ) ;
}
}
@ -474,32 +481,32 @@ void uh_cgi_request(
if ( ( req - > version > 1.0 ) & &
if ( ( req - > version > 1.0 ) & &
! uh_cgi_header_lookup ( res , " Transfer-Encoding " )
! uh_cgi_header_lookup ( res , " Transfer-Encoding " )
) {
) {
ensure ( uh_http_send ( cl , NULL ,
ensure_out ( uh_http_send ( cl , NULL ,
" Transfer-Encoding: chunked \r \n " , - 1 ) ) ;
" Transfer-Encoding: chunked \r \n " , - 1 ) ) ;
}
}
/* write headers from CGI program */
/* write headers from CGI program */
foreach_header ( i , res - > headers )
foreach_header ( i , res - > headers )
{
{
ensure ( uh_http_sendf ( cl , NULL , " %s: %s \r \n " ,
ensure_out ( uh_http_sendf ( cl , NULL , " %s: %s \r \n " ,
res - > headers [ i ] , res - > headers [ i + 1 ] ) ) ;
res - > headers [ i ] , res - > headers [ i + 1 ] ) ) ;
}
}
/* terminate header */
/* terminate header */
ensure ( uh_http_send ( cl , NULL , " \r \n " , - 1 ) ) ;
ensure_out ( uh_http_send ( cl , NULL , " \r \n " , - 1 ) ) ;
/* push out remaining head buffer */
/* push out remaining head buffer */
if ( hdroff < hdrlen )
if ( hdroff < hdrlen )
ensure ( uh_http_send ( cl , req , & hdr [ hdroff ] , hdrlen - hdroff ) ) ;
ensure_out ( uh_http_send ( cl , req , & hdr [ hdroff ] , hdrlen - hdroff ) ) ;
}
}
/* ... failed and head buffer exceeded */
/* ... failed and head buffer exceeded */
else if ( hdrlen > = sizeof ( hdr ) )
else if ( hdrlen > = sizeof ( hdr ) )
{
{
ensure ( uh_cgi_error_500 ( cl , req ,
ensure_out ( uh_cgi_error_500 ( cl , req ,
" The CGI program generated an invalid response: \n \n " ) ) ;
" The CGI program generated an invalid response: \n \n " ) ) ;
ensure ( uh_http_send ( cl , req , hdr , hdrlen ) ) ;
ensure_out ( uh_http_send ( cl , req , hdr , hdrlen ) ) ;
}
}
/* ... failed but free buffer space, try again */
/* ... failed but free buffer space, try again */
@ -510,7 +517,7 @@ void uh_cgi_request(
/* push out remaining read buffer */
/* push out remaining read buffer */
if ( bufoff < buflen )
if ( bufoff < buflen )
ensure ( uh_http_send ( cl , req , & buf [ bufoff ] , buflen - bufoff ) ) ;
ensure_out ( uh_http_send ( cl , req , & buf [ bufoff ] , buflen - bufoff ) ) ;
header_sent = 1 ;
header_sent = 1 ;
continue ;
continue ;
@ -518,7 +525,7 @@ void uh_cgi_request(
/* headers complete, pass through buffer to socket */
/* headers complete, pass through buffer to socket */
ensure ( uh_http_send ( cl , req , buf , buflen ) ) ;
ensure_out ( uh_http_send ( cl , req , buf , buflen ) ) ;
}
}
/* looks like eof from child */
/* looks like eof from child */
@ -538,7 +545,7 @@ void uh_cgi_request(
* build the required headers here .
* build the required headers here .
*/
*/
ensure ( uh_http_sendf ( cl , NULL ,
ensure_out ( uh_http_sendf ( cl , NULL ,
" HTTP/%.1f 200 OK \r \n "
" HTTP/%.1f 200 OK \r \n "
" Content-Type: text/plain \r \n "
" Content-Type: text/plain \r \n "
" %s \r \n " ,
" %s \r \n " ,
@ -546,11 +553,11 @@ void uh_cgi_request(
? " Transfer-Encoding: chunked \r \n " : " "
? " Transfer-Encoding: chunked \r \n " : " "
) ) ;
) ) ;
ensure ( uh_http_send ( cl , req , hdr , hdrlen ) ) ;
ensure_out ( uh_http_send ( cl , req , hdr , hdrlen ) ) ;
}
}
/* send final chunk if we're in chunked transfer mode */
/* send final chunk if we're in chunked transfer mode */
ensure ( uh_http_send ( cl , req , " " , 0 ) ) ;
ensure_out ( uh_http_send ( cl , req , " " , 0 ) ) ;
break ;
break ;
}
}
}
}
@ -561,13 +568,13 @@ void uh_cgi_request(
{
{
if ( ( errno ! = EINTR ) & & ! header_sent )
if ( ( errno ! = EINTR ) & & ! header_sent )
{
{
ensure ( uh_http_sendhf ( cl , 504 , " Gateway Timeout " ,
ensure_out ( uh_http_sendhf ( cl , 504 , " Gateway Timeout " ,
" The CGI script took too long to produce "
" The CGI script took too long to produce "
" a response " ) ) ;
" a response " ) ) ;
}
}
/* send final chunk if we're in chunked transfer mode */
/* send final chunk if we're in chunked transfer mode */
ensure ( uh_http_send ( cl , req , " " , 0 ) ) ;
ensure_out ( uh_http_send ( cl , req , " " , 0 ) ) ;
break ;
break ;
}
}