diff options
-rw-r--r-- | networking/httpd.c | 95 |
1 files changed, 56 insertions, 39 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index cd46f49ef..072714435 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -131,11 +131,12 @@ typedef struct Htaccess_IP { | |||
131 | } Htaccess_IP; | 131 | } Htaccess_IP; |
132 | 132 | ||
133 | struct globals { | 133 | struct globals { |
134 | int verbose; | 134 | int verbose; /* must be int (used by getopt32) */ |
135 | smallint flg_deny_all; | 135 | smallint flg_deny_all; |
136 | 136 | ||
137 | unsigned rmt_ip; | 137 | unsigned rmt_ip; |
138 | unsigned rmt_port; /* for set env REMOTE_PORT */ | 138 | unsigned rmt_port; /* for set env REMOTE_PORT */ |
139 | char *rmt_ip_str; /* for set env REMOTE_ADDR */ | ||
139 | const char *bind_addr_or_port; | 140 | const char *bind_addr_or_port; |
140 | 141 | ||
141 | const char *g_query; | 142 | const char *g_query; |
@@ -145,26 +146,27 @@ struct globals { | |||
145 | const char *found_mime_type; | 146 | const char *found_mime_type; |
146 | const char *found_moved_temporarily; | 147 | const char *found_moved_temporarily; |
147 | time_t last_mod; | 148 | time_t last_mod; |
148 | off_t ContentLength; /* -1 - unknown */ | 149 | off_t ContentLength; /* -1 - unknown */ |
149 | Htaccess_IP *ip_a_d; /* config allow/deny lines */ | 150 | Htaccess_IP *ip_a_d; /* config allow/deny lines */ |
150 | 151 | ||
151 | USE_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;) | 152 | USE_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;) |
152 | USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;) | 153 | USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;) |
153 | USE_FEATURE_HTTPD_CGI(char *referer;) | 154 | USE_FEATURE_HTTPD_CGI(char *referer;) |
154 | USE_FEATURE_HTTPD_CGI(char *user_agent;) | 155 | USE_FEATURE_HTTPD_CGI(char *user_agent;) |
155 | 156 | ||
156 | char *rmt_ip_str; /* for set env REMOTE_ADDR */ | ||
157 | |||
158 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 157 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
159 | Htaccess *g_auth; /* config user:password lines */ | 158 | Htaccess *g_auth; /* config user:password lines */ |
160 | #endif | 159 | #endif |
161 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES | 160 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES |
162 | Htaccess *mime_a; /* config mime types */ | 161 | Htaccess *mime_a; /* config mime types */ |
163 | #endif | 162 | #endif |
164 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR | 163 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR |
165 | Htaccess *script_i; /* config script interpreters */ | 164 | Htaccess *script_i; /* config script interpreters */ |
166 | #endif | 165 | #endif |
167 | char iobuf[MAX_MEMORY_BUF]; | 166 | char *iobuf; /* [MAX_MEMORY_BUF] */ |
167 | #define hdr_buf bb_common_bufsiz1 | ||
168 | char *hdr_ptr; | ||
169 | int hdr_cnt; | ||
168 | }; | 170 | }; |
169 | #define G (*ptr_to_globals) | 171 | #define G (*ptr_to_globals) |
170 | #define verbose (G.verbose ) | 172 | #define verbose (G.verbose ) |
@@ -189,6 +191,8 @@ struct globals { | |||
189 | #define mime_a (G.mime_a ) | 191 | #define mime_a (G.mime_a ) |
190 | #define script_i (G.script_i ) | 192 | #define script_i (G.script_i ) |
191 | #define iobuf (G.iobuf ) | 193 | #define iobuf (G.iobuf ) |
194 | #define hdr_ptr (G.hdr_ptr ) | ||
195 | #define hdr_cnt (G.hdr_cnt ) | ||
192 | #define INIT_G() do { \ | 196 | #define INIT_G() do { \ |
193 | PTR_TO_GLOBALS = xzalloc(sizeof(G)); \ | 197 | PTR_TO_GLOBALS = xzalloc(sizeof(G)); \ |
194 | USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \ | 198 | USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \ |
@@ -196,6 +200,7 @@ struct globals { | |||
196 | ContentLength = -1; \ | 200 | ContentLength = -1; \ |
197 | } while (0) | 201 | } while (0) |
198 | 202 | ||
203 | |||
199 | typedef enum { | 204 | typedef enum { |
200 | HTTP_OK = 200, | 205 | HTTP_OK = 200, |
201 | HTTP_MOVED_TEMPORARILY = 302, | 206 | HTTP_MOVED_TEMPORARILY = 302, |
@@ -881,12 +886,21 @@ static void send_headers_and_exit(HttpResponseNum responseNum) | |||
881 | static int get_line(void) | 886 | static int get_line(void) |
882 | { | 887 | { |
883 | int count = 0; | 888 | int count = 0; |
889 | char c; | ||
890 | |||
891 | while (1) { | ||
892 | if (hdr_cnt <= 0) { | ||
893 | hdr_cnt = safe_read(0, hdr_buf, sizeof(hdr_buf)); | ||
894 | if (hdr_cnt <= 0) | ||
895 | break; | ||
896 | hdr_ptr = hdr_buf; | ||
897 | } | ||
898 | iobuf[count] = c = *hdr_ptr++; | ||
899 | hdr_cnt--; | ||
884 | 900 | ||
885 | /* We must not read extra chars. Reading byte-by-byte... */ | 901 | if (c == '\r') |
886 | while (read(0, iobuf + count, 1) == 1) { | ||
887 | if (iobuf[count] == '\r') | ||
888 | continue; | 902 | continue; |
889 | if (iobuf[count] == '\n') { | 903 | if (c == '\n') { |
890 | iobuf[count] = '\0'; | 904 | iobuf[count] = '\0'; |
891 | return count; | 905 | return count; |
892 | } | 906 | } |
@@ -928,7 +942,6 @@ static void send_cgi_and_exit( | |||
928 | char *fullpath; | 942 | char *fullpath; |
929 | char *script; | 943 | char *script; |
930 | char *purl; | 944 | char *purl; |
931 | size_t post_read_size, post_read_idx; | ||
932 | int buf_count; | 945 | int buf_count; |
933 | int status; | 946 | int status; |
934 | int pid = 0; | 947 | int pid = 0; |
@@ -1080,10 +1093,10 @@ static void send_cgi_and_exit( | |||
1080 | /* First, restore variables possibly changed by child */ | 1093 | /* First, restore variables possibly changed by child */ |
1081 | xfunc_error_retval = 0; | 1094 | xfunc_error_retval = 0; |
1082 | 1095 | ||
1083 | /* Prepare for pumping data */ | 1096 | /* Prepare for pumping data. |
1097 | * iobuf is used for CGI -> network data, | ||
1098 | * hdr_buf is for network -> CGI data (POSTDATA) */ | ||
1084 | buf_count = 0; | 1099 | buf_count = 0; |
1085 | post_read_size = 0; | ||
1086 | post_read_idx = 0; /* for gcc */ | ||
1087 | close(fromCgi.wr); | 1100 | close(fromCgi.wr); |
1088 | close(toCgi.rd); | 1101 | close(toCgi.rd); |
1089 | 1102 | ||
@@ -1091,25 +1104,25 @@ static void send_cgi_and_exit( | |||
1091 | * and send it to the peer. So please no SIGPIPEs! */ | 1104 | * and send it to the peer. So please no SIGPIPEs! */ |
1092 | signal(SIGPIPE, SIG_IGN); | 1105 | signal(SIGPIPE, SIG_IGN); |
1093 | 1106 | ||
1107 | /* This loop still looks messy. What is an exit criteria? | ||
1108 | * "CGI's output closed"? Or "CGI has exited"? | ||
1109 | * What to do if CGI has closed both input and output, but | ||
1110 | * didn't exit? etc... */ | ||
1111 | |||
1112 | /* NB: breaking out of this loop jumps to log_and_exit() */ | ||
1094 | while (1) { | 1113 | while (1) { |
1095 | fd_set readSet; | 1114 | fd_set readSet; |
1096 | fd_set writeSet; | 1115 | fd_set writeSet; |
1097 | char wbuf[128]; | ||
1098 | int nfound; | 1116 | int nfound; |
1099 | int count; | 1117 | int count; |
1100 | 1118 | ||
1101 | /* This loop still looks messy. What is an exit criteria? | ||
1102 | * "CGI's output closed"? Or "CGI has exited"? | ||
1103 | * What to do if CGI has closed both input and output, but | ||
1104 | * didn't exit? etc... */ | ||
1105 | |||
1106 | FD_ZERO(&readSet); | 1119 | FD_ZERO(&readSet); |
1107 | FD_ZERO(&writeSet); | 1120 | FD_ZERO(&writeSet); |
1108 | FD_SET(fromCgi.rd, &readSet); | 1121 | FD_SET(fromCgi.rd, &readSet); |
1109 | if (bodyLen > 0 || post_read_size > 0) { | 1122 | if (bodyLen > 0 || hdr_cnt > 0) { |
1110 | FD_SET(toCgi.wr, &writeSet); | 1123 | FD_SET(toCgi.wr, &writeSet); |
1111 | nfound = toCgi.wr > fromCgi.rd ? toCgi.wr : fromCgi.rd; | 1124 | nfound = toCgi.wr > fromCgi.rd ? toCgi.wr : fromCgi.rd; |
1112 | if (post_read_size == 0) | 1125 | if (hdr_cnt <= 0) |
1113 | FD_SET(0, &readSet); | 1126 | FD_SET(0, &readSet); |
1114 | /* Now wait on the set of sockets! */ | 1127 | /* Now wait on the set of sockets! */ |
1115 | nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL); | 1128 | nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL); |
@@ -1135,30 +1148,30 @@ static void send_cgi_and_exit( | |||
1135 | break; | 1148 | break; |
1136 | } | 1149 | } |
1137 | 1150 | ||
1138 | if (post_read_size > 0 && FD_ISSET(toCgi.wr, &writeSet)) { | 1151 | if (hdr_cnt > 0 && FD_ISSET(toCgi.wr, &writeSet)) { |
1139 | /* Have data from peer and can write to CGI */ | 1152 | /* Have data from peer and can write to CGI */ |
1140 | count = safe_write(toCgi.wr, wbuf + post_read_idx, post_read_size); | 1153 | count = safe_write(toCgi.wr, hdr_ptr, hdr_cnt); |
1141 | /* Doesn't happen, we dont use nonblocking IO here | 1154 | /* Doesn't happen, we dont use nonblocking IO here |
1142 | *if (count < 0 && errno == EAGAIN) { | 1155 | *if (count < 0 && errno == EAGAIN) { |
1143 | * ... | 1156 | * ... |
1144 | *} else */ | 1157 | *} else */ |
1145 | if (count > 0) { | 1158 | if (count > 0) { |
1146 | post_read_idx += count; | 1159 | hdr_ptr += count; |
1147 | post_read_size -= count; | 1160 | hdr_cnt -= count; |
1148 | } else { | 1161 | } else { |
1149 | post_read_size = bodyLen = 0; /* EOF/broken pipe to CGI */ | 1162 | hdr_cnt = bodyLen = 0; /* EOF/broken pipe to CGI */ |
1150 | } | 1163 | } |
1151 | } else if (bodyLen > 0 && post_read_size == 0 | 1164 | } else if (bodyLen > 0 && hdr_cnt == 0 |
1152 | && FD_ISSET(0, &readSet) | 1165 | && FD_ISSET(0, &readSet) |
1153 | ) { | 1166 | ) { |
1154 | /* We expect data, prev data portion is eaten by CGI | 1167 | /* We expect data, prev data portion is eaten by CGI |
1155 | * and there *is* data to read from the peer | 1168 | * and there *is* data to read from the peer |
1156 | * (POSTDATA?) */ | 1169 | * (POSTDATA?) */ |
1157 | count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen; | 1170 | count = bodyLen > (int)sizeof(hdr_buf) ? (int)sizeof(hdr_buf) : bodyLen; |
1158 | count = safe_read(0, wbuf, count); | 1171 | count = safe_read(0, hdr_buf, count); |
1159 | if (count > 0) { | 1172 | if (count > 0) { |
1160 | post_read_size = count; | 1173 | hdr_cnt = count; |
1161 | post_read_idx = 0; | 1174 | hdr_ptr = hdr_buf; |
1162 | bodyLen -= count; | 1175 | bodyLen -= count; |
1163 | } else { | 1176 | } else { |
1164 | bodyLen = 0; /* closed */ | 1177 | bodyLen = 0; /* closed */ |
@@ -1195,7 +1208,7 @@ static void send_cgi_and_exit( | |||
1195 | full_write(1, HTTP_200, sizeof(HTTP_200)-1); | 1208 | full_write(1, HTTP_200, sizeof(HTTP_200)-1); |
1196 | full_write(1, rbuf, buf_count); | 1209 | full_write(1, rbuf, buf_count); |
1197 | } | 1210 | } |
1198 | break; /* closed */ | 1211 | break; /* CGI stdout is closed, exiting */ |
1199 | } | 1212 | } |
1200 | buf_count += count; | 1213 | buf_count += count; |
1201 | count = 0; | 1214 | count = 0; |
@@ -1379,6 +1392,7 @@ static int checkPermIP(void) | |||
1379 | return !flg_deny_all; | 1392 | return !flg_deny_all; |
1380 | } | 1393 | } |
1381 | 1394 | ||
1395 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | ||
1382 | /* | 1396 | /* |
1383 | * Check the permission file for access password protected. | 1397 | * Check the permission file for access password protected. |
1384 | * | 1398 | * |
@@ -1390,7 +1404,6 @@ static int checkPermIP(void) | |||
1390 | * | 1404 | * |
1391 | * Returns 1 if request is OK. | 1405 | * Returns 1 if request is OK. |
1392 | */ | 1406 | */ |
1393 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | ||
1394 | static int checkPerm(const char *path, const char *request) | 1407 | static int checkPerm(const char *path, const char *request) |
1395 | { | 1408 | { |
1396 | Htaccess *cur; | 1409 | Htaccess *cur; |
@@ -1457,7 +1470,6 @@ static int checkPerm(const char *path, const char *request) | |||
1457 | 1470 | ||
1458 | return prev == NULL; | 1471 | return prev == NULL; |
1459 | } | 1472 | } |
1460 | |||
1461 | #endif /* FEATURE_HTTPD_BASIC_AUTH */ | 1473 | #endif /* FEATURE_HTTPD_BASIC_AUTH */ |
1462 | 1474 | ||
1463 | /* | 1475 | /* |
@@ -1495,6 +1507,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
1495 | int credentials = -1; /* if not required this is Ok */ | 1507 | int credentials = -1; /* if not required this is Ok */ |
1496 | #endif | 1508 | #endif |
1497 | 1509 | ||
1510 | /* Allocation of iobuf is postponed until now | ||
1511 | * (IOW, server process doesn't need to waste 8k) */ | ||
1512 | iobuf = xmalloc(MAX_MEMORY_BUF); | ||
1513 | |||
1498 | rmt_port = get_nport(&fromAddr->sa); | 1514 | rmt_port = get_nport(&fromAddr->sa); |
1499 | rmt_port = ntohs(rmt_port); | 1515 | rmt_port = ntohs(rmt_port); |
1500 | rmt_ip = 0; | 1516 | rmt_ip = 0; |
@@ -1731,6 +1747,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
1731 | send_headers_and_exit(HTTP_NOT_IMPLEMENTED); | 1747 | send_headers_and_exit(HTTP_NOT_IMPLEMENTED); |
1732 | } | 1748 | } |
1733 | #endif /* FEATURE_HTTPD_CGI */ | 1749 | #endif /* FEATURE_HTTPD_CGI */ |
1750 | |||
1734 | if (purl[-1] == '/') | 1751 | if (purl[-1] == '/') |
1735 | strcpy(purl, "index.html"); | 1752 | strcpy(purl, "index.html"); |
1736 | if (stat(test, &sb) == 0) { | 1753 | if (stat(test, &sb) == 0) { |