diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-08-17 19:19:15 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-08-17 19:19:15 +0000 |
commit | e45af73dc233d345a642386431703ad9a1597093 (patch) | |
tree | 15592222186556954d34603fbeb11e6fa4f7d2d9 | |
parent | 241b1567adfa481e9c160f24d4ea7ca29ca7dd3e (diff) | |
download | busybox-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.c | 255 |
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 | ||
921 | static void send_headers_and_exit(HttpResponseNum responseNum) ATTRIBUTE_NORETURN; | ||
922 | static 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) { |
1490 | set_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 | */ |
1508 | static void handle_sigalrm(int sig) | 1519 | static void exit_on_signal(int sig) ATTRIBUTE_NORETURN; |
1520 | static 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) | |||
1826 | static void mini_httpd(int server) ATTRIBUTE_NORETURN; | 1817 | static void mini_httpd(int server) ATTRIBUTE_NORETURN; |
1827 | static void mini_httpd(int server) | 1818 | static 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) | |||
1898 | static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN; | 1868 | static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN; |
1899 | static void mini_httpd_inetd(void) | 1869 | static 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 | ||