diff options
-rw-r--r-- | networking/httpd.c | 137 |
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 | |||
96 | static const char httpdVersion[] = "busybox httpd/1.35 6-Oct-2004"; | 101 | static const char httpdVersion[] = "busybox httpd/1.35 6-Oct-2004"; |
97 | static const char default_path_httpd_conf[] = "/etc"; | 102 | static const char default_path_httpd_conf[] = "/etc"; |
98 | static const char httpd_conf[] = "httpd.conf"; | 103 | static 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 */ |