aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-08-17 19:19:15 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-08-17 19:19:15 +0000
commite45af73dc233d345a642386431703ad9a1597093 (patch)
tree15592222186556954d34603fbeb11e6fa4f7d2d9
parent241b1567adfa481e9c160f24d4ea7ca29ca7dd3e (diff)
downloadbusybox-w32-e45af73dc233d345a642386431703ad9a1597093.tar.gz
busybox-w32-e45af73dc233d345a642386431703ad9a1597093.tar.bz2
busybox-w32-e45af73dc233d345a642386431703ad9a1597093.zip
httpd shrink and logging update, part 3 of 7
text data bss dec hex filename 9836 0 0 9836 266c busybox.t1/networking/httpd.o.orig 9724 0 0 9724 25fc busybox.t2/networking/httpd.o 9657 0 0 9657 25b9 busybox.t3/networking/httpd.o 9342 0 0 9342 247e busybox.t4/networking/httpd.o 9342 0 0 9342 247e busybox.t5/networking/httpd.o 9262 0 0 9262 242e busybox.t6/networking/httpd.o 9283 0 0 9283 2443 busybox.t7/networking/httpd.o 9334 0 0 9334 2476 busybox.t8/networking/httpd.o
-rw-r--r--networking/httpd.c255
1 files changed, 107 insertions, 148 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index 2ac19cf47..35aa492d0 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -133,7 +133,6 @@ struct globals {
133 int server_socket; 133 int server_socket;
134 int accepted_socket; 134 int accepted_socket;
135 int verbose; 135 int verbose;
136 volatile smallint alarm_signaled;
137 smallint flg_deny_all; 136 smallint flg_deny_all;
138 137
139 unsigned rmt_ip; 138 unsigned rmt_ip;
@@ -172,7 +171,6 @@ struct globals {
172#define server_socket (G.server_socket ) 171#define server_socket (G.server_socket )
173#define accepted_socket (G.accepted_socket ) 172#define accepted_socket (G.accepted_socket )
174#define verbose (G.verbose ) 173#define verbose (G.verbose )
175#define alarm_signaled (G.alarm_signaled )
176#define flg_deny_all (G.flg_deny_all ) 174#define flg_deny_all (G.flg_deny_all )
177#define rmt_ip (G.rmt_ip ) 175#define rmt_ip (G.rmt_ip )
178#define tcp_port (G.tcp_port ) 176#define tcp_port (G.tcp_port )
@@ -920,6 +918,13 @@ static int sendHeaders(HttpResponseNum responseNum)
920 return full_write(i, iobuf, len); 918 return full_write(i, iobuf, len);
921} 919}
922 920
921static void send_headers_and_exit(HttpResponseNum responseNum) ATTRIBUTE_NORETURN;
922static void send_headers_and_exit(HttpResponseNum responseNum)
923{
924 sendHeaders(responseNum);
925 _exit(0);
926}
927
923/* 928/*
924 * Read from the socket until '\n' or EOF. '\r' chars are removed. 929 * Read from the socket until '\n' or EOF. '\r' chars are removed.
925 * '\n' is replaced with NUL. 930 * '\n' is replaced with NUL.
@@ -976,8 +981,6 @@ static void send_cgi_and_exit(
976 struct { int rd; int wr; } toCgi; /* httpd -> CGI pipe */ 981 struct { int rd; int wr; } toCgi; /* httpd -> CGI pipe */
977 char *argp[] = { NULL, NULL }; 982 char *argp[] = { NULL, NULL };
978 int pid = 0; 983 int pid = 0;
979 int inFd;
980 int outFd;
981 int buf_count; 984 int buf_count;
982 int status; 985 int status;
983 size_t post_read_size, post_read_idx; 986 size_t post_read_size, post_read_idx;
@@ -1104,15 +1107,16 @@ static void send_cgi_and_exit(
1104 1107
1105 /* set execve argp[0] without path */ 1108 /* set execve argp[0] without path */
1106 argp[0] = (char*)bb_basename(purl); 1109 argp[0] = (char*)bb_basename(purl);
1107 /* but script argp[0] must have absolute path and chdiring to this */ 1110 /* but script argp[0] must have absolute path */
1108 script = strrchr(fullpath, '/'); 1111 script = strrchr(fullpath, '/');
1109 if (!script) 1112 if (!script)
1110 goto error_execing_cgi; 1113 goto error_execing_cgi;
1111 *script = '\0'; 1114 *script = '\0';
1115 /* chdiring to script's dir */
1112 if (chdir(fullpath) == 0) { 1116 if (chdir(fullpath) == 0) {
1113 // Now run the program. If it fails, 1117 /* Now run the program. If it fails,
1114 // use _exit() so no destructors 1118 * use _exit() so no destructors
1115 // get called and make a mess. 1119 * get called and make a mess. */
1116#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1120#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
1117 char *interpr = NULL; 1121 char *interpr = NULL;
1118 char *suffix = strrchr(purl, '.'); 1122 char *suffix = strrchr(purl, '.');
@@ -1136,7 +1140,8 @@ static void send_cgi_and_exit(
1136 execv(fullpath, argp); 1140 execv(fullpath, argp);
1137 } 1141 }
1138 error_execing_cgi: 1142 error_execing_cgi:
1139 /* send to stdout (even if we are not from inetd) */ 1143 /* send to stdout
1144 * (we are CGI here, our stdout is pumped to the net) */
1140 accepted_socket = 1; 1145 accepted_socket = 1;
1141 sendHeaders(HTTP_NOT_FOUND); 1146 sendHeaders(HTTP_NOT_FOUND);
1142 _exit(242); 1147 _exit(242);
@@ -1146,10 +1151,11 @@ static void send_cgi_and_exit(
1146 buf_count = 0; 1151 buf_count = 0;
1147 post_read_size = 0; 1152 post_read_size = 0;
1148 post_read_idx = 0; /* for gcc */ 1153 post_read_idx = 0; /* for gcc */
1149 inFd = fromCgi.rd;
1150 outFd = toCgi.wr;
1151 close(fromCgi.wr); 1154 close(fromCgi.wr);
1152 close(toCgi.rd); 1155 close(toCgi.rd);
1156
1157 /* If CGI dies, we still want to correctly finish reading its output
1158 * and send it to the peer. So please no SIGPIPEs! */
1153 signal(SIGPIPE, SIG_IGN); 1159 signal(SIGPIPE, SIG_IGN);
1154 1160
1155 while (1) { 1161 while (1) {
@@ -1159,12 +1165,17 @@ static void send_cgi_and_exit(
1159 int nfound; 1165 int nfound;
1160 int count; 1166 int count;
1161 1167
1168 /* This loop still looks messy. What is an exit criteria?
1169 * "CGI's output closed"? Or "CGI has exited"?
1170 * What to do if CGI has closed both input and output, but
1171 * didn't exit? etc... */
1172
1162 FD_ZERO(&readSet); 1173 FD_ZERO(&readSet);
1163 FD_ZERO(&writeSet); 1174 FD_ZERO(&writeSet);
1164 FD_SET(inFd, &readSet); 1175 FD_SET(fromCgi.rd, &readSet);
1165 if (bodyLen > 0 || post_read_size > 0) { 1176 if (bodyLen > 0 || post_read_size > 0) {
1166 FD_SET(outFd, &writeSet); 1177 FD_SET(toCgi.wr, &writeSet);
1167 nfound = outFd > inFd ? outFd : inFd; 1178 nfound = toCgi.wr > fromCgi.rd ? toCgi.wr : fromCgi.rd;
1168 if (post_read_size == 0) { 1179 if (post_read_size == 0) {
1169 FD_SET(accepted_socket, &readSet); 1180 FD_SET(accepted_socket, &readSet);
1170 if (nfound < accepted_socket) 1181 if (nfound < accepted_socket)
@@ -1174,10 +1185,10 @@ static void send_cgi_and_exit(
1174 nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL); 1185 nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL);
1175 } else { 1186 } else {
1176 if (!bodyLen) { 1187 if (!bodyLen) {
1177 close(outFd); /* no more POST data to CGI */ 1188 close(toCgi.wr); /* no more POST data to CGI */
1178 bodyLen = -1; 1189 bodyLen = -1;
1179 } 1190 }
1180 nfound = select(inFd + 1, &readSet, NULL, NULL, NULL); 1191 nfound = select(fromCgi.rd + 1, &readSet, NULL, NULL, NULL);
1181 } 1192 }
1182 1193
1183 if (nfound <= 0) { 1194 if (nfound <= 0) {
@@ -1186,24 +1197,26 @@ static void send_cgi_and_exit(
1186 * are ready, yet select returned?! */ 1197 * are ready, yet select returned?! */
1187 continue; 1198 continue;
1188 } 1199 }
1189 close(inFd); 1200 close(fromCgi.rd);
1190 if (DEBUG && WIFEXITED(status)) 1201 if (DEBUG && WIFEXITED(status))
1191 bb_error_msg("piped has exited with status=%d", WEXITSTATUS(status)); 1202 bb_error_msg("CGI exited, status=%d", WEXITSTATUS(status));
1192 if (DEBUG && WIFSIGNALED(status)) 1203 if (DEBUG && WIFSIGNALED(status))
1193 bb_error_msg("piped has exited with signal=%d", WTERMSIG(status)); 1204 bb_error_msg("CGI killed, signal=%d", WTERMSIG(status));
1194 break; 1205 break;
1195 } 1206 }
1196 1207
1197 if (post_read_size > 0 && FD_ISSET(outFd, &writeSet)) { 1208 if (post_read_size > 0 && FD_ISSET(toCgi.wr, &writeSet)) {
1198 /* Have data from peer and can write to CGI */ 1209 /* Have data from peer and can write to CGI */
1199 // huh? why full_write? what if we will block? 1210 count = safe_write(toCgi.wr, wbuf + post_read_idx, post_read_size);
1200 // (imagine that CGI does not read its stdin...) 1211 /* Doesn't happen, we dont use nonblocking IO here
1201 count = full_write(outFd, wbuf + post_read_idx, post_read_size); 1212 *if (count < 0 && errno == EAGAIN) {
1213 * ...
1214 *} else */
1202 if (count > 0) { 1215 if (count > 0) {
1203 post_read_idx += count; 1216 post_read_idx += count;
1204 post_read_size -= count; 1217 post_read_size -= count;
1205 } else { 1218 } else {
1206 post_read_size = bodyLen = 0; /* broken pipe to CGI */ 1219 post_read_size = bodyLen = 0; /* EOF/broken pipe to CGI */
1207 } 1220 }
1208 } else if (bodyLen > 0 && post_read_size == 0 1221 } else if (bodyLen > 0 && post_read_size == 0
1209 && FD_ISSET(accepted_socket, &readSet) 1222 && FD_ISSET(accepted_socket, &readSet)
@@ -1226,7 +1239,7 @@ static void send_cgi_and_exit(
1226#if PIPESIZE >= MAX_MEMORY_BUF 1239#if PIPESIZE >= MAX_MEMORY_BUF
1227# error "PIPESIZE >= MAX_MEMORY_BUF" 1240# error "PIPESIZE >= MAX_MEMORY_BUF"
1228#endif 1241#endif
1229 if (FD_ISSET(inFd, &readSet)) { 1242 if (FD_ISSET(fromCgi.rd, &readSet)) {
1230 /* There is something to read from CGI */ 1243 /* There is something to read from CGI */
1231 int s = accepted_socket; 1244 int s = accepted_socket;
1232 char *rbuf = iobuf; 1245 char *rbuf = iobuf;
@@ -1245,7 +1258,7 @@ static void send_cgi_and_exit(
1245 * CGI may output a few first bytes and then wait 1258 * CGI may output a few first bytes and then wait
1246 * for POSTDATA without closing stdout. 1259 * for POSTDATA without closing stdout.
1247 * With full_read we may wait here forever. */ 1260 * With full_read we may wait here forever. */
1248 count = safe_read(inFd, rbuf + buf_count, PIPESIZE - 8); 1261 count = safe_read(fromCgi.rd, rbuf + buf_count, PIPESIZE - 8);
1249 if (count <= 0) { 1262 if (count <= 0) {
1250 /* eof (or error) and there was no "HTTP", 1263 /* eof (or error) and there was no "HTTP",
1251 * so write it, then write received data */ 1264 * so write it, then write received data */
@@ -1285,7 +1298,7 @@ static void send_cgi_and_exit(
1285 buf_count = -1; /* buffering off */ 1298 buf_count = -1; /* buffering off */
1286 } 1299 }
1287 } else { 1300 } else {
1288 count = safe_read(inFd, rbuf, PIPESIZE); 1301 count = safe_read(fromCgi.rd, rbuf, PIPESIZE);
1289 if (count <= 0) 1302 if (count <= 0)
1290 break; /* eof (or error) */ 1303 break; /* eof (or error) */
1291 } 1304 }
@@ -1293,7 +1306,7 @@ static void send_cgi_and_exit(
1293 break; 1306 break;
1294 if (DEBUG) 1307 if (DEBUG)
1295 fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf); 1308 fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf);
1296 } /* if (FD_ISSET(inFd)) */ 1309 } /* if (FD_ISSET(fromCgi.rd)) */
1297 } /* while (1) */ 1310 } /* while (1) */
1298 _exit(0); 1311 _exit(0);
1299} 1312}
@@ -1338,15 +1351,14 @@ static void send_file_and_exit(const char *url)
1338#endif /* FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES */ 1351#endif /* FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES */
1339 1352
1340 if (DEBUG) 1353 if (DEBUG)
1341 fprintf(stderr, "sending file '%s' content-type: %s\n", 1354 bb_error_msg("sending file '%s' content-type: %s",
1342 url, found_mime_type); 1355 url, found_mime_type);
1343 1356
1344 f = open(url, O_RDONLY); 1357 f = open(url, O_RDONLY);
1345 if (f < 0) { 1358 if (f < 0) {
1346 if (DEBUG) 1359 if (DEBUG)
1347 bb_perror_msg("cannot open '%s'", url); 1360 bb_perror_msg("cannot open '%s'", url);
1348 sendHeaders(HTTP_NOT_FOUND); 1361 send_headers_and_exit(HTTP_NOT_FOUND);
1349 _exit(0);
1350 } 1362 }
1351 1363
1352 sendHeaders(HTTP_OK); 1364 sendHeaders(HTTP_OK);
@@ -1354,13 +1366,13 @@ static void send_file_and_exit(const char *url)
1354 if (fd == 0) 1366 if (fd == 0)
1355 fd++; /* write to fd #1 in inetd mode */ 1367 fd++; /* write to fd #1 in inetd mode */
1356 1368
1357 /* If you want to know about EPIPEs below 1369 /* If you want to know about EPIPE below
1358 * (happen if you abort downloads from local httpd) */ 1370 * (happens if you abort downloads from local httpd): */
1359 /*signal(SIGPIPE, SIG_IGN);*/ 1371 /* signal(SIGPIPE, SIG_IGN); */
1360 1372
1361#if ENABLE_FEATURE_HTTPD_USE_SENDFILE 1373#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
1362 do { 1374 do {
1363 /* byte count is rounded down to 64k */ 1375 /* byte count (3rd arg) is rounded down to 64k */
1364 count = sendfile(fd, f, &offset, MAXINT(ssize_t) - 0xffff); 1376 count = sendfile(fd, f, &offset, MAXINT(ssize_t) - 0xffff);
1365 if (count < 0) { 1377 if (count < 0) {
1366 if (offset == 0) 1378 if (offset == 0)
@@ -1372,8 +1384,7 @@ static void send_file_and_exit(const char *url)
1372 1384
1373 fallback: 1385 fallback:
1374#endif 1386#endif
1375 /* TODO: why full_read? safe_read maybe? */ 1387 while ((count = safe_read(f, iobuf, MAX_MEMORY_BUF)) > 0) {
1376 while ((count = full_read(f, iobuf, MAX_MEMORY_BUF)) > 0) {
1377 ssize_t n = count; 1388 ssize_t n = count;
1378 count = full_write(fd, iobuf, count); 1389 count = full_write(fd, iobuf, count);
1379 if (count != n) 1390 if (count != n)
@@ -1382,8 +1393,8 @@ static void send_file_and_exit(const char *url)
1382#if ENABLE_FEATURE_HTTPD_USE_SENDFILE 1393#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
1383 fin: 1394 fin:
1384#endif 1395#endif
1385 if (count < 0) 1396 if (count < 0 && verbose > 1)
1386 bb_perror_msg("error:%u", errno); 1397 bb_perror_msg("error");
1387 _exit(0); 1398 _exit(0);
1388} 1399}
1389 1400
@@ -1487,10 +1498,10 @@ static int checkPerm(const char *path, const char *request)
1487 } 1498 }
1488 1499
1489 if (strcmp(p, request) == 0) { 1500 if (strcmp(p, request) == 0) {
1490set_remoteuser_var: 1501 set_remoteuser_var:
1491 remoteuser = strdup(request); 1502 remoteuser = strdup(request);
1492 if (remoteuser) 1503 if (remoteuser)
1493 remoteuser[(u - request)] = 0; 1504 remoteuser[(u - request)] = '\0';
1494 return 1; /* Ok */ 1505 return 1; /* Ok */
1495 } 1506 }
1496 /* unauthorized */ 1507 /* unauthorized */
@@ -1505,10 +1516,10 @@ set_remoteuser_var:
1505/* 1516/*
1506 * Handle timeouts 1517 * Handle timeouts
1507 */ 1518 */
1508static void handle_sigalrm(int sig) 1519static void exit_on_signal(int sig) ATTRIBUTE_NORETURN;
1520static void exit_on_signal(int sig)
1509{ 1521{
1510 sendHeaders(HTTP_REQUEST_TIMEOUT); 1522 send_headers_and_exit(HTTP_REQUEST_TIMEOUT);
1511 alarm_signaled = 1;
1512} 1523}
1513 1524
1514/* 1525/*
@@ -1519,6 +1530,7 @@ static void handle_incoming_and_exit(void)
1519{ 1530{
1520 char *url; 1531 char *url;
1521 char *purl; 1532 char *purl;
1533 int count;
1522 int blank = -1; 1534 int blank = -1;
1523 char *test; 1535 char *test;
1524 struct stat sb; 1536 struct stat sb;
@@ -1535,7 +1547,7 @@ static void handle_incoming_and_exit(void)
1535 int credentials = -1; /* if not required this is Ok */ 1547 int credentials = -1; /* if not required this is Ok */
1536#endif 1548#endif
1537 1549
1538 sa.sa_handler = handle_sigalrm; 1550 sa.sa_handler = exit_on_signal;
1539 sigemptyset(&sa.sa_mask); 1551 sigemptyset(&sa.sa_mask);
1540 sa.sa_flags = 0; /* no SA_RESTART */ 1552 sa.sa_flags = 0; /* no SA_RESTART */
1541 sigaction(SIGALRM, &sa, NULL); 1553 sigaction(SIGALRM, &sa, NULL);
@@ -1543,31 +1555,25 @@ static void handle_incoming_and_exit(void)
1543 /* It's not a real loop (it ends with while(0)). 1555 /* It's not a real loop (it ends with while(0)).
1544 * Break from this "loop" jumps to exit(0) */ 1556 * Break from this "loop" jumps to exit(0) */
1545 do { 1557 do {
1546 int count;
1547
1548 alarm(TIMEOUT); 1558 alarm(TIMEOUT);
1549 if (!get_line()) 1559 if (!get_line())
1550 break; /* EOF or error or empty line */ 1560 _exit(0); /* EOF or error or empty line */
1551 1561
1552 purl = strpbrk(iobuf, " \t"); 1562 purl = strpbrk(iobuf, " \t");
1553 if (purl == NULL) { 1563 if (purl == NULL) {
1554 BAD_REQUEST: 1564 send_headers_and_exit(HTTP_BAD_REQUEST);
1555 sendHeaders(HTTP_BAD_REQUEST);
1556 break;
1557 } 1565 }
1558 *purl = '\0'; 1566 *purl = '\0';
1559#if ENABLE_FEATURE_HTTPD_CGI 1567#if ENABLE_FEATURE_HTTPD_CGI
1560 if (strcasecmp(iobuf, prequest) != 0) { 1568 if (strcasecmp(iobuf, prequest) != 0) {
1561 prequest = "POST"; 1569 prequest = "POST";
1562 if (strcasecmp(iobuf, prequest) != 0) { 1570 if (strcasecmp(iobuf, prequest) != 0) {
1563 sendHeaders(HTTP_NOT_IMPLEMENTED); 1571 send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
1564 break;
1565 } 1572 }
1566 } 1573 }
1567#else 1574#else
1568 if (strcasecmp(iobuf, request_GET) != 0) { 1575 if (strcasecmp(iobuf, request_GET) != 0) {
1569 sendHeaders(HTTP_NOT_IMPLEMENTED); 1576 send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
1570 break;
1571 } 1577 }
1572#endif 1578#endif
1573 *purl = ' '; 1579 *purl = ' ';
@@ -1575,12 +1581,11 @@ static void handle_incoming_and_exit(void)
1575 1581
1576 if (count < 1 || iobuf[0] != '/') { 1582 if (count < 1 || iobuf[0] != '/') {
1577 /* Garbled request/URL */ 1583 /* Garbled request/URL */
1578 goto BAD_REQUEST; 1584 send_headers_and_exit(HTTP_BAD_REQUEST);
1579 } 1585 }
1580 url = alloca(strlen(iobuf) + sizeof("/index.html")); 1586 url = alloca(strlen(iobuf) + sizeof("/index.html"));
1581 if (url == NULL) { 1587 if (url == NULL) {
1582 sendHeaders(HTTP_INTERNAL_SERVER_ERROR); 1588 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
1583 break;
1584 } 1589 }
1585 strcpy(url, iobuf); 1590 strcpy(url, iobuf);
1586 /* extract url args if present */ 1591 /* extract url args if present */
@@ -1593,11 +1598,10 @@ static void handle_incoming_and_exit(void)
1593 1598
1594 test = decodeString(url, 0); 1599 test = decodeString(url, 0);
1595 if (test == NULL) 1600 if (test == NULL)
1596 goto BAD_REQUEST; 1601 send_headers_and_exit(HTTP_BAD_REQUEST);
1597 if (test == url+1) { 1602 if (test == url + 1) {
1598 /* '/' or NUL is encoded */ 1603 /* '/' or NUL is encoded */
1599 sendHeaders(HTTP_NOT_FOUND); 1604 send_headers_and_exit(HTTP_NOT_FOUND);
1600 break;
1601 } 1605 }
1602 1606
1603 /* algorithm stolen from libbb bb_simplify_path(), 1607 /* algorithm stolen from libbb bb_simplify_path(),
@@ -1619,7 +1623,7 @@ static void handle_incoming_and_exit(void)
1619 ++test; 1623 ++test;
1620 if (purl == url) { 1624 if (purl == url) {
1621 /* protect root */ 1625 /* protect root */
1622 goto BAD_REQUEST; 1626 send_headers_and_exit(HTTP_BAD_REQUEST);
1623 } 1627 }
1624 while (*--purl != '/') /* omit previous dir */; 1628 while (*--purl != '/') /* omit previous dir */;
1625 continue; 1629 continue;
@@ -1668,7 +1672,7 @@ static void handle_incoming_and_exit(void)
1668 if (prequest != request_GET) { 1672 if (prequest != request_GET) {
1669 test = iobuf + sizeof("Content-length:") - 1; 1673 test = iobuf + sizeof("Content-length:") - 1;
1670 if (!test[0]) 1674 if (!test[0])
1671 goto bail_out; 1675 _exit(0);
1672 errno = 0; 1676 errno = 0;
1673 /* not using strtoul: it ignores leading minus! */ 1677 /* not using strtoul: it ignores leading minus! */
1674 length = strtol(test, &test, 10); 1678 length = strtol(test, &test, 10);
@@ -1676,7 +1680,7 @@ static void handle_incoming_and_exit(void)
1676 /* so we check for negative or too large values in one go: */ 1680 /* so we check for negative or too large values in one go: */
1677 /* (long -> ulong conv caused negatives to be seen as > INT_MAX) */ 1681 /* (long -> ulong conv caused negatives to be seen as > INT_MAX) */
1678 if (test[0] || errno || length > INT_MAX) 1682 if (test[0] || errno || length > INT_MAX)
1679 goto bail_out; 1683 _exit(0);
1680 } 1684 }
1681 } else if (STRNCASECMP(iobuf, "Cookie:") == 0) { 1685 } else if (STRNCASECMP(iobuf, "Cookie:") == 0) {
1682 cookie = strdup(skip_whitespace(iobuf + sizeof("Cookie:")-1)); 1686 cookie = strdup(skip_whitespace(iobuf + sizeof("Cookie:")-1));
@@ -1706,38 +1710,30 @@ static void handle_incoming_and_exit(void)
1706 } /* while extra header reading */ 1710 } /* while extra header reading */
1707 } 1711 }
1708 alarm(0); 1712 alarm(0);
1709 if (alarm_signaled)
1710 break;
1711 1713
1712 if (strcmp(bb_basename(url), httpd_conf) == 0 || ip_allowed == 0) { 1714 if (strcmp(bb_basename(url), httpd_conf) == 0 || ip_allowed == 0) {
1713 /* protect listing [/path]/httpd_conf or IP deny */ 1715 /* protect listing [/path]/httpd_conf or IP deny */
1714#if ENABLE_FEATURE_HTTPD_CGI 1716 send_headers_and_exit(HTTP_FORBIDDEN);
1715 FORBIDDEN: /* protect listing /cgi-bin */
1716#endif
1717 sendHeaders(HTTP_FORBIDDEN);
1718 break;
1719 } 1717 }
1720 1718
1721#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1719#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
1722 if (credentials <= 0 && checkPerm(url, ":") == 0) { 1720 if (credentials <= 0 && checkPerm(url, ":") == 0) {
1723 sendHeaders(HTTP_UNAUTHORIZED); 1721 send_headers_and_exit(HTTP_UNAUTHORIZED);
1724 break;
1725 } 1722 }
1726#endif 1723#endif
1727 1724
1728 if (found_moved_temporarily) { 1725 if (found_moved_temporarily) {
1729 sendHeaders(HTTP_MOVED_TEMPORARILY); 1726 send_headers_and_exit(HTTP_MOVED_TEMPORARILY);
1730 /* clear unforked memory flag */
1731 found_moved_temporarily = NULL;
1732 break;
1733 } 1727 }
1734 1728
1735 test = url + 1; /* skip first '/' */ 1729 test = url + 1; /* skip first '/' */
1736 1730
1737#if ENABLE_FEATURE_HTTPD_CGI 1731#if ENABLE_FEATURE_HTTPD_CGI
1738 if (strncmp(test, "cgi-bin", 7) == 0) { 1732 if (strncmp(test, "cgi-bin", 7) == 0) {
1739 if (test[7] == '/' && test[8] == '\0') 1733 if (test[7] == '/' && test[8] == '\0') {
1740 goto FORBIDDEN; /* protect listing cgi-bin/ */ 1734 /* protect listing cgi-bin/ */
1735 send_headers_and_exit(HTTP_FORBIDDEN);
1736 }
1741 send_cgi_and_exit(url, prequest, length, cookie, content_type); 1737 send_cgi_and_exit(url, prequest, length, cookie, content_type);
1742 } 1738 }
1743#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1739#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
@@ -1754,8 +1750,7 @@ static void handle_incoming_and_exit(void)
1754 } 1750 }
1755#endif 1751#endif
1756 if (prequest != request_GET) { 1752 if (prequest != request_GET) {
1757 sendHeaders(HTTP_NOT_IMPLEMENTED); 1753 send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
1758 break;
1759 } 1754 }
1760#endif /* FEATURE_HTTPD_CGI */ 1755#endif /* FEATURE_HTTPD_CGI */
1761 if (purl[-1] == '/') 1756 if (purl[-1] == '/')
@@ -1779,10 +1774,6 @@ static void handle_incoming_and_exit(void)
1779 send_file_and_exit(test); 1774 send_file_and_exit(test);
1780 } while (0); 1775 } while (0);
1781 1776
1782#if ENABLE_FEATURE_HTTPD_CGI
1783 bail_out:
1784#endif
1785
1786 _exit(0); 1777 _exit(0);
1787 1778
1788#if 0 /* Is this needed? Why? */ 1779#if 0 /* Is this needed? Why? */
@@ -1826,55 +1817,31 @@ static void handle_incoming_and_exit(void)
1826static void mini_httpd(int server) ATTRIBUTE_NORETURN; 1817static void mini_httpd(int server) ATTRIBUTE_NORETURN;
1827static void mini_httpd(int server) 1818static void mini_httpd(int server)
1828{ 1819{
1829// TODO: use accept WITHOUT select, it will just block there
1830 fd_set readfd, portfd;
1831
1832 FD_ZERO(&portfd);
1833 FD_SET(server, &portfd);
1834
1835 /* copy the ports we are watching to the readfd set */ 1820 /* copy the ports we are watching to the readfd set */
1836 while (1) { 1821 while (1) {
1837 int s; 1822 int n;
1838 union { 1823 len_and_sockaddr fromAddr;
1839 struct sockaddr sa; 1824
1840 struct sockaddr_in sin; 1825 /* Wait for connections... */
1841 USE_FEATURE_IPV6(struct sockaddr_in6 sin6;) 1826 fromAddr.len = LSA_SIZEOF_SA;
1842 } fromAddr; 1827 n = accept(server, &fromAddr.sa, &fromAddr.len);
1843// TODO: this looks like lsa to me 1828
1844 socklen_t fromAddrLen = sizeof(fromAddr); 1829 if (n < 0)
1845
1846 /* Now wait INDEFINITELY on the set of sockets */
1847 readfd = portfd;
1848 if (select(server + 1, &readfd, 0, 0, 0) <= 0)
1849 continue; 1830 continue;
1850 if (!FD_ISSET(server, &readfd)) 1831 /* set the KEEPALIVE option to cull dead connections */
1851 continue; 1832 setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
1852 s = accept(server, &fromAddr.sa, &fromAddrLen); 1833 accepted_socket = n;
1853 if (s < 0) 1834
1854 continue; 1835 n = get_nport(&fromAddr.sa);
1855 accepted_socket = s; 1836 tcp_port = ntohs(n);
1856 rmt_ip = 0; 1837 rmt_ip = 0;
1857 tcp_port = 0;
1858 if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
1859 free(rmt_ip_str);
1860 rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddrLen);
1861 if (DEBUG)
1862 bb_error_msg("connection from '%s'", rmt_ip_str);
1863 }
1864 if (fromAddr.sa.sa_family == AF_INET) { 1838 if (fromAddr.sa.sa_family == AF_INET) {
1865 rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); 1839 rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
1866// TODO: use get_nport?
1867 tcp_port = ntohs(fromAddr.sin.sin_port);
1868 } 1840 }
1869#if ENABLE_FEATURE_IPV6 1841 if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
1870 if (fromAddr.sa.sa_family == AF_INET6) { 1842 free(rmt_ip_str);
1871 //rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); 1843 rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddr.len);
1872 tcp_port = ntohs(fromAddr.sin6.sin6_port);
1873 } 1844 }
1874#endif
1875
1876 /* set the KEEPALIVE option to cull dead connections */
1877 setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
1878 1845
1879 if (fork() == 0) { 1846 if (fork() == 0) {
1880 /* child */ 1847 /* child */
@@ -1885,10 +1852,13 @@ static void mini_httpd(int server)
1885 if (verbose) { 1852 if (verbose) {
1886 /* this trick makes -v logging much simpler */ 1853 /* this trick makes -v logging much simpler */
1887 applet_name = rmt_ip_str; 1854 applet_name = rmt_ip_str;
1855 if (verbose > 2)
1856 bb_error_msg("connected");
1888 } 1857 }
1889 handle_incoming_and_exit(); 1858 handle_incoming_and_exit();
1890 } 1859 }
1891 close(s); 1860 /* parent, or fork failed */
1861 close(accepted_socket);
1892 } /* while (1) */ 1862 } /* while (1) */
1893 /* never reached */ 1863 /* never reached */
1894} 1864}
@@ -1898,31 +1868,20 @@ static void mini_httpd(int server)
1898static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN; 1868static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN;
1899static void mini_httpd_inetd(void) 1869static void mini_httpd_inetd(void)
1900{ 1870{
1901 union { 1871 int n;
1902 struct sockaddr sa; 1872 len_and_sockaddr fromAddr;
1903 struct sockaddr_in sin; 1873
1904 USE_FEATURE_IPV6(struct sockaddr_in6 sin6;) 1874 fromAddr.len = LSA_SIZEOF_SA;
1905 } fromAddr; 1875 getpeername(0, &fromAddr.sa, &fromAddr.len);
1906// TODO: this looks like lsa to me 1876 n = get_nport(&fromAddr.sa);
1907 socklen_t fromAddrLen = sizeof(fromAddr); 1877 tcp_port = ntohs(n);
1908
1909 getpeername(0, &fromAddr.sa, &fromAddrLen);
1910 rmt_ip = 0; 1878 rmt_ip = 0;
1911 tcp_port = 0;
1912 if (verbose || ENABLE_FEATURE_HTTPD_CGI || DEBUG) {
1913 free(rmt_ip_str);
1914 rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddrLen);
1915 }
1916 if (fromAddr.sa.sa_family == AF_INET) { 1879 if (fromAddr.sa.sa_family == AF_INET) {
1917 rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); 1880 rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
1918 tcp_port = ntohs(fromAddr.sin.sin_port);
1919 } 1881 }
1920#if ENABLE_FEATURE_IPV6 1882 if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
1921 if (fromAddr.sa.sa_family == AF_INET6) { 1883 rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddr.len);
1922 //rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
1923 tcp_port = ntohs(fromAddr.sin6.sin6_port);
1924 } 1884 }
1925#endif
1926 handle_incoming_and_exit(); 1885 handle_incoming_and_exit();
1927} 1886}
1928 1887