diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-13 23:42:54 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-13 23:42:54 +0000 |
commit | b5368bf437970dfdab7136af527a208f059c5c78 (patch) | |
tree | f673cf7b75fa2d3d3567763bcea0900a2c6f5530 | |
parent | e54b472ffc7e30d97e1f3df8e61a67edf8c2197b (diff) | |
download | busybox-w32-b5368bf437970dfdab7136af527a208f059c5c78.tar.gz busybox-w32-b5368bf437970dfdab7136af527a208f059c5c78.tar.bz2 busybox-w32-b5368bf437970dfdab7136af527a208f059c5c78.zip |
httpd: a little bit more correct handling of CGI "HTTP/xxx" output
-rw-r--r-- | libbb/full_write.c | 2 | ||||
-rw-r--r-- | networking/httpd.c | 84 |
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; |