aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2004-10-08 08:03:29 +0000
committerEric Andersen <andersen@codepoet.org>2004-10-08 08:03:29 +0000
commit07f2fea62c38c3926d4dedd47b542bbb8059fcd4 (patch)
treebe98aa602575a4205a8bc3c2f0f62ebb7a2eaf03
parent9e954abc4f6b9c08fcd8b90f5ceaa465ecdfb38d (diff)
downloadbusybox-w32-07f2fea62c38c3926d4dedd47b542bbb8059fcd4.tar.gz
busybox-w32-07f2fea62c38c3926d4dedd47b542bbb8059fcd4.tar.bz2
busybox-w32-07f2fea62c38c3926d4dedd47b542bbb8059fcd4.zip
last_patch139.gz from Vladimir N. Oleynik:
>I also don't mean to disagree about leaving 30x status codes until after >1.0. In fact, although redirecting http://host/dir to http://host/dir/ >with a 301 is common practice (e.g. Apache, IIS), AFAIK it isn't >actually required (or mentioned) by the HTTP specs. Ok. Attached patch have 302 and 408 implemented features. --w vodz
-rw-r--r--networking/httpd.c114
1 files changed, 83 insertions, 31 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index ff093c5f1..83ded5330 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -2,7 +2,7 @@
2 * httpd implementation for busybox 2 * httpd implementation for busybox
3 * 3 *
4 * Copyright (C) 2002,2003 Glenn Engel <glenne@engel.org> 4 * Copyright (C) 2002,2003 Glenn Engel <glenne@engel.org>
5 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 5 * Copyright (C) 2003,2004 Vladimir Oleynik <dzo@simtreas.ru>
6 * 6 *
7 * simplify patch stolen from libbb without using strdup 7 * simplify patch stolen from libbb without using strdup
8 * 8 *
@@ -116,7 +116,7 @@
116#include "busybox.h" 116#include "busybox.h"
117 117
118 118
119static const char httpdVersion[] = "busybox httpd/1.34 2-Oct-2003"; 119static const char httpdVersion[] = "busybox httpd/1.35 6-Oct-2004";
120static const char default_path_httpd_conf[] = "/etc"; 120static const char default_path_httpd_conf[] = "/etc";
121static const char httpd_conf[] = "httpd.conf"; 121static const char httpd_conf[] = "httpd.conf";
122static const char home[] = "./"; 122static const char home[] = "./";
@@ -127,6 +127,8 @@ static const char home[] = "./";
127# define cont_l_fmt "%ld" 127# define cont_l_fmt "%ld"
128#endif 128#endif
129 129
130#define TIMEOUT 60
131
130// Note: busybox xfuncs are not used because we want the server to keep running 132// Note: busybox xfuncs are not used because we want the server to keep running
131// if something bad happens due to a malformed user request. 133// if something bad happens due to a malformed user request.
132// As a result, all memory allocation after daemonize 134// As a result, all memory allocation after daemonize
@@ -218,6 +220,8 @@ typedef struct
218 char *remoteuser; 220 char *remoteuser;
219#endif 221#endif
220 222
223 const char *query;
224
221#ifdef CONFIG_FEATURE_HTTPD_CGI 225#ifdef CONFIG_FEATURE_HTTPD_CGI
222 char *referer; 226 char *referer;
223#endif 227#endif
@@ -230,8 +234,11 @@ typedef struct
230#endif 234#endif
231 unsigned port; /* server initial port and for 235 unsigned port; /* server initial port and for
232 set env REMOTE_PORT */ 236 set env REMOTE_PORT */
237 union HTTPD_FOUND {
238 const char *found_mime_type;
239 const char *found_moved_temporarily;
240 } httpd_found;
233 241
234 const char *found_mime_type;
235 off_t ContentLength; /* -1 - unknown */ 242 off_t ContentLength; /* -1 - unknown */
236 time_t last_mod; 243 time_t last_mod;
237 244
@@ -253,6 +260,8 @@ typedef struct
253#define a_c_r 0 260#define a_c_r 0
254#define a_c_w 1 261#define a_c_w 1
255#endif 262#endif
263 volatile int alarm_signaled;
264
256} HttpdConfig; 265} HttpdConfig;
257 266
258static HttpdConfig *config; 267static HttpdConfig *config;
@@ -284,11 +293,13 @@ static const char* const suffixTable [] = {
284typedef enum 293typedef enum
285{ 294{
286 HTTP_OK = 200, 295 HTTP_OK = 200,
296 HTTP_MOVED_TEMPORARILY = 302,
297 HTTP_BAD_REQUEST = 400, /* malformed syntax */
287 HTTP_UNAUTHORIZED = 401, /* authentication needed, respond with auth hdr */ 298 HTTP_UNAUTHORIZED = 401, /* authentication needed, respond with auth hdr */
288 HTTP_NOT_FOUND = 404, 299 HTTP_NOT_FOUND = 404,
289 HTTP_NOT_IMPLEMENTED = 501, /* used for unrecognized requests */
290 HTTP_BAD_REQUEST = 400, /* malformed syntax */
291 HTTP_FORBIDDEN = 403, 300 HTTP_FORBIDDEN = 403,
301 HTTP_REQUEST_TIMEOUT = 408,
302 HTTP_NOT_IMPLEMENTED = 501, /* used for unrecognized requests */
292 HTTP_INTERNAL_SERVER_ERROR = 500, 303 HTTP_INTERNAL_SERVER_ERROR = 500,
293#if 0 /* future use */ 304#if 0 /* future use */
294 HTTP_CONTINUE = 100, 305 HTTP_CONTINUE = 100,
@@ -299,7 +310,6 @@ typedef enum
299 HTTP_NO_CONTENT = 204, 310 HTTP_NO_CONTENT = 204,
300 HTTP_MULTIPLE_CHOICES = 300, 311 HTTP_MULTIPLE_CHOICES = 300,
301 HTTP_MOVED_PERMANENTLY = 301, 312 HTTP_MOVED_PERMANENTLY = 301,
302 HTTP_MOVED_TEMPORARILY = 302,
303 HTTP_NOT_MODIFIED = 304, 313 HTTP_NOT_MODIFIED = 304,
304 HTTP_PAYMENT_REQUIRED = 402, 314 HTTP_PAYMENT_REQUIRED = 402,
305 HTTP_BAD_GATEWAY = 502, 315 HTTP_BAD_GATEWAY = 502,
@@ -317,6 +327,9 @@ typedef struct
317 327
318static const HttpEnumString httpResponseNames[] = { 328static const HttpEnumString httpResponseNames[] = {
319 { HTTP_OK, "OK" }, 329 { HTTP_OK, "OK" },
330 { HTTP_MOVED_TEMPORARILY, "Found", "Directories must end with a slash." },
331 { HTTP_REQUEST_TIMEOUT, "Request Timeout",
332 "No request appeared within a reasonable time period." },
320 { HTTP_NOT_IMPLEMENTED, "Not Implemented", 333 { HTTP_NOT_IMPLEMENTED, "Not Implemented",
321 "The requested method is not recognized by this server." }, 334 "The requested method is not recognized by this server." },
322#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 335#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
@@ -334,7 +347,6 @@ static const HttpEnumString httpResponseNames[] = {
334 { HTTP_NO_CONTENT, "No Content" }, 347 { HTTP_NO_CONTENT, "No Content" },
335 { HTTP_MULTIPLE_CHOICES, "Multiple Choices" }, 348 { HTTP_MULTIPLE_CHOICES, "Multiple Choices" },
336 { HTTP_MOVED_PERMANENTLY, "Moved Permanently" }, 349 { HTTP_MOVED_PERMANENTLY, "Moved Permanently" },
337 { HTTP_MOVED_TEMPORARILY, "Moved Temporarily" },
338 { HTTP_NOT_MODIFIED, "Not Modified" }, 350 { HTTP_NOT_MODIFIED, "Not Modified" },
339 { HTTP_BAD_GATEWAY, "Bad Gateway", "" }, 351 { HTTP_BAD_GATEWAY, "Bad Gateway", "" },
340 { HTTP_SERVICE_UNAVAILABLE, "Service Unavailable", "" }, 352 { HTTP_SERVICE_UNAVAILABLE, "Service Unavailable", "" },
@@ -943,6 +955,7 @@ static int sendHeaders(HttpResponseNum responseNum)
943 char *buf = config->buf; 955 char *buf = config->buf;
944 const char *responseString = ""; 956 const char *responseString = "";
945 const char *infoString = 0; 957 const char *infoString = 0;
958 const char *mime_type;
946 unsigned int i; 959 unsigned int i;
947 time_t timer = time(0); 960 time_t timer = time(0);
948 char timeStr[80]; 961 char timeStr[80];
@@ -956,16 +969,16 @@ static int sendHeaders(HttpResponseNum responseNum)
956 break; 969 break;
957 } 970 }
958 } 971 }
959 if (responseNum != HTTP_OK) { 972 /* error message is HTML */
960 config->found_mime_type = "text/html"; // error message is HTML 973 mime_type = responseNum == HTTP_OK ?
961 } 974 config->httpd_found.found_mime_type : "text/html";
962 975
963 /* emit the current date */ 976 /* emit the current date */
964 strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer)); 977 strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer));
965 len = sprintf(buf, 978 len = sprintf(buf,
966 "HTTP/1.0 %d %s\nContent-type: %s\r\n" 979 "HTTP/1.0 %d %s\nContent-type: %s\r\n"
967 "Date: %s\r\nConnection: close\r\n", 980 "Date: %s\r\nConnection: close\r\n",
968 responseNum, responseString, config->found_mime_type, timeStr); 981 responseNum, responseString, mime_type, timeStr);
969 982
970#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 983#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
971 if (responseNum == HTTP_UNAUTHORIZED) { 984 if (responseNum == HTTP_UNAUTHORIZED) {
@@ -973,6 +986,13 @@ static int sendHeaders(HttpResponseNum responseNum)
973 config->realm); 986 config->realm);
974 } 987 }
975#endif 988#endif
989 if(responseNum == HTTP_MOVED_TEMPORARILY) {
990 len += sprintf(buf+len, "Location: %s/%s%s\r\n",
991 config->httpd_found.found_moved_temporarily,
992 (config->query ? "?" : ""),
993 (config->query ? config->query : ""));
994 }
995
976 if (config->ContentLength != -1) { /* file */ 996 if (config->ContentLength != -1) { /* file */
977 strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&config->last_mod)); 997 strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&config->last_mod));
978 len += sprintf(buf+len, "Last-Modified: %s\r\n%s " cont_l_fmt "\r\n", 998 len += sprintf(buf+len, "Last-Modified: %s\r\n%s " cont_l_fmt "\r\n",
@@ -1035,7 +1055,6 @@ static int getLine(void)
1035 * 1055 *
1036 * $Parameters: 1056 * $Parameters:
1037 * (const char *) url . . . . . . The requested URL (with leading /). 1057 * (const char *) url . . . . . . The requested URL (with leading /).
1038 * (const char *urlArgs). . . . . Any URL arguments.
1039 * (int bodyLen) . . . . . . . . Length of the post body. 1058 * (int bodyLen) . . . . . . . . Length of the post body.
1040 * (const char *cookie) . . . . . For set HTTP_COOKIE. 1059 * (const char *cookie) . . . . . For set HTTP_COOKIE.
1041 * (const char *content_type) . . For set CONTENT_TYPE. 1060 * (const char *content_type) . . For set CONTENT_TYPE.
@@ -1047,8 +1066,7 @@ static int getLine(void)
1047 * 1066 *
1048 ****************************************************************************/ 1067 ****************************************************************************/
1049static int sendCgi(const char *url, 1068static int sendCgi(const char *url,
1050 const char *request, const char *urlArgs, 1069 const char *request, int bodyLen, const char *cookie,
1051 int bodyLen, const char *cookie,
1052 const char *content_type) 1070 const char *content_type)
1053{ 1071{
1054 int fromCgi[2]; /* pipe for reading data from CGI */ 1072 int fromCgi[2]; /* pipe for reading data from CGI */
@@ -1118,10 +1136,10 @@ static int sendCgi(const char *url,
1118 addEnv("PATH", "INFO", script); /* set /PATH_INFO or NULL */ 1136 addEnv("PATH", "INFO", script); /* set /PATH_INFO or NULL */
1119 addEnv("PATH", "", getenv("PATH")); 1137 addEnv("PATH", "", getenv("PATH"));
1120 addEnv("REQUEST", "METHOD", request); 1138 addEnv("REQUEST", "METHOD", request);
1121 if(urlArgs) { 1139 if(config->query) {
1122 char *uri = alloca(strlen(purl) + 2 + strlen(urlArgs)); 1140 char *uri = alloca(strlen(purl) + 2 + strlen(config->query));
1123 if(uri) 1141 if(uri)
1124 sprintf(uri, "%s?%s", purl, urlArgs); 1142 sprintf(uri, "%s?%s", purl, config->query);
1125 addEnv("REQUEST", "URI", uri); 1143 addEnv("REQUEST", "URI", uri);
1126 } else { 1144 } else {
1127 addEnv("REQUEST", "URI", purl); 1145 addEnv("REQUEST", "URI", purl);
@@ -1130,7 +1148,7 @@ static int sendCgi(const char *url,
1130 *script = '\0'; /* reduce /PATH_INFO */ 1148 *script = '\0'; /* reduce /PATH_INFO */
1131 /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */ 1149 /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */
1132 addEnv("SCRIPT_NAME", "", purl); 1150 addEnv("SCRIPT_NAME", "", purl);
1133 addEnv("QUERY_STRING", "", urlArgs); 1151 addEnv("QUERY_STRING", "", config->query);
1134 addEnv("SERVER", "SOFTWARE", httpdVersion); 1152 addEnv("SERVER", "SOFTWARE", httpdVersion);
1135 addEnv("SERVER", "PROTOCOL", "HTTP/1.0"); 1153 addEnv("SERVER", "PROTOCOL", "HTTP/1.0");
1136 addEnv("GATEWAY_INTERFACE", "", "CGI/1.1"); 1154 addEnv("GATEWAY_INTERFACE", "", "CGI/1.1");
@@ -1324,14 +1342,14 @@ static int sendFile(const char *url)
1324 break; 1342 break;
1325 } 1343 }
1326 /* also, if not found, set default as "application/octet-stream"; */ 1344 /* also, if not found, set default as "application/octet-stream"; */
1327 config->found_mime_type = *(table+1); 1345 config->httpd_found.found_mime_type = *(table+1);
1328#ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 1346#ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
1329 if (suffix) { 1347 if (suffix) {
1330 Htaccess * cur; 1348 Htaccess * cur;
1331 1349
1332 for (cur = config->mime_a; cur; cur = cur->next) { 1350 for (cur = config->mime_a; cur; cur = cur->next) {
1333 if(strcmp(cur->before_colon, suffix) == 0) { 1351 if(strcmp(cur->before_colon, suffix) == 0) {
1334 config->found_mime_type = cur->after_colon; 1352 config->httpd_found.found_mime_type = cur->after_colon;
1335 break; 1353 break;
1336 } 1354 }
1337 } 1355 }
@@ -1341,7 +1359,7 @@ static int sendFile(const char *url)
1341#ifdef DEBUG 1359#ifdef DEBUG
1342 if (config->debugHttpd) 1360 if (config->debugHttpd)
1343 fprintf(stderr, "Sending file '%s' Content-type: %s\n", 1361 fprintf(stderr, "Sending file '%s' Content-type: %s\n",
1344 url, config->found_mime_type); 1362 url, config->httpd_found.found_mime_type);
1345#endif 1363#endif
1346 1364
1347 f = open(url, O_RDONLY); 1365 f = open(url, O_RDONLY);
@@ -1485,6 +1503,20 @@ set_remoteuser_var:
1485 1503
1486#endif /* CONFIG_FEATURE_HTTPD_BASIC_AUTH */ 1504#endif /* CONFIG_FEATURE_HTTPD_BASIC_AUTH */
1487 1505
1506/****************************************************************************
1507 *
1508 > $Function: handleIncoming()
1509 *
1510 * $Description: Handle an incoming http request.
1511 *
1512 ****************************************************************************/
1513
1514static void
1515handle_sigalrm( int sig )
1516{
1517 sendHeaders(HTTP_REQUEST_TIMEOUT);
1518 config->alarm_signaled = sig;
1519}
1488 1520
1489/**************************************************************************** 1521/****************************************************************************
1490 * 1522 *
@@ -1499,7 +1531,6 @@ static void handleIncoming(void)
1499 char *url; 1531 char *url;
1500 char *purl; 1532 char *purl;
1501 int blank = -1; 1533 int blank = -1;
1502 char *urlArgs;
1503 char *test; 1534 char *test;
1504 struct stat sb; 1535 struct stat sb;
1505 int ip_allowed; 1536 int ip_allowed;
@@ -1514,14 +1545,21 @@ static void handleIncoming(void)
1514 struct timeval tv; 1545 struct timeval tv;
1515 int retval; 1546 int retval;
1516#endif 1547#endif
1548 struct sigaction sa;
1517 1549
1518#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 1550#ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
1519 int credentials = -1; /* if not requred this is Ok */ 1551 int credentials = -1; /* if not requred this is Ok */
1520#endif 1552#endif
1521 1553
1554 sa.sa_handler = handle_sigalrm;
1555 sigemptyset(&sa.sa_mask);
1556 sa.sa_flags = 0; /* no SA_RESTART */
1557 sigaction(SIGALRM, &sa, NULL);
1558
1522 do { 1559 do {
1523 int count; 1560 int count;
1524 1561
1562 (void) alarm( TIMEOUT );
1525 if (getLine() <= 0) 1563 if (getLine() <= 0)
1526 break; /* closed */ 1564 break; /* closed */
1527 1565
@@ -1561,9 +1599,11 @@ BAD_REQUEST:
1561 } 1599 }
1562 strcpy(url, buf); 1600 strcpy(url, buf);
1563 /* extract url args if present */ 1601 /* extract url args if present */
1564 urlArgs = strchr(url, '?'); 1602 test = strchr(url, '?');
1565 if (urlArgs) 1603 if (test) {
1566 *urlArgs++ = 0; 1604 *test++ = 0;
1605 config->query = test;
1606 }
1567 1607
1568 /* algorithm stolen from libbb bb_simplify_path(), 1608 /* algorithm stolen from libbb bb_simplify_path(),
1569 but don`t strdup and reducing trailing slash and protect out root */ 1609 but don`t strdup and reducing trailing slash and protect out root */
@@ -1594,16 +1634,15 @@ BAD_REQUEST:
1594 test = purl; /* end ptr */ 1634 test = purl; /* end ptr */
1595 1635
1596 /* If URL is directory, adding '/' */ 1636 /* If URL is directory, adding '/' */
1637 /* If URL is directory, adding '/' */
1597 if(test[-1] != '/') { 1638 if(test[-1] != '/') {
1598 if ( is_directory(url + 1, 1, &sb) ) { 1639 if ( is_directory(url + 1, 1, &sb) ) {
1599 *test++ = '/'; 1640 config->httpd_found.found_moved_temporarily = url;
1600 *test = 0;
1601 purl = test; /* end ptr */
1602 } 1641 }
1603 } 1642 }
1604#ifdef DEBUG 1643#ifdef DEBUG
1605 if (config->debugHttpd) 1644 if (config->debugHttpd)
1606 fprintf(stderr, "url='%s', args=%s\n", url, urlArgs); 1645 fprintf(stderr, "url='%s', args=%s\n", url, config->query);
1607#endif 1646#endif
1608 1647
1609 test = url; 1648 test = url;
@@ -1620,7 +1659,7 @@ BAD_REQUEST:
1620 } 1659 }
1621 1660
1622 // read until blank line for HTTP version specified, else parse immediate 1661 // read until blank line for HTTP version specified, else parse immediate
1623 while (blank >= 0 && (count = getLine()) > 0) { 1662 while (blank >= 0 && alarm(TIMEOUT) >= 0 && (count = getLine()) > 0) {
1624 1663
1625#ifdef DEBUG 1664#ifdef DEBUG
1626 if (config->debugHttpd) fprintf(stderr, "Header: '%s'\n", buf); 1665 if (config->debugHttpd) fprintf(stderr, "Header: '%s'\n", buf);
@@ -1665,6 +1704,9 @@ BAD_REQUEST:
1665 1704
1666 } /* while extra header reading */ 1705 } /* while extra header reading */
1667 1706
1707 (void) alarm( 0 );
1708 if(config->alarm_signaled)
1709 break;
1668 1710
1669 if (strcmp(strrchr(url, '/') + 1, httpd_conf) == 0 || ip_allowed == 0) { 1711 if (strcmp(strrchr(url, '/') + 1, httpd_conf) == 0 || ip_allowed == 0) {
1670 /* protect listing [/path]/httpd_conf or IP deny */ 1712 /* protect listing [/path]/httpd_conf or IP deny */
@@ -1682,6 +1724,16 @@ FORBIDDEN: /* protect listing /cgi-bin */
1682 } 1724 }
1683#endif 1725#endif
1684 1726
1727 if(config->httpd_found.found_moved_temporarily) {
1728 sendHeaders(HTTP_MOVED_TEMPORARILY);
1729#ifdef DEBUG
1730 /* clear unforked memory flag */
1731 if(config->debugHttpd)
1732 config->httpd_found.found_moved_temporarily = NULL;
1733#endif
1734 break;
1735 }
1736
1685 test = url + 1; /* skip first '/' */ 1737 test = url + 1; /* skip first '/' */
1686 1738
1687#ifdef CONFIG_FEATURE_HTTPD_CGI 1739#ifdef CONFIG_FEATURE_HTTPD_CGI
@@ -1692,7 +1744,7 @@ FORBIDDEN: /* protect listing /cgi-bin */
1692 if (strncmp(test, "cgi-bin", 7) == 0) { 1744 if (strncmp(test, "cgi-bin", 7) == 0) {
1693 if(test[7] == '/' && test[8] == 0) 1745 if(test[7] == '/' && test[8] == 0)
1694 goto FORBIDDEN; // protect listing cgi-bin/ 1746 goto FORBIDDEN; // protect listing cgi-bin/
1695 sendCgi(url, prequest, urlArgs, length, cookie, content_type); 1747 sendCgi(url, prequest, length, cookie, content_type);
1696 } else { 1748 } else {
1697 if (prequest != request_GET) 1749 if (prequest != request_GET)
1698 sendHeaders(HTTP_NOT_IMPLEMENTED); 1750 sendHeaders(HTTP_NOT_IMPLEMENTED);