|
|
@@ -139,7 +139,7 @@ void uh_cgi_request(
|
|
|
struct client *cl, struct http_request *req,
|
|
|
struct path_info *pi, struct interpreter *ip
|
|
|
) {
|
|
|
- int i, hdroff, bufoff;
|
|
|
+ int i, hdroff, bufoff, rv;
|
|
|
int hdrlen = 0;
|
|
|
int buflen = 0;
|
|
|
int fd_max = 0;
|
|
|
@@ -376,12 +376,6 @@ void uh_cgi_request(
|
|
|
|
|
|
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 */
|
|
|
while( 1 )
|
|
|
{
|
|
|
@@ -391,11 +385,21 @@ void uh_cgi_request(
|
|
|
FD_SET(rfd[0], &reader);
|
|
|
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 */
|
|
|
- if( select_intr(fd_max, &reader,
|
|
|
- (content_length > -1) ? &writer : NULL, NULL,
|
|
|
- (header_sent < 1) ? &timeout : NULL) > 0
|
|
|
- ) {
|
|
|
+ else if( rv > 0 )
|
|
|
+ {
|
|
|
/* ready to write to cgi program */
|
|
|
if( FD_ISSET(wfd[1], &writer) )
|
|
|
{
|
|
|
@@ -403,7 +407,10 @@ void uh_cgi_request(
|
|
|
if( content_length > 0 )
|
|
|
{
|
|
|
/* 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 */
|
|
|
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 )
|
|
|
{
|
|
|
/* write status */
|
|
|
- ensure(uh_http_sendf(cl, NULL,
|
|
|
+ ensure_out(uh_http_sendf(cl, NULL,
|
|
|
"HTTP/%.1f %03d %s\r\n"
|
|
|
"Connection: close\r\n",
|
|
|
req->version, res->statuscode,
|
|
|
@@ -466,7 +473,7 @@ void uh_cgi_request(
|
|
|
if( !uh_cgi_header_lookup(res, "Location") &&
|
|
|
!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));
|
|
|
}
|
|
|
|
|
|
@@ -474,32 +481,32 @@ void uh_cgi_request(
|
|
|
if( (req->version > 1.0) &&
|
|
|
!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));
|
|
|
}
|
|
|
|
|
|
/* write headers from CGI program */
|
|
|
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]));
|
|
|
}
|
|
|
|
|
|
/* 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 */
|
|
|
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 */
|
|
|
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"));
|
|
|
|
|
|
- ensure(uh_http_send(cl, req, hdr, hdrlen));
|
|
|
+ ensure_out(uh_http_send(cl, req, hdr, hdrlen));
|
|
|
}
|
|
|
|
|
|
/* ... failed but free buffer space, try again */
|
|
|
@@ -510,7 +517,7 @@ void uh_cgi_request(
|
|
|
|
|
|
/* push out remaining read buffer */
|
|
|
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;
|
|
|
continue;
|
|
|
@@ -518,7 +525,7 @@ void uh_cgi_request(
|
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
@@ -538,7 +545,7 @@ void uh_cgi_request(
|
|
|
* build the required headers here.
|
|
|
*/
|
|
|
|
|
|
- ensure(uh_http_sendf(cl, NULL,
|
|
|
+ ensure_out(uh_http_sendf(cl, NULL,
|
|
|
"HTTP/%.1f 200 OK\r\n"
|
|
|
"Content-Type: text/plain\r\n"
|
|
|
"%s\r\n",
|
|
|
@@ -546,11 +553,11 @@ void uh_cgi_request(
|
|
|
? "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 */
|
|
|
- ensure(uh_http_send(cl, req, "", 0));
|
|
|
+ ensure_out(uh_http_send(cl, req, "", 0));
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
@@ -561,13 +568,13 @@ void uh_cgi_request(
|
|
|
{
|
|
|
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 "
|
|
|
"a response"));
|
|
|
}
|
|
|
|
|
|
/* 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;
|
|
|
}
|