diff options
author | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2006-11-21 00:06:28 +0000 |
---|---|---|
committer | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2006-11-21 00:06:28 +0000 |
commit | 4ef4f06b342a621422e5314f4d724a6b472a8614 (patch) | |
tree | 20af8b0cad2a9cd2b2b18da8fbf44fabd6510bf8 | |
parent | 0d01b9791d1d7ad53c4a9173298a14cf7dc0b571 (diff) | |
download | busybox-w32-4ef4f06b342a621422e5314f4d724a6b472a8614.tar.gz busybox-w32-4ef4f06b342a621422e5314f4d724a6b472a8614.tar.bz2 busybox-w32-4ef4f06b342a621422e5314f4d724a6b472a8614.zip |
httpd: More robust Content-length: parsing,
code reorganization (less indented)
git-svn-id: svn://busybox.net/trunk/busybox@16593 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r-- | networking/httpd.c | 170 |
1 files changed, 86 insertions, 84 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index d5cfd652c..71792862e 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -256,7 +256,9 @@ static const HttpEnumString httpResponseNames[] = { | |||
256 | 256 | ||
257 | 257 | ||
258 | static const char RFC1123FMT[] = "%a, %d %b %Y %H:%M:%S GMT"; | 258 | static const char RFC1123FMT[] = "%a, %d %b %Y %H:%M:%S GMT"; |
259 | static const char Content_length[] = "Content-length:"; | 259 | |
260 | |||
261 | #define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1) | ||
260 | 262 | ||
261 | 263 | ||
262 | static int scan_ip(const char **ep, unsigned int *ip, unsigned char endc) | 264 | static int scan_ip(const char **ep, unsigned int *ip, unsigned char endc) |
@@ -880,7 +882,7 @@ static int sendHeaders(HttpResponseNum responseNum) | |||
880 | if (config->ContentLength != -1) { /* file */ | 882 | if (config->ContentLength != -1) { /* file */ |
881 | strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&config->last_mod)); | 883 | strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&config->last_mod)); |
882 | len += sprintf(buf+len, "Last-Modified: %s\r\n%s %"OFF_FMT"\r\n", | 884 | len += sprintf(buf+len, "Last-Modified: %s\r\n%s %"OFF_FMT"\r\n", |
883 | timeStr, Content_length, (off_t) config->ContentLength); | 885 | timeStr, "Content-length:", (off_t) config->ContentLength); |
884 | } | 886 | } |
885 | strcat(buf, "\r\n"); | 887 | strcat(buf, "\r\n"); |
886 | len += 2; | 888 | len += 2; |
@@ -962,20 +964,15 @@ static int sendCgi(const char *url, | |||
962 | int outFd; | 964 | int outFd; |
963 | int firstLine = 1; | 965 | int firstLine = 1; |
964 | 966 | ||
965 | do { | 967 | if (pipe(fromCgi) != 0) |
966 | if (pipe(fromCgi) != 0) { | 968 | return 0; |
967 | break; | 969 | if (pipe(toCgi) != 0) |
968 | } | 970 | return 0; |
969 | if (pipe(toCgi) != 0) { | 971 | pid = fork(); |
970 | break; | 972 | if (pid < 0) |
971 | } | 973 | return 0; |
972 | |||
973 | pid = fork(); | ||
974 | if (pid < 0) { | ||
975 | pid = 0; | ||
976 | break; | ||
977 | } | ||
978 | 974 | ||
975 | do { | ||
979 | if (!pid) { | 976 | if (!pid) { |
980 | /* child process */ | 977 | /* child process */ |
981 | char *script; | 978 | char *script; |
@@ -1031,10 +1028,9 @@ static int sendCgi(const char *url, | |||
1031 | if (script != NULL) | 1028 | if (script != NULL) |
1032 | *script = '\0'; /* reduce /PATH_INFO */ | 1029 | *script = '\0'; /* reduce /PATH_INFO */ |
1033 | /* SCRIPT_FILENAME required by PHP in CGI mode */ | 1030 | /* SCRIPT_FILENAME required by PHP in CGI mode */ |
1034 | if (realpath(purl + 1, realpath_buff)) | 1031 | if (!realpath(purl + 1, realpath_buff)) |
1035 | setenv1("SCRIPT_FILENAME", realpath_buff); | 1032 | goto error_execing_cgi; |
1036 | else | 1033 | setenv1("SCRIPT_FILENAME", realpath_buff); |
1037 | *realpath_buff = '\0'; | ||
1038 | /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */ | 1034 | /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */ |
1039 | setenv1("SCRIPT_NAME", purl); | 1035 | setenv1("SCRIPT_NAME", purl); |
1040 | setenv1("QUERY_STRING", config->query); | 1036 | setenv1("QUERY_STRING", config->query); |
@@ -1045,9 +1041,8 @@ static int sendCgi(const char *url, | |||
1045 | #if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV | 1041 | #if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV |
1046 | setenv_long("REMOTE_PORT", config->port); | 1042 | setenv_long("REMOTE_PORT", config->port); |
1047 | #endif | 1043 | #endif |
1048 | if (bodyLen) { | 1044 | if (bodyLen) |
1049 | setenv_long("CONTENT_LENGTH", bodyLen); | 1045 | setenv_long("CONTENT_LENGTH", bodyLen); |
1050 | } | ||
1051 | if (cookie) | 1046 | if (cookie) |
1052 | setenv1("HTTP_COOKIE", cookie); | 1047 | setenv1("HTTP_COOKIE", cookie); |
1053 | if (content_type) | 1048 | if (content_type) |
@@ -1064,37 +1059,37 @@ static int sendCgi(const char *url, | |||
1064 | /* set execve argp[0] without path */ | 1059 | /* set execve argp[0] without path */ |
1065 | argp[0] = strrchr(purl, '/') + 1; | 1060 | argp[0] = strrchr(purl, '/') + 1; |
1066 | /* but script argp[0] must have absolute path and chdiring to this */ | 1061 | /* but script argp[0] must have absolute path and chdiring to this */ |
1067 | if (*realpath_buff) { | 1062 | script = strrchr(realpath_buff, '/'); |
1068 | script = strrchr(realpath_buff, '/'); | 1063 | if (!script) |
1069 | if (script) { | 1064 | goto error_execing_cgi; |
1070 | *script = '\0'; | 1065 | *script = '\0'; |
1071 | if (chdir(realpath_buff) == 0) { | 1066 | if (chdir(realpath_buff) == 0) { |
1072 | // now run the program. If it fails, | 1067 | // now run the program. If it fails, |
1073 | // use _exit() so no destructors | 1068 | // use _exit() so no destructors |
1074 | // get called and make a mess. | 1069 | // get called and make a mess. |
1075 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR | 1070 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR |
1076 | char *interpr = NULL; | 1071 | char *interpr = NULL; |
1077 | char *suffix = strrchr(purl, '.'); | 1072 | char *suffix = strrchr(purl, '.'); |
1078 | 1073 | ||
1079 | if (suffix) { | 1074 | if (suffix) { |
1080 | Htaccess * cur; | 1075 | Htaccess *cur; |
1081 | for (cur = config->script_i; cur; cur = cur->next) | 1076 | for (cur = config->script_i; cur; cur = cur->next) { |
1082 | if (strcmp(cur->before_colon + 1, suffix) == 0) { | 1077 | if (strcmp(cur->before_colon + 1, suffix) == 0) { |
1083 | interpr = cur->after_colon; | 1078 | interpr = cur->after_colon; |
1084 | break; | 1079 | break; |
1085 | } | ||
1086 | } | 1080 | } |
1081 | } | ||
1082 | } | ||
1087 | #endif | 1083 | #endif |
1088 | *script = '/'; | 1084 | *script = '/'; |
1089 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR | 1085 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR |
1090 | if (interpr) | 1086 | if (interpr) |
1091 | execv(interpr, argp); | 1087 | execv(interpr, argp); |
1092 | else | 1088 | else |
1093 | #endif | 1089 | #endif |
1094 | execv(realpath_buff, argp); | 1090 | execv(realpath_buff, argp); |
1095 | } | ||
1096 | } | ||
1097 | } | 1091 | } |
1092 | error_execing_cgi: | ||
1098 | /* send to stdout (even if we are not from inetd) */ | 1093 | /* send to stdout (even if we are not from inetd) */ |
1099 | config->accepted_socket = 1; | 1094 | config->accepted_socket = 1; |
1100 | sendHeaders(HTTP_NOT_FOUND); | 1095 | sendHeaders(HTTP_NOT_FOUND); |
@@ -1103,7 +1098,7 @@ static int sendCgi(const char *url, | |||
1103 | 1098 | ||
1104 | } while (0); | 1099 | } while (0); |
1105 | 1100 | ||
1106 | if (pid) { | 1101 | if (pid > 0) { |
1107 | /* parent process */ | 1102 | /* parent process */ |
1108 | int status; | 1103 | int status; |
1109 | size_t post_readed_size = 0, post_readed_idx = 0; | 1104 | size_t post_readed_size = 0, post_readed_idx = 0; |
@@ -1425,7 +1420,7 @@ static void handleIncoming(void) | |||
1425 | int ip_allowed; | 1420 | int ip_allowed; |
1426 | #if ENABLE_FEATURE_HTTPD_CGI | 1421 | #if ENABLE_FEATURE_HTTPD_CGI |
1427 | const char *prequest = request_GET; | 1422 | const char *prequest = request_GET; |
1428 | long length = 0; | 1423 | unsigned long length = 0; |
1429 | char *cookie = 0; | 1424 | char *cookie = 0; |
1430 | char *content_type = 0; | 1425 | char *content_type = 0; |
1431 | #endif | 1426 | #endif |
@@ -1452,11 +1447,11 @@ static void handleIncoming(void) | |||
1452 | 1447 | ||
1453 | purl = strpbrk(buf, " \t"); | 1448 | purl = strpbrk(buf, " \t"); |
1454 | if (purl == NULL) { | 1449 | if (purl == NULL) { |
1455 | BAD_REQUEST: | 1450 | BAD_REQUEST: |
1456 | sendHeaders(HTTP_BAD_REQUEST); | 1451 | sendHeaders(HTTP_BAD_REQUEST); |
1457 | break; | 1452 | break; |
1458 | } | 1453 | } |
1459 | *purl = 0; | 1454 | *purl = '\0'; |
1460 | #if ENABLE_FEATURE_HTTPD_CGI | 1455 | #if ENABLE_FEATURE_HTTPD_CGI |
1461 | if (strcasecmp(buf, prequest) != 0) { | 1456 | if (strcasecmp(buf, prequest) != 0) { |
1462 | prequest = "POST"; | 1457 | prequest = "POST"; |
@@ -1487,29 +1482,35 @@ BAD_REQUEST: | |||
1487 | /* extract url args if present */ | 1482 | /* extract url args if present */ |
1488 | test = strchr(url, '?'); | 1483 | test = strchr(url, '?'); |
1489 | if (test) { | 1484 | if (test) { |
1490 | *test++ = 0; | 1485 | *test++ = '\0'; |
1491 | config->query = test; | 1486 | config->query = test; |
1492 | } | 1487 | } |
1493 | 1488 | ||
1494 | test = decodeString(url, 0); | 1489 | test = decodeString(url, 0); |
1495 | if (test == NULL) | 1490 | if (test == NULL) |
1496 | goto BAD_REQUEST; | 1491 | goto BAD_REQUEST; |
1492 | /* FIXME: bug? should be "url+1"? */ | ||
1497 | if (test == (buf+1)) { | 1493 | if (test == (buf+1)) { |
1498 | sendHeaders(HTTP_NOT_FOUND); | 1494 | sendHeaders(HTTP_NOT_FOUND); |
1499 | break; | 1495 | break; |
1500 | } | 1496 | } |
1497 | |||
1501 | /* algorithm stolen from libbb bb_simplify_path(), | 1498 | /* algorithm stolen from libbb bb_simplify_path(), |
1502 | but don't strdup and reducing trailing slash and protect out root */ | 1499 | but don't strdup and reducing trailing slash and protect out root */ |
1503 | purl = test = url; | 1500 | purl = test = url; |
1504 | |||
1505 | do { | 1501 | do { |
1506 | if (*purl == '/') { | 1502 | if (*purl == '/') { |
1507 | if (*test == '/') { /* skip duplicate (or initial) slash */ | 1503 | /* skip duplicate (or initial) slash */ |
1504 | if (*test == '/') { | ||
1508 | continue; | 1505 | continue; |
1509 | } else if (*test == '.') { | 1506 | } |
1510 | if (test[1] == '/' || test[1] == 0) { /* skip extra '.' */ | 1507 | if (*test == '.') { |
1508 | /* skip extra '.' */ | ||
1509 | if (test[1] == '/' || test[1] == 0) { | ||
1511 | continue; | 1510 | continue; |
1512 | } else if ((test[1] == '.') && (test[2] == '/' || test[2] == 0)) { | 1511 | } else |
1512 | /* '..': be careful */ | ||
1513 | if (test[1] == '.' && (test[2] == '/' || test[2] == 0)) { | ||
1513 | ++test; | 1514 | ++test; |
1514 | if (purl == url) { | 1515 | if (purl == url) { |
1515 | /* protect out root */ | 1516 | /* protect out root */ |
@@ -1522,9 +1523,8 @@ BAD_REQUEST: | |||
1522 | } | 1523 | } |
1523 | *++purl = *test; | 1524 | *++purl = *test; |
1524 | } while (*++test); | 1525 | } while (*++test); |
1525 | 1526 | *++purl = '\0'; /* so keep last character */ | |
1526 | *++purl = 0; /* so keep last character */ | 1527 | test = purl; /* end ptr */ |
1527 | test = purl; /* end ptr */ | ||
1528 | 1528 | ||
1529 | /* If URL is directory, adding '/' */ | 1529 | /* If URL is directory, adding '/' */ |
1530 | if (test[-1] != '/') { | 1530 | if (test[-1] != '/') { |
@@ -1560,36 +1560,40 @@ BAD_REQUEST: | |||
1560 | 1560 | ||
1561 | #if ENABLE_FEATURE_HTTPD_CGI | 1561 | #if ENABLE_FEATURE_HTTPD_CGI |
1562 | /* try and do our best to parse more lines */ | 1562 | /* try and do our best to parse more lines */ |
1563 | if ((strncasecmp(buf, Content_length, 15) == 0)) { | 1563 | if ((STRNCASECMP(buf, "Content-length:") == 0)) { |
1564 | if (prequest != request_GET) | 1564 | /* extra read only for POST */ |
1565 | length = strtol(buf + 15, 0, 0); // extra read only for POST | 1565 | if (prequest != request_GET) { |
1566 | } else if ((strncasecmp(buf, "Cookie:", 7) == 0)) { | 1566 | test = buf + sizeof("Content-length:")-1; |
1567 | for (test = buf + 7; isspace(*test); test++) | 1567 | if (!test[0]) goto bail_out; |
1568 | ; | 1568 | errno = 0; |
1569 | cookie = strdup(test); | 1569 | /* not using strtoul: it ignores leading munis! */ |
1570 | } else if ((strncasecmp(buf, "Content-Type:", 13) == 0)) { | 1570 | length = strtol(test, &test, 10); |
1571 | for (test = buf + 13; isspace(*test); test++) | 1571 | /* length is "ulong", but we need to pass it to int later */ |
1572 | ; | 1572 | /* so we check for negative or too large values in one go: */ |
1573 | content_type = strdup(test); | 1573 | /* (long -> ulong conv will cause negatives to be seen as > INT_MAX) */ |
1574 | } else if ((strncasecmp(buf, "Referer:", 8) == 0)) { | 1574 | if (test[0] || errno || length > INT_MAX) |
1575 | for (test = buf + 8; isspace(*test); test++) | 1575 | goto bail_out; |
1576 | ; | 1576 | } |
1577 | config->referer = strdup(test); | 1577 | } else if ((STRNCASECMP(buf, "Cookie:") == 0)) { |
1578 | cookie = strdup(skip_whitespace(buf + sizeof("Cookie:")-1)); | ||
1579 | } else if ((STRNCASECMP(buf, "Content-Type:") == 0)) { | ||
1580 | content_type = strdup(skip_whitespace(buf + sizeof("Content-Type:")-1)); | ||
1581 | } else if ((STRNCASECMP(buf, "Referer:") == 0)) { | ||
1582 | config->referer = strdup(skip_whitespace(buf + sizeof("Referer:")-1)); | ||
1578 | } | 1583 | } |
1579 | #endif | 1584 | #endif |
1580 | 1585 | ||
1581 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 1586 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
1582 | if (strncasecmp(buf, "Authorization:", 14) == 0) { | 1587 | if (STRNCASECMP(buf, "Authorization:") == 0) { |
1583 | /* We only allow Basic credentials. | 1588 | /* We only allow Basic credentials. |
1584 | * It shows up as "Authorization: Basic <userid:password>" where | 1589 | * It shows up as "Authorization: Basic <userid:password>" where |
1585 | * the userid:password is base64 encoded. | 1590 | * the userid:password is base64 encoded. |
1586 | */ | 1591 | */ |
1587 | for (test = buf + 14; isspace(*test); test++) | 1592 | test = skip_whitespace(buf + sizeof("Authorization:")-1); |
1588 | ; | 1593 | if (STRNCASECMP(test, "Basic") != 0) |
1589 | if (strncasecmp(test, "Basic", 5) != 0) | ||
1590 | continue; | 1594 | continue; |
1591 | 1595 | test += sizeof("Basic")-1; | |
1592 | test += 5; /* decodeBase64() skiping space self */ | 1596 | /* decodeBase64() skips whitespace itself */ |
1593 | decodeBase64(test); | 1597 | decodeBase64(test); |
1594 | credentials = checkPerm(url, test); | 1598 | credentials = checkPerm(url, test); |
1595 | } | 1599 | } |
@@ -1627,10 +1631,6 @@ FORBIDDEN: /* protect listing /cgi-bin */ | |||
1627 | test = url + 1; /* skip first '/' */ | 1631 | test = url + 1; /* skip first '/' */ |
1628 | 1632 | ||
1629 | #if ENABLE_FEATURE_HTTPD_CGI | 1633 | #if ENABLE_FEATURE_HTTPD_CGI |
1630 | /* if strange Content-Length */ | ||
1631 | if (length < 0) | ||
1632 | break; | ||
1633 | |||
1634 | if (strncmp(test, "cgi-bin", 7) == 0) { | 1634 | if (strncmp(test, "cgi-bin", 7) == 0) { |
1635 | if (test[7] == '/' && test[8] == 0) | 1635 | if (test[7] == '/' && test[8] == 0) |
1636 | goto FORBIDDEN; // protect listing cgi-bin/ | 1636 | goto FORBIDDEN; // protect listing cgi-bin/ |
@@ -1654,6 +1654,8 @@ FORBIDDEN: /* protect listing /cgi-bin */ | |||
1654 | #endif | 1654 | #endif |
1655 | } while (0); | 1655 | } while (0); |
1656 | 1656 | ||
1657 | bail_out: | ||
1658 | |||
1657 | if (DEBUG) | 1659 | if (DEBUG) |
1658 | fprintf(stderr, "closing socket\n\n"); | 1660 | fprintf(stderr, "closing socket\n\n"); |
1659 | #if ENABLE_FEATURE_HTTPD_CGI | 1661 | #if ENABLE_FEATURE_HTTPD_CGI |