aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-08-17 19:20:07 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-08-17 19:20:07 +0000
commit073214f89409a8b2a01bae70f7ce699944b2a3be (patch)
tree8a8ed39b502c8a67612790274300a3edb6c8f9ab
parent91adf7d5877ecc7587556b993808b63f6f249080 (diff)
downloadbusybox-w32-073214f89409a8b2a01bae70f7ce699944b2a3be.tar.gz
busybox-w32-073214f89409a8b2a01bae70f7ce699944b2a3be.tar.bz2
busybox-w32-073214f89409a8b2a01bae70f7ce699944b2a3be.zip
httpd shrink and logging update, part 5 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.c412
1 files changed, 198 insertions, 214 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index 69d994a47..81660b2e6 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -20,7 +20,7 @@
20 * httpd -p 80 -u 80 -h /www -c /etc/httpd.conf -r "Web Server Authentication" 20 * httpd -p 80 -u 80 -h /www -c /etc/httpd.conf -r "Web Server Authentication"
21 * 21 *
22 * 22 *
23 * When a url contains "cgi-bin" it is assumed to be a cgi script. The 23 * When a url starts by "/cgi-bin/" it is assumed to be a cgi script. The
24 * server changes directory to the location of the script and executes it 24 * server changes directory to the location of the script and executes it
25 * after setting QUERY_STRING and other environment variables. 25 * after setting QUERY_STRING and other environment variables.
26 * 26 *
@@ -89,44 +89,45 @@
89 * root configuration file. If -c is set and the file is not found, the 89 * root configuration file. If -c is set and the file is not found, the
90 * server exits with an error. 90 * server exits with an error.
91 * 91 *
92*/ 92 */
93 93
94#include "libbb.h" 94#include "libbb.h"
95#if ENABLE_FEATURE_HTTPD_USE_SENDFILE 95#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
96#include <sys/sendfile.h> 96#include <sys/sendfile.h>
97#endif 97#endif
98 98
99//#define DEBUG 1
100#define DEBUG 0
101
99/* amount of buffering in a pipe */ 102/* amount of buffering in a pipe */
100#ifndef PIPE_BUF 103#ifndef PIPE_BUF
101# define PIPE_BUF 4096 104# define PIPE_BUF 4096
102#endif 105#endif
103 106
104static const char default_path_httpd_conf[] ALIGN1 = "/etc"; 107#define MAX_MEMORY_BUF 8192 /* IO buffer */
105static const char httpd_conf[] ALIGN1 = "httpd.conf";
106
107#define TIMEOUT 60
108 108
109// Note: busybox xfuncs are not used because we want the server to keep running 109#define HEADER_READ_TIMEOUT 60
110// if something bad happens due to a malformed user request.
111// As a result, all memory allocations after daemonize
112// are checked rigorously
113 110
114//#define DEBUG 1 111static const char default_path_httpd_conf[] ALIGN1 = "/etc";
115#define DEBUG 0 112static const char httpd_conf[] ALIGN1 = "httpd.conf";
116 113
117#define MAX_MEMORY_BUF 8192 /* IO buffer */ 114typedef struct has_next_ptr {
115 struct has_next_ptr *next;
116} has_next_ptr;
118 117
118/* Must have "next" as a first member */
119typedef struct Htaccess { 119typedef struct Htaccess {
120 char *after_colon;
121 struct Htaccess *next; 120 struct Htaccess *next;
121 char *after_colon;
122 char before_colon[1]; /* really bigger, must be last */ 122 char before_colon[1]; /* really bigger, must be last */
123} Htaccess; 123} Htaccess;
124 124
125/* Must have "next" as a first member */
125typedef struct Htaccess_IP { 126typedef struct Htaccess_IP {
127 struct Htaccess_IP *next;
126 unsigned ip; 128 unsigned ip;
127 unsigned mask; 129 unsigned mask;
128 int allow_deny; 130 int allow_deny;
129 struct Htaccess_IP *next;
130} Htaccess_IP; 131} Htaccess_IP;
131 132
132struct globals { 133struct globals {
@@ -199,30 +200,6 @@ struct globals {
199 ContentLength = -1; \ 200 ContentLength = -1; \
200} while (0) 201} while (0)
201 202
202static const char request_GET[] ALIGN1 = "GET"; /* size algorithmic optimize */
203
204static const char *const suffixTable[] = {
205/* Warning: shorter equivalent suffix in one line must be first */
206 ".htm.html", "text/html",
207 ".jpg.jpeg", "image/jpeg",
208 ".gif", "image/gif",
209 ".png", "image/png",
210 ".txt.h.c.cc.cpp", "text/plain",
211 ".css", "text/css",
212 ".wav", "audio/wav",
213 ".avi", "video/x-msvideo",
214 ".qt.mov", "video/quicktime",
215 ".mpe.mpeg", "video/mpeg",
216 ".mid.midi", "audio/midi",
217 ".mp3", "audio/mpeg",
218#if 0 /* unpopular */
219 ".au", "audio/basic",
220 ".pac", "application/x-ns-proxy-autoconfig",
221 ".vrml.wrl", "model/vrml",
222#endif
223 0, "application/octet-stream" /* default */
224};
225
226typedef enum { 203typedef enum {
227 HTTP_OK = 200, 204 HTTP_OK = 200,
228 HTTP_MOVED_TEMPORARILY = 302, 205 HTTP_MOVED_TEMPORARILY = 302,
@@ -285,11 +262,32 @@ static const HttpEnumString httpResponseNames[] = {
285}; 262};
286 263
287 264
288static const char RFC1123FMT[] ALIGN1 = "%a, %d %b %Y %H:%M:%S GMT"; 265#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1)
289 266
267static void free_llist(has_next_ptr **pptr)
268{
269 has_next_ptr *cur = *pptr;
270 while (cur) {
271 has_next_ptr *t = cur;
272 cur = cur->next;
273 free(t);
274 }
275 *pptr = NULL;
276}
290 277
291#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1) 278#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
279 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
280 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
281static ALWAYS_INLINE void free_Htaccess_list(Htaccess **pptr)
282{
283 free_llist((has_next_ptr**)pptr);
284}
285#endif
292 286
287static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr)
288{
289 free_llist((has_next_ptr**)pptr);
290}
293 291
294static int scan_ip(const char **ep, unsigned *ip, unsigned char endc) 292static int scan_ip(const char **ep, unsigned *ip, unsigned char endc)
295{ 293{
@@ -365,33 +363,8 @@ static int scan_ip_mask(const char *ipm, unsigned *ip, unsigned *mask)
365 return 0; 363 return 0;
366} 364}
367 365
368#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ 366/*
369 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ 367 * Parse configuration file into in-memory linked list.
370 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
371static void free_config_lines(Htaccess **pprev)
372{
373 Htaccess *prev = *pprev;
374
375 while (prev) {
376 Htaccess *cur = prev;
377
378 prev = cur->next;
379 free(cur);
380 }
381 *pprev = NULL;
382}
383#endif
384
385/* flag */
386#define FIRST_PARSE 0
387#define SUBDIR_PARSE 1
388#define SIGNALED_PARSE 2
389#define FIND_FROM_HTTPD_ROOT 3
390/****************************************************************************
391 *
392 > $Function: parse_conf()
393 *
394 * $Description: parse configuration file into in-memory linked list.
395 * 368 *
396 * The first non-white character is examined to determine if the config line 369 * The first non-white character is examined to determine if the config line
397 * is one of the following: 370 * is one of the following:
@@ -404,14 +377,14 @@ static void free_config_lines(Htaccess **pprev)
404 * are also discarded. That is, previous settings are retained if flag is 377 * are also discarded. That is, previous settings are retained if flag is
405 * SUBDIR_PARSE. 378 * SUBDIR_PARSE.
406 * 379 *
407 * $Parameters: 380 * path Path where to look for httpd.conf (without filename).
408 * (const char *) path . . null for ip address checks, path for password 381 * flag Type of the parse request.
409 * checks. 382 */
410 * (int) flag . . . . . . the source of the parse request. 383/* flag */
411 * 384#define FIRST_PARSE 0
412 * $Return: (None) 385#define SUBDIR_PARSE 1
413 * 386#define SIGNALED_PARSE 2
414 ****************************************************************************/ 387#define FIND_FROM_HTTPD_ROOT 3
415static void parse_conf(const char *path, int flag) 388static void parse_conf(const char *path, int flag)
416{ 389{
417 FILE *f; 390 FILE *f;
@@ -423,38 +396,28 @@ static void parse_conf(const char *path, int flag)
423 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 396 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
424 Htaccess *cur; 397 Htaccess *cur;
425#endif 398#endif
426
427 const char *cf = configFile; 399 const char *cf = configFile;
428 char buf[160]; 400 char buf[160];
429 char *p0 = NULL; 401 char *p0 = NULL;
430 char *c, *p; 402 char *c, *p;
403 Htaccess_IP *pip;
431 404
432 /* free previous ip setup if present */ 405 /* discard old rules */
433 Htaccess_IP *pip = ip_a_d; 406 free_Htaccess_IP_list(&ip_a_d);
434
435 while (pip) {
436 Htaccess_IP *cur_ipl = pip;
437
438 pip = cur_ipl->next;
439 free(cur_ipl);
440 }
441 ip_a_d = NULL;
442
443 flg_deny_all = 0; 407 flg_deny_all = 0;
444
445#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ 408#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
446 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ 409 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
447 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 410 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
448 /* retain previous auth and mime config only for subdir parse */ 411 /* retain previous auth and mime config only for subdir parse */
449 if (flag != SUBDIR_PARSE) { 412 if (flag != SUBDIR_PARSE) {
450#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 413#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
451 free_config_lines(&g_auth); 414 free_Htaccess_list(&g_auth);
452#endif 415#endif
453#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 416#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
454 free_config_lines(&mime_a); 417 free_Htaccess_list(&mime_a);
455#endif 418#endif
456#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 419#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
457 free_config_lines(&script_i); 420 free_Htaccess_list(&script_i);
458#endif 421#endif
459 } 422 }
460#endif 423#endif
@@ -463,7 +426,7 @@ static void parse_conf(const char *path, int flag)
463 cf = alloca(strlen(path) + sizeof(httpd_conf) + 2); 426 cf = alloca(strlen(path) + sizeof(httpd_conf) + 2);
464 if (cf == NULL) { 427 if (cf == NULL) {
465 if (flag == FIRST_PARSE) 428 if (flag == FIRST_PARSE)
466 bb_error_msg_and_die(bb_msg_memory_exhausted); 429 bb_error_msg_and_die(bb_msg_memory_exhausted);
467 return; 430 return;
468 } 431 }
469 sprintf((char *)cf, "%s/%s", path, httpd_conf); 432 sprintf((char *)cf, "%s/%s", path, httpd_conf);
@@ -486,21 +449,21 @@ static void parse_conf(const char *path, int flag)
486 /* This could stand some work */ 449 /* This could stand some work */
487 while ((p0 = fgets(buf, sizeof(buf), f)) != NULL) { 450 while ((p0 = fgets(buf, sizeof(buf), f)) != NULL) {
488 c = NULL; 451 c = NULL;
489 for (p = p0; *p0 != 0 && *p0 != '#'; p0++) { 452 for (p = p0; *p0 != '\0' && *p0 != '#'; p0++) {
490 if (!isspace(*p0)) { 453 if (!isspace(*p0)) {
491 *p++ = *p0; 454 *p++ = *p0;
492 if (*p0 == ':' && c == NULL) 455 if (*p0 == ':' && c == NULL)
493 c = p; 456 c = p;
494 } 457 }
495 } 458 }
496 *p = 0; 459 *p = '\0';
497 460
498 /* test for empty or strange line */ 461 /* test for empty or strange line */
499 if (c == NULL || *c == 0) 462 if (c == NULL || *c == '\0')
500 continue; 463 continue;
501 p0 = buf; 464 p0 = buf;
502 if (*p0 == 'd') 465 if (*p0 == 'd')
503 *p0 = 'D'; 466 *p0 = 'D';
504 if (*c == '*') { 467 if (*c == '*') {
505 if (*p0 == 'D') { 468 if (*p0 == 'D') {
506 /* memorize deny all */ 469 /* memorize deny all */
@@ -535,7 +498,7 @@ static void parse_conf(const char *path, int flag)
535 } 498 }
536 pip->allow_deny = *p0; 499 pip->allow_deny = *p0;
537 if (*p0 == 'D') { 500 if (*p0 == 'D') {
538 /* Deny:form_IP move top */ 501 /* Deny:from_IP move top */
539 pip->next = ip_a_d; 502 pip->next = ip_a_d;
540 ip_a_d = pip; 503 ip_a_d = pip;
541 } else { 504 } else {
@@ -555,12 +518,12 @@ static void parse_conf(const char *path, int flag)
555 } 518 }
556#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 519#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
557 if (*p0 == '/') { 520 if (*p0 == '/') {
558 /* make full path from httpd root / curent_path / config_line_path */ 521 /* make full path from httpd root / current_path / config_line_path */
559 cf = flag == SUBDIR_PARSE ? path : ""; 522 cf = (flag == SUBDIR_PARSE ? path : "");
560 p0 = malloc(strlen(cf) + (c - buf) + 2 + strlen(c)); 523 p0 = malloc(strlen(cf) + (c - buf) + 2 + strlen(c));
561 if (p0 == NULL) 524 if (p0 == NULL)
562 continue; 525 continue;
563 c[-1] = 0; 526 c[-1] = '\0';
564 sprintf(p0, "/%s%s", cf, buf); 527 sprintf(p0, "/%s%s", cf, buf);
565 528
566 /* another call bb_simplify_path */ 529 /* another call bb_simplify_path */
@@ -571,9 +534,9 @@ static void parse_conf(const char *path, int flag)
571 if (*cf == '/') { /* skip duplicate (or initial) slash */ 534 if (*cf == '/') { /* skip duplicate (or initial) slash */
572 continue; 535 continue;
573 } else if (*cf == '.') { 536 } else if (*cf == '.') {
574 if (cf[1] == '/' || cf[1] == 0) { /* remove extra '.' */ 537 if (cf[1] == '/' || cf[1] == '\0') { /* remove extra '.' */
575 continue; 538 continue;
576 } else if ((cf[1] == '.') && (cf[2] == '/' || cf[2] == 0)) { 539 } else if ((cf[1] == '.') && (cf[2] == '/' || cf[2] == '\0')) {
577 ++cf; 540 ++cf;
578 if (p > p0) { 541 if (p > p0) {
579 while (*--p != '/') /* omit previous dir */; 542 while (*--p != '/') /* omit previous dir */;
@@ -588,7 +551,7 @@ static void parse_conf(const char *path, int flag)
588 if ((p == p0) || (*p != '/')) { /* not a trailing slash */ 551 if ((p == p0) || (*p != '/')) { /* not a trailing slash */
589 ++p; /* so keep last character */ 552 ++p; /* so keep last character */
590 } 553 }
591 *p = 0; 554 *p = '\0';
592 sprintf(p0, "%s:%s", p0, c); 555 sprintf(p0, "%s:%s", p0, c);
593 } 556 }
594#endif 557#endif
@@ -658,23 +621,14 @@ static void parse_conf(const char *path, int flag)
658} 621}
659 622
660#if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR 623#if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR
661/**************************************************************************** 624/*
662 * 625 * Given a string, html-encode special characters.
663 > $Function: encodeString() 626 * This is used for the -e command line option to provide an easy way
664 * 627 * for scripts to encode result data without confusing browsers. The
665 * $Description: Given a string, html encode special characters. 628 * returned string pointer is memory allocated by malloc().
666 * This is used for the -e command line option to provide an easy way
667 * for scripts to encode result data without confusing browsers. The
668 * returned string pointer is memory allocated by malloc().
669 *
670 * $Parameters:
671 * (const char *) string . . The first string to encode.
672 *
673 * $Return: (char *) . . . .. . . A pointer to the encoded string.
674 *
675 * $Errors: Returns a null string ("") if memory is not available.
676 * 629 *
677 ****************************************************************************/ 630 * Returns a pointer to the encoded string (malloced).
631 */
678static char *encodeString(const char *string) 632static char *encodeString(const char *string)
679{ 633{
680 /* take the simple route and encode everything */ 634 /* take the simple route and encode everything */
@@ -694,25 +648,18 @@ static char *encodeString(const char *string)
694} 648}
695#endif /* FEATURE_HTTPD_ENCODE_URL_STR */ 649#endif /* FEATURE_HTTPD_ENCODE_URL_STR */
696 650
697/**************************************************************************** 651/*
698 * 652 * Given a URL encoded string, convert it to plain ascii.
699 > $Function: decodeString() 653 * Since decoding always makes strings smaller, the decode is done in-place.
700 * 654 * Thus, callers should strdup() the argument if they do not want the
701 * $Description: Given a URL encoded string, convert it to plain ascii. 655 * argument modified. The return is the original pointer, allowing this
702 * Since decoding always makes strings smaller, the decode is done in-place. 656 * function to be easily used as arguments to other functions.
703 * Thus, callers should strdup() the argument if they do not want the
704 * argument modified. The return is the original pointer, allowing this
705 * function to be easily used as arguments to other functions.
706 *
707 * $Parameters:
708 * (char *) string . . . The first string to decode.
709 * (int) option_d . . 1 if called for httpd -d
710 *
711 * $Return: (char *) . . . . A pointer to the decoded string (same as input).
712 * 657 *
713 * $Errors: None 658 * string The first string to decode.
659 * option_d 1 if called for httpd -d
714 * 660 *
715 ****************************************************************************/ 661 * Returns a pointer to the decoded string (same as input).
662 */
716static char *decodeString(char *orig, int option_d) 663static char *decodeString(char *orig, int option_d)
717{ 664{
718 /* note that decoded string is always shorter than original */ 665 /* note that decoded string is always shorter than original */
@@ -754,9 +701,9 @@ static char *decodeString(char *orig, int option_d)
754 701
755 702
756#if ENABLE_FEATURE_HTTPD_CGI 703#if ENABLE_FEATURE_HTTPD_CGI
757/**************************************************************************** 704/*
758 * setenv helpers 705 * setenv helpers
759 ****************************************************************************/ 706 */
760static void setenv1(const char *name, const char *value) 707static void setenv1(const char *name, const char *value)
761{ 708{
762 if (!value) 709 if (!value)
@@ -773,10 +720,10 @@ static void setenv_long(const char *name, long value)
773 720
774#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 721#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
775/* 722/*
776 * Decode a base 64 data stream as per rfc1521. 723 * Decode a base64 data stream as per rfc1521.
777 * Note that the rfc states that non base64 chars are to be ignored. 724 * Note that the rfc states that non base64 chars are to be ignored.
778 * Since the decode always results in a shorter size than the input, it is 725 * Since the decode always results in a shorter size than the input,
779 * OK to pass the input arg as an output arg. 726 * it is OK to pass the input arg as an output arg.
780 * Parameter: a pointer to a base64 encoded string. 727 * Parameter: a pointer to a base64 encoded string.
781 * Decoded data is stored in-place. 728 * Decoded data is stored in-place.
782 */ 729 */
@@ -818,18 +765,9 @@ static void decodeBase64(char *Data)
818} 765}
819#endif 766#endif
820 767
821 768/*
822/**************************************************************************** 769 * Create a listen server socket on the designated port.
823 * 770 */
824 > $Function: openServer()
825 *
826 * $Description: create a listen server socket on the designated port.
827 *
828 * $Return: (int) . . . A connection socket. -1 for errors.
829 *
830 * $Errors: None
831 *
832 ****************************************************************************/
833#if BB_MMU 771#if BB_MMU
834static int openServer(void) 772static int openServer(void)
835{ 773{
@@ -853,6 +791,8 @@ static int openServer(void)
853 */ 791 */
854static int sendHeaders(HttpResponseNum responseNum) 792static int sendHeaders(HttpResponseNum responseNum)
855{ 793{
794 static const char RFC1123FMT[] ALIGN1 = "%a, %d %b %Y %H:%M:%S GMT";
795
856 const char *responseString = ""; 796 const char *responseString = "";
857 const char *infoString = NULL; 797 const char *infoString = NULL;
858 const char *mime_type; 798 const char *mime_type;
@@ -1318,6 +1258,28 @@ static void send_cgi_and_exit(
1318static void send_file_and_exit(const char *url) ATTRIBUTE_NORETURN; 1258static void send_file_and_exit(const char *url) ATTRIBUTE_NORETURN;
1319static void send_file_and_exit(const char *url) 1259static void send_file_and_exit(const char *url)
1320{ 1260{
1261 static const char *const suffixTable[] = {
1262 /* Warning: shorter equivalent suffix in one line must be first */
1263 ".htm.html", "text/html",
1264 ".jpg.jpeg", "image/jpeg",
1265 ".gif", "image/gif",
1266 ".png", "image/png",
1267 ".txt.h.c.cc.cpp", "text/plain",
1268 ".css", "text/css",
1269 ".wav", "audio/wav",
1270 ".avi", "video/x-msvideo",
1271 ".qt.mov", "video/quicktime",
1272 ".mpe.mpeg", "video/mpeg",
1273 ".mid.midi", "audio/midi",
1274 ".mp3", "audio/mpeg",
1275#if 0 /* unpopular */
1276 ".au", "audio/basic",
1277 ".pac", "application/x-ns-proxy-autoconfig",
1278 ".vrml.wrl", "model/vrml",
1279#endif
1280 NULL
1281 };
1282
1321 char *suffix; 1283 char *suffix;
1322 int f; 1284 int f;
1323 int fd; 1285 int fd;
@@ -1330,25 +1292,31 @@ static void send_file_and_exit(const char *url)
1330 1292
1331 suffix = strrchr(url, '.'); 1293 suffix = strrchr(url, '.');
1332 1294
1333 for (table = suffixTable; *table; table += 2) 1295 /* If not found, set default as "application/octet-stream"; */
1334 if (suffix != NULL && (try_suffix = strstr(*table, suffix)) != 0) { 1296 found_mime_type = "application/octet-stream";
1335 try_suffix += strlen(suffix); 1297 if (suffix) {
1336 if (*try_suffix == 0 || *try_suffix == '.') 1298#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
1337 break; 1299 Htaccess *cur;
1300#endif
1301 for (table = suffixTable; *table; table += 2) {
1302 try_suffix = strstr(table[0], suffix);
1303 if (try_suffix) {
1304 try_suffix += strlen(suffix);
1305 if (*try_suffix == '\0' || *try_suffix == '.') {
1306 found_mime_type = table[1];
1307 break;
1308 }
1309 }
1338 } 1310 }
1339 /* also, if not found, set default as "application/octet-stream"; */
1340 found_mime_type = table[1];
1341#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 1311#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
1342 if (suffix) {
1343 Htaccess * cur;
1344 for (cur = mime_a; cur; cur = cur->next) { 1312 for (cur = mime_a; cur; cur = cur->next) {
1345 if (strcmp(cur->before_colon, suffix) == 0) { 1313 if (strcmp(cur->before_colon, suffix) == 0) {
1346 found_mime_type = cur->after_colon; 1314 found_mime_type = cur->after_colon;
1347 break; 1315 break;
1348 } 1316 }
1349 } 1317 }
1318#endif
1350 } 1319 }
1351#endif /* FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES */
1352 1320
1353 if (DEBUG) 1321 if (DEBUG)
1354 bb_error_msg("sending file '%s' content-type: %s", 1322 bb_error_msg("sending file '%s' content-type: %s",
@@ -1426,27 +1394,21 @@ static int checkPermIP(void)
1426 return !flg_deny_all; 1394 return !flg_deny_all;
1427} 1395}
1428 1396
1429/**************************************************************************** 1397/*
1430 * 1398 * Check the permission file for access password protected.
1431 > $Function: checkPerm()
1432 *
1433 * $Description: Check the permission file for access password protected.
1434 *
1435 * If config file isn't present, everything is allowed.
1436 * Entries are of the form you can see example from header source
1437 * 1399 *
1438 * $Parameters: 1400 * If config file isn't present, everything is allowed.
1439 * (const char *) path . . . . The file path. 1401 * Entries are of the form you can see example from header source
1440 * (const char *) request . . . User information to validate.
1441 * 1402 *
1442 * $Return: (int) . . . . . . . . . 1 if request OK, 0 otherwise. 1403 * path The file path.
1404 * request User information to validate.
1443 * 1405 *
1444 ****************************************************************************/ 1406 * Returns 1 if request is OK.
1445 1407 */
1446#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1408#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
1447static int checkPerm(const char *path, const char *request) 1409static int checkPerm(const char *path, const char *request)
1448{ 1410{
1449 Htaccess * cur; 1411 Htaccess *cur;
1450 const char *p; 1412 const char *p;
1451 const char *p0; 1413 const char *p0;
1452 1414
@@ -1481,7 +1443,7 @@ static int checkPerm(const char *path, const char *request)
1481 char *cipher; 1443 char *cipher;
1482 char *pp; 1444 char *pp;
1483 1445
1484 if (strncmp(p, request, u-request) != 0) { 1446 if (strncmp(p, request, u - request) != 0) {
1485 /* user uncompared */ 1447 /* user uncompared */
1486 continue; 1448 continue;
1487 } 1449 }
@@ -1528,15 +1490,17 @@ static void exit_on_signal(int sig)
1528static void handle_incoming_and_exit(void) ATTRIBUTE_NORETURN; 1490static void handle_incoming_and_exit(void) ATTRIBUTE_NORETURN;
1529static void handle_incoming_and_exit(void) 1491static void handle_incoming_and_exit(void)
1530{ 1492{
1493 static const char request_GET[] ALIGN1 = "GET";
1494
1531 char *url; 1495 char *url;
1532 char *purl; 1496 char *purl;
1533 int count; 1497 int count;
1534 int blank = -1; 1498 int http_major_version;
1535 char *test; 1499 char *test;
1536 struct stat sb; 1500 struct stat sb;
1537 int ip_allowed; 1501 int ip_allowed;
1538#if ENABLE_FEATURE_HTTPD_CGI 1502#if ENABLE_FEATURE_HTTPD_CGI
1539 const char *prequest = request_GET; 1503 const char *prequest;
1540 unsigned long length = 0; 1504 unsigned long length = 0;
1541 char *cookie = 0; 1505 char *cookie = 0;
1542 char *content_type = 0; 1506 char *content_type = 0;
@@ -1546,21 +1510,24 @@ static void handle_incoming_and_exit(void)
1546 int credentials = -1; /* if not required this is Ok */ 1510 int credentials = -1; /* if not required this is Ok */
1547#endif 1511#endif
1548 1512
1513 /* Install timeout handler */
1549 sa.sa_handler = exit_on_signal; 1514 sa.sa_handler = exit_on_signal;
1550 sigemptyset(&sa.sa_mask); 1515 sigemptyset(&sa.sa_mask);
1551 sa.sa_flags = 0; /* no SA_RESTART */ 1516 sa.sa_flags = 0; /* no SA_RESTART */
1552 sigaction(SIGALRM, &sa, NULL); 1517 sigaction(SIGALRM, &sa, NULL);
1518 alarm(HEADER_READ_TIMEOUT);
1553 1519
1554 alarm(TIMEOUT);
1555 if (!get_line()) 1520 if (!get_line())
1556 _exit(0); /* EOF or error or empty line */ 1521 _exit(0); /* EOF or error or empty line */
1557 1522
1523 /* Determine type of request (GET/POST) */
1558 purl = strpbrk(iobuf, " \t"); 1524 purl = strpbrk(iobuf, " \t");
1559 if (purl == NULL) { 1525 if (purl == NULL) {
1560 send_headers_and_exit(HTTP_BAD_REQUEST); 1526 send_headers_and_exit(HTTP_BAD_REQUEST);
1561 } 1527 }
1562 *purl = '\0'; 1528 *purl = '\0';
1563#if ENABLE_FEATURE_HTTPD_CGI 1529#if ENABLE_FEATURE_HTTPD_CGI
1530 prequest = request_GET;
1564 if (strcasecmp(iobuf, prequest) != 0) { 1531 if (strcasecmp(iobuf, prequest) != 0) {
1565 prequest = "POST"; 1532 prequest = "POST";
1566 if (strcasecmp(iobuf, prequest) != 0) { 1533 if (strcasecmp(iobuf, prequest) != 0) {
@@ -1573,8 +1540,10 @@ static void handle_incoming_and_exit(void)
1573 } 1540 }
1574#endif 1541#endif
1575 *purl = ' '; 1542 *purl = ' ';
1576 count = sscanf(purl, " %[^ ] HTTP/%d.%*d", iobuf, &blank);
1577 1543
1544 /* Copy URL from after "GET "/"POST " to stack-allocated char[] */
1545 http_major_version = -1;
1546 count = sscanf(purl, " %[^ ] HTTP/%d.%*d", iobuf, &http_major_version);
1578 if (count < 1 || iobuf[0] != '/') { 1547 if (count < 1 || iobuf[0] != '/') {
1579 /* Garbled request/URL */ 1548 /* Garbled request/URL */
1580 send_headers_and_exit(HTTP_BAD_REQUEST); 1549 send_headers_and_exit(HTTP_BAD_REQUEST);
@@ -1584,7 +1553,8 @@ static void handle_incoming_and_exit(void)
1584 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); 1553 send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
1585 } 1554 }
1586 strcpy(url, iobuf); 1555 strcpy(url, iobuf);
1587 /* extract url args if present */ 1556
1557 /* Extract url args if present */
1588 test = strchr(url, '?'); 1558 test = strchr(url, '?');
1589 g_query = NULL; 1559 g_query = NULL;
1590 if (test) { 1560 if (test) {
@@ -1592,6 +1562,7 @@ static void handle_incoming_and_exit(void)
1592 g_query = test; 1562 g_query = test;
1593 } 1563 }
1594 1564
1565 /* Decode URL escape sequences */
1595 test = decodeString(url, 0); 1566 test = decodeString(url, 0);
1596 if (test == NULL) 1567 if (test == NULL)
1597 send_headers_and_exit(HTTP_BAD_REQUEST); 1568 send_headers_and_exit(HTTP_BAD_REQUEST);
@@ -1600,7 +1571,8 @@ static void handle_incoming_and_exit(void)
1600 send_headers_and_exit(HTTP_NOT_FOUND); 1571 send_headers_and_exit(HTTP_NOT_FOUND);
1601 } 1572 }
1602 1573
1603 /* algorithm stolen from libbb bb_simplify_path(), 1574 /* Canonicalize path */
1575 /* Algorithm stolen from libbb bb_simplify_path(),
1604 * but don't strdup and reducing trailing slash and protect out root */ 1576 * but don't strdup and reducing trailing slash and protect out root */
1605 purl = test = url; 1577 purl = test = url;
1606 do { 1578 do {
@@ -1631,13 +1603,14 @@ static void handle_incoming_and_exit(void)
1631 *++purl = '\0'; /* so keep last character */ 1603 *++purl = '\0'; /* so keep last character */
1632 test = purl; /* end ptr */ 1604 test = purl; /* end ptr */
1633 1605
1634 /* If URL is directory, adding '/' */ 1606 /* If URL is a directory, add '/' */
1635 if (test[-1] != '/') { 1607 if (test[-1] != '/') {
1636 if (is_directory(url + 1, 1, &sb)) { 1608 if (is_directory(url + 1, 1, &sb)) {
1637 found_moved_temporarily = url; 1609 found_moved_temporarily = url;
1638 } 1610 }
1639 } 1611 }
1640 1612
1613 /* Log it */
1641 if (verbose > 1) 1614 if (verbose > 1)
1642 bb_error_msg("url:%s", url); 1615 bb_error_msg("url:%s", url);
1643 1616
@@ -1653,15 +1626,17 @@ static void handle_incoming_and_exit(void)
1653 } 1626 }
1654 *test = '/'; 1627 *test = '/';
1655 } 1628 }
1656 if (blank >= 0) { 1629 if (http_major_version >= 0) {
1657 /* read until blank line for HTTP version specified, else parse immediate */ 1630 /* Request was with "... HTTP/n.m", and n >= 0 */
1631
1632 /* Read until blank line for HTTP version specified, else parse immediate */
1658 while (1) { 1633 while (1) {
1659 alarm(TIMEOUT); 1634 alarm(HEADER_READ_TIMEOUT);
1660 if (!get_line()) 1635 if (!get_line())
1661 break; /* EOF or error or empty line */ 1636 break; /* EOF or error or empty line */
1662
1663 if (DEBUG) 1637 if (DEBUG)
1664 bb_error_msg("header: '%s'", iobuf); 1638 bb_error_msg("header: '%s'", iobuf);
1639
1665#if ENABLE_FEATURE_HTTPD_CGI 1640#if ENABLE_FEATURE_HTTPD_CGI
1666 /* try and do our best to parse more lines */ 1641 /* try and do our best to parse more lines */
1667 if ((STRNCASECMP(iobuf, "Content-length:") == 0)) { 1642 if ((STRNCASECMP(iobuf, "Content-length:") == 0)) {
@@ -1707,6 +1682,7 @@ static void handle_incoming_and_exit(void)
1707 } /* while extra header reading */ 1682 } /* while extra header reading */
1708 } 1683 }
1709 1684
1685 /* We read everything, disable peer timeout */
1710 alarm(0); 1686 alarm(0);
1711 1687
1712 if (strcmp(bb_basename(url), httpd_conf) == 0 || ip_allowed == 0) { 1688 if (strcmp(bb_basename(url), httpd_conf) == 0 || ip_allowed == 0) {
@@ -1727,9 +1703,9 @@ static void handle_incoming_and_exit(void)
1727 test = url + 1; /* skip first '/' */ 1703 test = url + 1; /* skip first '/' */
1728 1704
1729#if ENABLE_FEATURE_HTTPD_CGI 1705#if ENABLE_FEATURE_HTTPD_CGI
1730 if (strncmp(test, "cgi-bin", 7) == 0) { 1706 if (strncmp(test, "cgi-bin/", 8) == 0) {
1731 if (test[7] == '/' && test[8] == '\0') { 1707 if (test[8] == '\0') {
1732 /* protect listing cgi-bin/ */ 1708 /* protect listing "cgi-bin/" */
1733 send_headers_and_exit(HTTP_FORBIDDEN); 1709 send_headers_and_exit(HTTP_FORBIDDEN);
1734 } 1710 }
1735 send_cgi_and_exit(url, prequest, length, cookie, content_type); 1711 send_cgi_and_exit(url, prequest, length, cookie, content_type);
@@ -1768,7 +1744,11 @@ static void handle_incoming_and_exit(void)
1768 send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type); 1744 send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type);
1769 } 1745 }
1770 } 1746 }
1771#endif /* FEATURE_HTTPD_CGI */ 1747#endif
1748 /* else {
1749 * fall through to send_file, it errors out if open fails
1750 * }
1751 */
1772 1752
1773 send_file_and_exit(test); 1753 send_file_and_exit(test);
1774 1754
@@ -1813,6 +1793,11 @@ static void handle_incoming_and_exit(void)
1813static void mini_httpd(int server) ATTRIBUTE_NORETURN; 1793static void mini_httpd(int server) ATTRIBUTE_NORETURN;
1814static void mini_httpd(int server) 1794static void mini_httpd(int server)
1815{ 1795{
1796 /* NB: it's best to not use xfuncs in this loop before fork().
1797 * Otherwise server may die on transient errors (temporary
1798 * out-of-memory condition, etc), which is Bad(tm).
1799 * Try to do any dangerous calls after fork.
1800 */
1816 while (1) { 1801 while (1) {
1817 int n; 1802 int n;
1818 len_and_sockaddr fromAddr; 1803 len_and_sockaddr fromAddr;
@@ -1825,18 +1810,6 @@ static void mini_httpd(int server)
1825 continue; 1810 continue;
1826 /* set the KEEPALIVE option to cull dead connections */ 1811 /* set the KEEPALIVE option to cull dead connections */
1827 setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 1812 setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
1828 accepted_socket = n;
1829
1830 n = get_nport(&fromAddr.sa);
1831 tcp_port = ntohs(n);
1832 rmt_ip = 0;
1833 if (fromAddr.sa.sa_family == AF_INET) {
1834 rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
1835 }
1836 if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
1837 free(rmt_ip_str);
1838 rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddr.len);
1839 }
1840 1813
1841 if (fork() == 0) { 1814 if (fork() == 0) {
1842 /* child */ 1815 /* child */
@@ -1844,6 +1817,16 @@ static void mini_httpd(int server)
1844 /* Do not reload config on HUP */ 1817 /* Do not reload config on HUP */
1845 signal(SIGHUP, SIG_IGN); 1818 signal(SIGHUP, SIG_IGN);
1846#endif 1819#endif
1820 accepted_socket = n;
1821 n = get_nport(&fromAddr.sa);
1822 tcp_port = ntohs(n);
1823 rmt_ip = 0;
1824 if (fromAddr.sa.sa_family == AF_INET) {
1825 rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr);
1826 }
1827 if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
1828 rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddr.len);
1829 }
1847 if (verbose) { 1830 if (verbose) {
1848 /* this trick makes -v logging much simpler */ 1831 /* this trick makes -v logging much simpler */
1849 applet_name = rmt_ip_str; 1832 applet_name = rmt_ip_str;
@@ -1853,7 +1836,7 @@ static void mini_httpd(int server)
1853 handle_incoming_and_exit(); 1836 handle_incoming_and_exit();
1854 } 1837 }
1855 /* parent, or fork failed */ 1838 /* parent, or fork failed */
1856 close(accepted_socket); 1839 close(n);
1857 } /* while (1) */ 1840 } /* while (1) */
1858 /* never reached */ 1841 /* never reached */
1859} 1842}
@@ -1883,12 +1866,13 @@ static void mini_httpd_inetd(void)
1883#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 1866#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
1884static void sighup_handler(int sig) 1867static void sighup_handler(int sig)
1885{ 1868{
1886 /* set and reset */
1887 struct sigaction sa; 1869 struct sigaction sa;
1888 1870
1889 parse_conf(default_path_httpd_conf, sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE); 1871 parse_conf(default_path_httpd_conf, sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE);
1872
1873 memset(&sa, 0, sizeof(sa));
1890 sa.sa_handler = sighup_handler; 1874 sa.sa_handler = sighup_handler;
1891 sigemptyset(&sa.sa_mask); 1875 /*sigemptyset(&sa.sa_mask); - memset should be enough */
1892 sa.sa_flags = SA_RESTART; 1876 sa.sa_flags = SA_RESTART;
1893 sigaction(SIGHUP, &sa, NULL); 1877 sigaction(SIGHUP, &sa, NULL);
1894} 1878}
@@ -1930,12 +1914,13 @@ int httpd_main(int argc, char **argv)
1930 USE_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;) 1914 USE_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;)
1931 USE_FEATURE_HTTPD_AUTH_MD5(const char *pass;) 1915 USE_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
1932 1916
1917 INIT_G();
1918
1933#if ENABLE_LOCALE_SUPPORT 1919#if ENABLE_LOCALE_SUPPORT
1934 /* Undo busybox.c: we want to speak English in http (dates etc) */ 1920 /* Undo busybox.c: we want to speak English in http (dates etc) */
1935 setlocale(LC_TIME, "C"); 1921 setlocale(LC_TIME, "C");
1936#endif 1922#endif
1937 1923
1938 INIT_G();
1939 home_httpd = xrealloc_getcwd_or_warn(NULL); 1924 home_httpd = xrealloc_getcwd_or_warn(NULL);
1940 opt_complementary = "vv"; /* counter */ 1925 opt_complementary = "vv"; /* counter */
1941 /* We do not "absolutize" path given by -h (home) opt. 1926 /* We do not "absolutize" path given by -h (home) opt.
@@ -2012,13 +1997,12 @@ int httpd_main(int argc, char **argv)
2012 } 1997 }
2013#endif 1998#endif
2014 1999
2000#if BB_MMU
2015#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 2001#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
2016 sighup_handler(0); 2002 sighup_handler(0);
2017#else 2003#else
2018 parse_conf(default_path_httpd_conf, FIRST_PARSE); 2004 parse_conf(default_path_httpd_conf, FIRST_PARSE);
2019#endif 2005#endif
2020
2021#if BB_MMU
2022 if (opt & OPT_INETD) 2006 if (opt & OPT_INETD)
2023 mini_httpd_inetd(); 2007 mini_httpd_inetd();
2024 if (!(opt & OPT_FOREGROUND)) 2008 if (!(opt & OPT_FOREGROUND))