aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-02-13 23:42:54 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-02-13 23:42:54 +0000
commiteff633f958509cb5cfa336fae7e5d4915ae63f27 (patch)
treef673cf7b75fa2d3d3567763bcea0900a2c6f5530
parentac2036f3cdc4911776c7a7362d84ce4bb8276c36 (diff)
downloadbusybox-w32-eff633f958509cb5cfa336fae7e5d4915ae63f27.tar.gz
busybox-w32-eff633f958509cb5cfa336fae7e5d4915ae63f27.tar.bz2
busybox-w32-eff633f958509cb5cfa336fae7e5d4915ae63f27.zip
httpd: a little bit more correct handling of CGI "HTTP/xxx" output
git-svn-id: svn://busybox.net/trunk/busybox@17879 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--libbb/full_write.c2
-rw-r--r--networking/httpd.c84
2 files changed, 50 insertions, 36 deletions
diff --git a/libbb/full_write.c b/libbb/full_write.c
index bceac6de5..7bbacb8ac 100644
--- a/libbb/full_write.c
+++ b/libbb/full_write.c
@@ -7,8 +7,6 @@
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */ 8 */
9 9
10#include <stdio.h>
11#include <unistd.h>
12#include "libbb.h" 10#include "libbb.h"
13 11
14/* 12/*
diff --git a/networking/httpd.c b/networking/httpd.c
index 6f4ca05a7..3524531e3 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -967,7 +967,7 @@ static int sendCgi(const char *url,
967 int pid = 0; 967 int pid = 0;
968 int inFd; 968 int inFd;
969 int outFd; 969 int outFd;
970 int firstLine = 1; 970 int buf_count;
971 int status; 971 int status;
972 size_t post_read_size, post_read_idx; 972 size_t post_read_size, post_read_idx;
973 973
@@ -994,7 +994,7 @@ static int sendCgi(const char *url,
994 dup2(toCgi[0], 0); // replace stdin with the pipe 994 dup2(toCgi[0], 0); // replace stdin with the pipe
995 dup2(fromCgi[1], 1); // replace stdout with the pipe 995 dup2(fromCgi[1], 1); // replace stdout with the pipe
996 /* Huh? User seeing stderr can be a security problem... 996 /* Huh? User seeing stderr can be a security problem...
997 * and if cgi really wants that, it can always dup2(1,2)... 997 * and if CGI really wants that, it can always dup2(1,2)...
998 if (!DEBUG) 998 if (!DEBUG)
999 dup2(fromCgi[1], 2); // replace stderr with the pipe 999 dup2(fromCgi[1], 2); // replace stderr with the pipe
1000 */ 1000 */
@@ -1125,6 +1125,7 @@ static int sendCgi(const char *url,
1125 1125
1126 /* parent process */ 1126 /* parent process */
1127 1127
1128 buf_count = 0;
1128 post_read_size = 0; 1129 post_read_size = 0;
1129 post_read_idx = 0; /* for gcc */ 1130 post_read_idx = 0; /* for gcc */
1130 inFd = fromCgi[0]; 1131 inFd = fromCgi[0];
@@ -1162,10 +1163,11 @@ static int sendCgi(const char *url,
1162 } 1163 }
1163 1164
1164 if (nfound <= 0) { 1165 if (nfound <= 0) {
1165 if (waitpid(pid, &status, WNOHANG) <= 0) 1166 if (waitpid(pid, &status, WNOHANG) <= 0) {
1166 /* Weird. CGI didn't exit and no fd's 1167 /* Weird. CGI didn't exit and no fd's
1167 * are ready, yet select returned?! */ 1168 * are ready, yet select returned?! */
1168 continue; 1169 continue;
1170 }
1169 close(inFd); 1171 close(inFd);
1170 if (DEBUG && WIFEXITED(status)) 1172 if (DEBUG && WIFEXITED(status))
1171 bb_error_msg("piped has exited with status=%d", WEXITSTATUS(status)); 1173 bb_error_msg("piped has exited with status=%d", WEXITSTATUS(status));
@@ -1190,7 +1192,7 @@ static int sendCgi(const char *url,
1190 ) { 1192 ) {
1191 /* We expect data, prev data portion is eaten by CGI 1193 /* We expect data, prev data portion is eaten by CGI
1192 * and there *is* data to read from the peer 1194 * and there *is* data to read from the peer
1193 * (POST data?) */ 1195 * (POSTDATA?) */
1194 count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen; 1196 count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen;
1195 count = safe_read(config->accepted_socket, wbuf, count); 1197 count = safe_read(config->accepted_socket, wbuf, count);
1196 if (count > 0) { 1198 if (count > 0) {
@@ -1202,42 +1204,56 @@ static int sendCgi(const char *url,
1202 } 1204 }
1203 } 1205 }
1204 1206
1205 if (FD_ISSET(inFd, &readSet)) {
1206 /* There is something to read from CGI */
1207 int s = config->accepted_socket;
1208 char *rbuf = config->buf;
1209#define PIPESIZE PIPE_BUF 1207#define PIPESIZE PIPE_BUF
1210#if PIPESIZE >= MAX_MEMORY_BUFF 1208#if PIPESIZE >= MAX_MEMORY_BUFF
1211# error "PIPESIZE >= MAX_MEMORY_BUFF" 1209# error "PIPESIZE >= MAX_MEMORY_BUFF"
1212#endif 1210#endif
1213 /* Must use safe_read, not full_read, because 1211 if (FD_ISSET(inFd, &readSet)) {
1214 * cgi may output a few first lines and then wait 1212 /* There is something to read from CGI */
1215 * for POSTDATA without closing stdout. 1213 int s = config->accepted_socket;
1216 * With full_read we may wait here forever. */ 1214 char *rbuf = config->buf;
1217 count = safe_read(inFd, rbuf, PIPESIZE); 1215
1218 if (count == 0) 1216 /* Are we still buffering CGI output? */
1219 break; /* closed */ 1217 if (buf_count >= 0) {
1220 if (count < 0)
1221 continue; /* huh, error, why continue?? */
1222
1223 if (firstLine) {
1224 static const char HTTP_200[] = "HTTP/1.0 200 OK\r\n\r\n"; 1218 static const char HTTP_200[] = "HTTP/1.0 200 OK\r\n\r\n";
1225 rbuf[count] = '\0'; 1219 /* Must use safe_read, not full_read, because
1226 /* check to see if the user script added headers */ 1220 * CGI may output a few first bytes and then wait
1227 /* (NB: buggy wrt cgi splitting "HTTP OK") */ 1221 * for POSTDATA without closing stdout.
1228 if (memcmp(rbuf, HTTP_200, 4) != 0) { 1222 * With full_read we may wait here forever. */
1229 /* there is no "HTTP", do it ourself */ 1223 count = safe_read(inFd, rbuf + buf_count, PIPESIZE - 4);
1230 full_write(s, HTTP_200, sizeof(HTTP_200)-1); 1224 if (count <= 0) {
1225 /* eof (or error) and there was no "HTTP",
1226 * so add one and write out the received data */
1227 if (buf_count) {
1228 full_write(s, HTTP_200, sizeof(HTTP_200)-1);
1229 full_write(s, rbuf, buf_count);
1230 }
1231 break; /* closed */
1231 } 1232 }
1232 /* Example of valid GCI without "Content-type:" 1233 buf_count += count;
1233 * echo -en "HTTP/1.0 302 Found\r\n" 1234 count = 0;
1234 * echo -en "Location: http://www.busybox.net\r\n" 1235 if (buf_count >= 4) {
1235 * echo -en "\r\n" 1236 /* check to see if CGI added "HTTP" */
1236 if (!strstr(rbuf, "ontent-")) { 1237 if (memcmp(rbuf, HTTP_200, 4) != 0) {
1237 full_write(s, "Content-type: text/plain\r\n\r\n", 28); 1238 /* there is no "HTTP", do it ourself */
1239 if (full_write(s, HTTP_200, sizeof(HTTP_200)-1) != sizeof(HTTP_200)-1)
1240 break;
1241 }
1242 /* example of valid CGI without "Content-type:"
1243 * echo -en "HTTP/1.0 302 Found\r\n"
1244 * echo -en "Location: http://www.busybox.net\r\n"
1245 * echo -en "\r\n"
1246 if (!strstr(rbuf, "ontent-")) {
1247 full_write(s, "Content-type: text/plain\r\n\r\n", 28);
1248 }
1249 */
1250 count = buf_count;
1251 buf_count = -1; /* buffering off */
1238 } 1252 }
1239 */ 1253 } else {
1240 firstLine = 0; 1254 count = safe_read(inFd, rbuf, PIPESIZE);
1255 if (count <= 0)
1256 break; /* eof (or error) */
1241 } 1257 }
1242 if (full_write(s, rbuf, count) != count) 1258 if (full_write(s, rbuf, count) != count)
1243 break; 1259 break;