httpd: a little bit more correct handling of CGI "HTTP/xxx" output

This commit is contained in:
Denis Vlasenko
2007-02-13 23:42:54 +00:00
parent e54b472ffc
commit b5368bf437
2 changed files with 49 additions and 35 deletions

View File

@@ -7,8 +7,6 @@
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/ */
#include <stdio.h>
#include <unistd.h>
#include "libbb.h" #include "libbb.h"
/* /*

View File

@@ -967,7 +967,7 @@ static int sendCgi(const char *url,
int pid = 0; int pid = 0;
int inFd; int inFd;
int outFd; int outFd;
int firstLine = 1; int buf_count;
int status; int status;
size_t post_read_size, post_read_idx; size_t post_read_size, post_read_idx;
@@ -994,7 +994,7 @@ static int sendCgi(const char *url,
dup2(toCgi[0], 0); // replace stdin with the pipe dup2(toCgi[0], 0); // replace stdin with the pipe
dup2(fromCgi[1], 1); // replace stdout with the pipe dup2(fromCgi[1], 1); // replace stdout with the pipe
/* Huh? User seeing stderr can be a security problem... /* Huh? User seeing stderr can be a security problem...
* and if cgi really wants that, it can always dup2(1,2)... * and if CGI really wants that, it can always dup2(1,2)...
if (!DEBUG) if (!DEBUG)
dup2(fromCgi[1], 2); // replace stderr with the pipe dup2(fromCgi[1], 2); // replace stderr with the pipe
*/ */
@@ -1125,6 +1125,7 @@ static int sendCgi(const char *url,
/* parent process */ /* parent process */
buf_count = 0;
post_read_size = 0; post_read_size = 0;
post_read_idx = 0; /* for gcc */ post_read_idx = 0; /* for gcc */
inFd = fromCgi[0]; inFd = fromCgi[0];
@@ -1162,10 +1163,11 @@ static int sendCgi(const char *url,
} }
if (nfound <= 0) { if (nfound <= 0) {
if (waitpid(pid, &status, WNOHANG) <= 0) if (waitpid(pid, &status, WNOHANG) <= 0) {
/* Weird. CGI didn't exit and no fd's /* Weird. CGI didn't exit and no fd's
* are ready, yet select returned?! */ * are ready, yet select returned?! */
continue; continue;
}
close(inFd); close(inFd);
if (DEBUG && WIFEXITED(status)) if (DEBUG && WIFEXITED(status))
bb_error_msg("piped has exited with status=%d", WEXITSTATUS(status)); bb_error_msg("piped has exited with status=%d", WEXITSTATUS(status));
@@ -1190,7 +1192,7 @@ static int sendCgi(const char *url,
) { ) {
/* We expect data, prev data portion is eaten by CGI /* We expect data, prev data portion is eaten by CGI
* and there *is* data to read from the peer * and there *is* data to read from the peer
* (POST data?) */ * (POSTDATA?) */
count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen; count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen;
count = safe_read(config->accepted_socket, wbuf, count); count = safe_read(config->accepted_socket, wbuf, count);
if (count > 0) { if (count > 0) {
@@ -1202,34 +1204,42 @@ static int sendCgi(const char *url,
} }
} }
if (FD_ISSET(inFd, &readSet)) {
/* There is something to read from CGI */
int s = config->accepted_socket;
char *rbuf = config->buf;
#define PIPESIZE PIPE_BUF #define PIPESIZE PIPE_BUF
#if PIPESIZE >= MAX_MEMORY_BUFF #if PIPESIZE >= MAX_MEMORY_BUFF
# error "PIPESIZE >= MAX_MEMORY_BUFF" # error "PIPESIZE >= MAX_MEMORY_BUFF"
#endif #endif
if (FD_ISSET(inFd, &readSet)) {
/* There is something to read from CGI */
int s = config->accepted_socket;
char *rbuf = config->buf;
/* Are we still buffering CGI output? */
if (buf_count >= 0) {
static const char HTTP_200[] = "HTTP/1.0 200 OK\r\n\r\n";
/* Must use safe_read, not full_read, because /* Must use safe_read, not full_read, because
* cgi may output a few first lines and then wait * CGI may output a few first bytes and then wait
* for POSTDATA without closing stdout. * for POSTDATA without closing stdout.
* With full_read we may wait here forever. */ * With full_read we may wait here forever. */
count = safe_read(inFd, rbuf, PIPESIZE); count = safe_read(inFd, rbuf + buf_count, PIPESIZE - 4);
if (count == 0) if (count <= 0) {
/* eof (or error) and there was no "HTTP",
* so add one and write out the received data */
if (buf_count) {
full_write(s, HTTP_200, sizeof(HTTP_200)-1);
full_write(s, rbuf, buf_count);
}
break; /* closed */ break; /* closed */
if (count < 0) }
continue; /* huh, error, why continue?? */ buf_count += count;
count = 0;
if (firstLine) { if (buf_count >= 4) {
static const char HTTP_200[] = "HTTP/1.0 200 OK\r\n\r\n"; /* check to see if CGI added "HTTP" */
rbuf[count] = '\0';
/* check to see if the user script added headers */
/* (NB: buggy wrt cgi splitting "HTTP OK") */
if (memcmp(rbuf, HTTP_200, 4) != 0) { if (memcmp(rbuf, HTTP_200, 4) != 0) {
/* there is no "HTTP", do it ourself */ /* there is no "HTTP", do it ourself */
full_write(s, HTTP_200, sizeof(HTTP_200)-1); if (full_write(s, HTTP_200, sizeof(HTTP_200)-1) != sizeof(HTTP_200)-1)
break;
} }
/* Example of valid GCI without "Content-type:" /* example of valid CGI without "Content-type:"
* echo -en "HTTP/1.0 302 Found\r\n" * echo -en "HTTP/1.0 302 Found\r\n"
* echo -en "Location: http://www.busybox.net\r\n" * echo -en "Location: http://www.busybox.net\r\n"
* echo -en "\r\n" * echo -en "\r\n"
@@ -1237,7 +1247,13 @@ static int sendCgi(const char *url,
full_write(s, "Content-type: text/plain\r\n\r\n", 28); full_write(s, "Content-type: text/plain\r\n\r\n", 28);
} }
*/ */
firstLine = 0; count = buf_count;
buf_count = -1; /* buffering off */
}
} else {
count = safe_read(inFd, rbuf, PIPESIZE);
if (count <= 0)
break; /* eof (or error) */
} }
if (full_write(s, rbuf, count) != count) if (full_write(s, rbuf, count) != count)
break; break;