aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/httpd.c137
1 files changed, 76 insertions, 61 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index bf3da36d9..da33146de 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -93,6 +93,11 @@
93 93
94#include "busybox.h" 94#include "busybox.h"
95 95
96/* amount of buffering in a pipe */
97#ifndef PIPE_BUF
98# define PIPE_BUF 4096
99#endif
100
96static const char httpdVersion[] = "busybox httpd/1.35 6-Oct-2004"; 101static const char httpdVersion[] = "busybox httpd/1.35 6-Oct-2004";
97static const char default_path_httpd_conf[] = "/etc"; 102static const char default_path_httpd_conf[] = "/etc";
98static const char httpd_conf[] = "httpd.conf"; 103static const char httpd_conf[] = "httpd.conf";
@@ -106,10 +111,7 @@ static const char home[] = "./";
106// is checked rigorously 111// is checked rigorously
107 112
108//#define DEBUG 1 113//#define DEBUG 1
109 114#define DEBUG 0
110#ifndef DEBUG
111# define DEBUG 0
112#endif
113 115
114#define MAX_MEMORY_BUFF 8192 /* IO buffer */ 116#define MAX_MEMORY_BUFF 8192 /* IO buffer */
115 117
@@ -885,8 +887,8 @@ static int sendHeaders(HttpResponseNum responseNum)
885 /* emit the current date */ 887 /* emit the current date */
886 strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer)); 888 strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer));
887 len = sprintf(buf, 889 len = sprintf(buf,
888 "HTTP/1.0 %d %s\r\nContent-type: %s\r\n" 890 "HTTP/1.0 %d %s\r\nContent-type: %s\r\n"
889 "Date: %s\r\nConnection: close\r\n", 891 "Date: %s\r\nConnection: close\r\n",
890 responseNum, responseString, mime_type, timeStr); 892 responseNum, responseString, mime_type, timeStr);
891 893
892#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 894#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
@@ -986,7 +988,7 @@ static int sendCgi(const char *url,
986 int outFd; 988 int outFd;
987 int firstLine = 1; 989 int firstLine = 1;
988 int status; 990 int status;
989 size_t post_readed_size, post_readed_idx; 991 size_t post_read_size, post_read_idx;
990 992
991 if (pipe(fromCgi) != 0) 993 if (pipe(fromCgi) != 0)
992 return 0; 994 return 0;
@@ -1000,7 +1002,7 @@ static int sendCgi(const char *url,
1000 if (!pid) { 1002 if (!pid) {
1001 /* child process */ 1003 /* child process */
1002 char *script; 1004 char *script;
1003 char *purl = strdup(url); 1005 char *purl = xstrdup(url);
1004 char realpath_buff[MAXPATHLEN]; 1006 char realpath_buff[MAXPATHLEN];
1005 1007
1006 if (purl == NULL) 1008 if (purl == NULL)
@@ -1129,8 +1131,8 @@ static int sendCgi(const char *url,
1129 1131
1130 /* parent process */ 1132 /* parent process */
1131 1133
1132 post_readed_size = 0; 1134 post_read_size = 0;
1133 post_readed_idx = 0; 1135 post_read_idx = 0; /* for gcc */
1134 inFd = fromCgi[0]; 1136 inFd = fromCgi[0];
1135 outFd = toCgi[1]; 1137 outFd = toCgi[1];
1136 close(fromCgi[1]); 1138 close(fromCgi[1]);
@@ -1147,95 +1149,108 @@ static int sendCgi(const char *url,
1147 FD_ZERO(&readSet); 1149 FD_ZERO(&readSet);
1148 FD_ZERO(&writeSet); 1150 FD_ZERO(&writeSet);
1149 FD_SET(inFd, &readSet); 1151 FD_SET(inFd, &readSet);
1150 if (bodyLen > 0 || post_readed_size > 0) { 1152 if (bodyLen > 0 || post_read_size > 0) {
1151 FD_SET(outFd, &writeSet); 1153 FD_SET(outFd, &writeSet);
1152 nfound = outFd > inFd ? outFd : inFd; 1154 nfound = outFd > inFd ? outFd : inFd;
1153 if (post_readed_size == 0) { 1155 if (post_read_size == 0) {
1154 FD_SET(config->accepted_socket, &readSet); 1156 FD_SET(config->accepted_socket, &readSet);
1155 if (nfound < config->accepted_socket) 1157 if (nfound < config->accepted_socket)
1156 nfound = config->accepted_socket; 1158 nfound = config->accepted_socket;
1157 } 1159 }
1158 /* Now wait on the set of sockets! */ 1160 /* Now wait on the set of sockets! */
1159 nfound = select(nfound + 1, &readSet, &writeSet, 0, NULL); 1161 nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL);
1160 } else { 1162 } else {
1161 if (!bodyLen) { 1163 if (!bodyLen) {
1162 close(outFd); 1164 close(outFd); /* no more POST data to CGI */
1163 bodyLen = -1; 1165 bodyLen = -1;
1164 } 1166 }
1165 nfound = select(inFd + 1, &readSet, 0, 0, NULL); 1167 nfound = select(inFd + 1, &readSet, NULL, NULL, NULL);
1166 } 1168 }
1167 1169
1168 if (nfound <= 0) { 1170 if (nfound <= 0) {
1169 if (waitpid(pid, &status, WNOHANG) > 0) { 1171 if (waitpid(pid, &status, WNOHANG) <= 0)
1170 close(inFd); 1172 /* Weird. CGI didn't exit and no fd's
1171 if (DEBUG && WIFEXITED(status)) 1173 * are ready, yet select returned?! */
1172 bb_error_msg("piped has exited with status=%d", WEXITSTATUS(status)); 1174 continue;
1173 if (DEBUG && WIFSIGNALED(status)) 1175 close(inFd);
1174 bb_error_msg("piped has exited with signal=%d", WTERMSIG(status)); 1176 if (DEBUG && WIFEXITED(status))
1175 break; 1177 bb_error_msg("piped has exited with status=%d", WEXITSTATUS(status));
1176 } 1178 if (DEBUG && WIFSIGNALED(status))
1177 } else if (post_readed_size > 0 && FD_ISSET(outFd, &writeSet)) { 1179 bb_error_msg("piped has exited with signal=%d", WTERMSIG(status));
1178 count = full_write(outFd, wbuf + post_readed_idx, post_readed_size); 1180 break;
1181 }
1182
1183 if (post_read_size > 0 && FD_ISSET(outFd, &writeSet)) {
1184 /* Have data from peer and can write to CGI */
1185 // huh? why full_write? what if we will block?
1186 // (imagine that CGI does not read its stdin...)
1187 count = full_write(outFd, wbuf + post_read_idx, post_read_size);
1179 if (count > 0) { 1188 if (count > 0) {
1180 post_readed_size -= count; 1189 post_read_idx += count;
1181 post_readed_idx += count; 1190 post_read_size -= count;
1182 if (post_readed_size == 0)
1183 post_readed_idx = 0;
1184 } else { 1191 } else {
1185 post_readed_size = post_readed_idx = bodyLen = 0; /* broken pipe to CGI */ 1192 post_read_size = bodyLen = 0; /* broken pipe to CGI */
1186 } 1193 }
1187 } else if (bodyLen > 0 && post_readed_size == 0 && FD_ISSET(config->accepted_socket, &readSet)) { 1194 } else if (bodyLen > 0 && post_read_size == 0
1195 && FD_ISSET(config->accepted_socket, &readSet)
1196 ) {
1197 /* We expect data, prev data portion is eaten by CGI
1198 * and there *is* data to read from the peer
1199 * (POST data?) */
1188 count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen; 1200 count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen;
1189 count = safe_read(config->accepted_socket, wbuf, count); 1201 count = safe_read(config->accepted_socket, wbuf, count);
1190 if (count > 0) { 1202 if (count > 0) {
1191 post_readed_size += count; 1203 post_read_size = count;
1204 post_read_idx = 0;
1192 bodyLen -= count; 1205 bodyLen -= count;
1193 } else { 1206 } else {
1194 bodyLen = 0; /* closed */ 1207 bodyLen = 0; /* closed */
1195 } 1208 }
1196 } 1209 }
1210
1197 if (FD_ISSET(inFd, &readSet)) { 1211 if (FD_ISSET(inFd, &readSet)) {
1212 /* There is something to read from CGI */
1198 int s = config->accepted_socket; 1213 int s = config->accepted_socket;
1199 char *rbuf = config->buf; 1214 char *rbuf = config->buf;
1200 1215#define PIPESIZE PIPE_BUF
1201#ifndef PIPE_BUF
1202# define PIPESIZE 4096 /* amount of buffering in a pipe */
1203#else
1204# define PIPESIZE PIPE_BUF
1205#endif
1206#if PIPESIZE >= MAX_MEMORY_BUFF 1216#if PIPESIZE >= MAX_MEMORY_BUFF
1207# error "PIPESIZE >= MAX_MEMORY_BUFF" 1217# error "PIPESIZE >= MAX_MEMORY_BUFF"
1208#endif 1218#endif
1209
1210 /* There is something to read */
1211 /* NB: was safe_read. If it *has to be* safe_read, */ 1219 /* NB: was safe_read. If it *has to be* safe_read, */
1212 /* please explain why in this comment... */ 1220 /* please explain why in this comment... */
1213 count = full_read(inFd, rbuf, PIPESIZE); 1221 count = full_read(inFd, rbuf, PIPESIZE);
1214 if (count == 0) 1222 if (count == 0)
1215 break; /* closed */ 1223 break; /* closed */
1216 if (count > 0) { 1224 if (count < 0)
1217 if (firstLine) { 1225 continue; /* huh, error, why continue?? */
1218 /* full_read (above) avoids 1226
1219 * "chopped up into small chunks" syndrome here */ 1227 if (firstLine) {
1220 rbuf[count] = 0; 1228 /* full_read (above) avoids
1221 /* check to see if the user script added headers */ 1229 * "chopped up into small chunks" syndrome here */
1222 if (strncmp(rbuf, "HTTP/1.0 200 OK\r\n", 4) != 0) { 1230 rbuf[count] = '\0';
1223 /* there is no "HTTP", do it ourself */ 1231 /* check to see if the user script added headers */
1224 full_write(s, "HTTP/1.0 200 OK\r\n", 17); 1232#define HTTP_200 "HTTP/1.0 200 OK\r\n\r\n"
1225 } /* hmm, maybe 'else if'? */ 1233 if (memcmp(rbuf, HTTP_200, 4) != 0) {
1226 if (!strstr(rbuf, "ontent-")) { 1234 /* there is no "HTTP", do it ourself */
1227 full_write(s, "Content-type: text/plain\r\n\r\n", 28); 1235 full_write(s, HTTP_200, sizeof(HTTP_200)-1);
1228 }
1229 firstLine = 0;
1230 } 1236 }
1231 if (full_write(s, rbuf, count) != count) 1237#undef HTTP_200
1232 break; 1238 /* Example of valid GCI without "Content-type:"
1233 1239 * echo -en "HTTP/1.0 302 Found\r\n"
1234 if (DEBUG) 1240 * echo -en "Location: http://www.busybox.net\r\n"
1235 fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf); 1241 * echo -en "\r\n"
1242 */
1243 //if (!strstr(rbuf, "ontent-")) {
1244 // full_write(s, "Content-type: text/plain\r\n\r\n", 28);
1245 //}
1246 firstLine = 0;
1236 } 1247 }
1237 } 1248 if (full_write(s, rbuf, count) != count)
1238 } 1249 break;
1250 if (DEBUG)
1251 fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf);
1252 } /* if (FD_ISSET(inFd)) */
1253 } /* while (1) */
1239 return 0; 1254 return 0;
1240} 1255}
1241#endif /* FEATURE_HTTPD_CGI */ 1256#endif /* FEATURE_HTTPD_CGI */