diff options
author | Ron Yorston <rmy@pobox.com> | 2019-04-20 07:50:02 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2019-04-20 07:50:02 +0100 |
commit | 241d4d4ac319d4b0507dbc70434545418fd74b79 (patch) | |
tree | 3d1d8b92eb7f015f5e102cd472a330ec784a5d43 | |
parent | e4bc2cb29c5465cbec2dec1ba3b325139007d03a (diff) | |
parent | e49a572b529dc7dcfb052c679074b9b87577e388 (diff) | |
download | busybox-w32-FRP-3128-g241d4d4ac.tar.gz busybox-w32-FRP-3128-g241d4d4ac.tar.bz2 busybox-w32-FRP-3128-g241d4d4ac.zip |
Merge branch 'busybox' into mergeFRP-3128-g241d4d4ac
-rw-r--r-- | networking/httpd.c | 260 | ||||
-rw-r--r-- | shell/ash.c | 36 | ||||
-rw-r--r-- | shell/hush.c | 3 | ||||
-rwxr-xr-x | testsuite/dc.tests | 6 |
4 files changed, 172 insertions, 133 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index 2b0acd7dc..3f1e02ec8 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -259,18 +259,11 @@ | |||
259 | #if ENABLE_FEATURE_USE_SENDFILE | 259 | #if ENABLE_FEATURE_USE_SENDFILE |
260 | # include <sys/sendfile.h> | 260 | # include <sys/sendfile.h> |
261 | #endif | 261 | #endif |
262 | /* amount of buffering in a pipe */ | ||
263 | #ifndef PIPE_BUF | ||
264 | # define PIPE_BUF 4096 | ||
265 | #endif | ||
266 | 262 | ||
267 | #define DEBUG 0 | 263 | #define DEBUG 0 |
268 | 264 | ||
269 | #define IOBUF_SIZE 8192 | 265 | #define IOBUF_SIZE 8192 |
270 | #define MAX_HTTP_HEADERS_SIZE ((8*1024) - 16) | 266 | #define MAX_HTTP_HEADERS_SIZE (32*1024) |
271 | #if PIPE_BUF >= IOBUF_SIZE | ||
272 | # error "PIPE_BUF >= IOBUF_SIZE" | ||
273 | #endif | ||
274 | 267 | ||
275 | #define HEADER_READ_TIMEOUT 60 | 268 | #define HEADER_READ_TIMEOUT 60 |
276 | 269 | ||
@@ -1150,18 +1143,61 @@ static void send_headers(unsigned responseNum) | |||
1150 | file_size = range_end - range_start + 1; | 1143 | file_size = range_end - range_start + 1; |
1151 | } | 1144 | } |
1152 | #endif | 1145 | #endif |
1146 | |||
1147 | //RFC 2616 4.4 Message Length | ||
1148 | // The transfer-length of a message is the length of the message-body as | ||
1149 | // it appears in the message; that is, after any transfer-codings have | ||
1150 | // been applied. When a message-body is included with a message, the | ||
1151 | // transfer-length of that body is determined by one of the following | ||
1152 | // (in order of precedence): | ||
1153 | // 1.Any response message which "MUST NOT" include a message-body (such | ||
1154 | // as the 1xx, 204, and 304 responses and any response to a HEAD | ||
1155 | // request) is always terminated by the first empty line after the | ||
1156 | // header fields, regardless of the entity-header fields present in | ||
1157 | // the message. | ||
1158 | // 2.If a Transfer-Encoding header field (section 14.41) is present and | ||
1159 | // has any value other than "identity", then the transfer-length is | ||
1160 | // defined by use of the "chunked" transfer-coding (section 3.6), | ||
1161 | // unless the message is terminated by closing the connection. | ||
1162 | // 3.If a Content-Length header field (section 14.13) is present, its | ||
1163 | // decimal value in OCTETs represents both the entity-length and the | ||
1164 | // transfer-length. The Content-Length header field MUST NOT be sent | ||
1165 | // if these two lengths are different (i.e., if a Transfer-Encoding | ||
1166 | // header field is present). If a message is received with both a | ||
1167 | // Transfer-Encoding header field and a Content-Length header field, | ||
1168 | // the latter MUST be ignored. | ||
1169 | // 4.If the message uses the media type "multipart/byteranges" ... | ||
1170 | // 5.By the server closing the connection. | ||
1171 | // | ||
1172 | // (NB: standards do not define "Transfer-Length:" _header_, | ||
1173 | // transfer-length above is just a concept). | ||
1174 | |||
1153 | len += sprintf(iobuf + len, | 1175 | len += sprintf(iobuf + len, |
1154 | #if ENABLE_FEATURE_HTTPD_RANGES | 1176 | #if ENABLE_FEATURE_HTTPD_RANGES |
1155 | "Accept-Ranges: bytes\r\n" | 1177 | "Accept-Ranges: bytes\r\n" |
1156 | #endif | 1178 | #endif |
1157 | "Last-Modified: %s\r\n" | 1179 | "Last-Modified: %s\r\n" |
1158 | "%s-Length: %"OFF_FMT"u\r\n", | 1180 | /* Because of 4.4 (5), we can forgo sending of "Content-Length" |
1181 | * since we close connection afterwards, but it helps clients | ||
1182 | * to e.g. estimate download times, show progress bars etc. | ||
1183 | * Theoretically we should not send it if page is compressed, | ||
1184 | * but de-facto standard is to send it (see comment below). | ||
1185 | */ | ||
1186 | "Content-Length: %"OFF_FMT"u\r\n", | ||
1159 | date_str, | 1187 | date_str, |
1160 | content_gzip ? "Transfer" : "Content", | ||
1161 | file_size | 1188 | file_size |
1162 | ); | 1189 | ); |
1163 | } | 1190 | } |
1164 | 1191 | ||
1192 | /* This should be "Transfer-Encoding", not "Content-Encoding": | ||
1193 | * "data is compressed for transfer", not "data is an archive". | ||
1194 | * But many clients were not handling "Transfer-Encoding" correctly | ||
1195 | * (they were not uncompressing gzipped pages, tried to show | ||
1196 | * raw compressed data), and servers worked around it by using | ||
1197 | * "Content-Encoding" instead... and this become de-facto standard. | ||
1198 | * https://bugzilla.mozilla.org/show_bug.cgi?id=68517 | ||
1199 | * https://bugs.chromium.org/p/chromium/issues/detail?id=94730 | ||
1200 | */ | ||
1165 | if (content_gzip) | 1201 | if (content_gzip) |
1166 | len += sprintf(iobuf + len, "Content-Encoding: gzip\r\n"); | 1202 | len += sprintf(iobuf + len, "Content-Encoding: gzip\r\n"); |
1167 | 1203 | ||
@@ -1210,10 +1246,10 @@ static unsigned get_line(void) | |||
1210 | unsigned count; | 1246 | unsigned count; |
1211 | char c; | 1247 | char c; |
1212 | 1248 | ||
1213 | alarm(HEADER_READ_TIMEOUT); | ||
1214 | count = 0; | 1249 | count = 0; |
1215 | while (1) { | 1250 | while (1) { |
1216 | if (hdr_cnt <= 0) { | 1251 | if (hdr_cnt <= 0) { |
1252 | alarm(HEADER_READ_TIMEOUT); | ||
1217 | hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); | 1253 | hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); |
1218 | if (hdr_cnt <= 0) | 1254 | if (hdr_cnt <= 0) |
1219 | goto ret; | 1255 | goto ret; |
@@ -1370,10 +1406,10 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post | |||
1370 | * CGI may output a few first bytes and then wait | 1406 | * CGI may output a few first bytes and then wait |
1371 | * for POSTDATA without closing stdout. | 1407 | * for POSTDATA without closing stdout. |
1372 | * With full_read we may wait here forever. */ | 1408 | * With full_read we may wait here forever. */ |
1373 | count = safe_read(fromCgi_rd, rbuf + out_cnt, PIPE_BUF - 8); | 1409 | count = safe_read(fromCgi_rd, rbuf + out_cnt, IOBUF_SIZE - 8); |
1374 | if (count <= 0) { | 1410 | if (count <= 0) { |
1375 | /* eof (or error) and there was no "HTTP", | 1411 | /* eof (or error) and there was no "HTTP", |
1376 | * so write it, then write received data */ | 1412 | * send "HTTP/1.0 200 OK\r\n", then send received data */ |
1377 | if (out_cnt) { | 1413 | if (out_cnt) { |
1378 | full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1); | 1414 | full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1); |
1379 | full_write(STDOUT_FILENO, rbuf, out_cnt); | 1415 | full_write(STDOUT_FILENO, rbuf, out_cnt); |
@@ -1411,7 +1447,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post | |||
1411 | out_cnt = -1; /* buffering off */ | 1447 | out_cnt = -1; /* buffering off */ |
1412 | } | 1448 | } |
1413 | } else { | 1449 | } else { |
1414 | count = safe_read(fromCgi_rd, rbuf, PIPE_BUF); | 1450 | count = safe_read(fromCgi_rd, rbuf, IOBUF_SIZE); |
1415 | if (count <= 0) | 1451 | if (count <= 0) |
1416 | break; /* eof (or error) */ | 1452 | break; /* eof (or error) */ |
1417 | } | 1453 | } |
@@ -2085,7 +2121,6 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2085 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 2121 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
2086 | smallint authorized = -1; | 2122 | smallint authorized = -1; |
2087 | #endif | 2123 | #endif |
2088 | char http_major_version; | ||
2089 | char *HTTP_slash; | 2124 | char *HTTP_slash; |
2090 | 2125 | ||
2091 | /* Allocation of iobuf is postponed until now | 2126 | /* Allocation of iobuf is postponed until now |
@@ -2148,16 +2183,12 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2148 | if (urlp[0] != '/') | 2183 | if (urlp[0] != '/') |
2149 | send_headers_and_exit(HTTP_BAD_REQUEST); | 2184 | send_headers_and_exit(HTTP_BAD_REQUEST); |
2150 | 2185 | ||
2151 | /* Find end of URL and parse HTTP version, if any */ | 2186 | /* Find end of URL */ |
2152 | //TODO: maybe just reject all queries which have no " HTTP/xyz" suffix? | 2187 | HTTP_slash = strchr(urlp, ' '); |
2153 | //Then 'http_major_version' can be deleted | ||
2154 | http_major_version = ('0' - 1); /* "less than 0th" version */ | ||
2155 | HTTP_slash = strchrnul(urlp, ' '); | ||
2156 | /* Is it " HTTP/"? */ | 2188 | /* Is it " HTTP/"? */ |
2157 | if (HTTP_slash[0] && strncmp(HTTP_slash + 1, HTTP_200, 5) == 0) { | 2189 | if (!HTTP_slash || strncmp(HTTP_slash + 1, HTTP_200, 5) != 0) |
2158 | http_major_version = HTTP_slash[6]; | 2190 | send_headers_and_exit(HTTP_BAD_REQUEST); |
2159 | *HTTP_slash++ = '\0'; | 2191 | *HTTP_slash++ = '\0'; |
2160 | } | ||
2161 | 2192 | ||
2162 | /* Copy URL from after "GET "/"POST " to stack-allocated char[] */ | 2193 | /* Copy URL from after "GET "/"POST " to stack-allocated char[] */ |
2163 | urlcopy = alloca((HTTP_slash - urlp) + 2 + strlen(index_page)); | 2194 | urlcopy = alloca((HTTP_slash - urlp) + 2 + strlen(index_page)); |
@@ -2173,6 +2204,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2173 | Htaccess_Proxy *proxy_entry = find_proxy_entry(urlcopy); | 2204 | Htaccess_Proxy *proxy_entry = find_proxy_entry(urlcopy); |
2174 | 2205 | ||
2175 | if (proxy_entry) { | 2206 | if (proxy_entry) { |
2207 | if (verbose > 1) | ||
2208 | bb_error_msg("proxy:%s", urlcopy); | ||
2176 | lsa = host2sockaddr(proxy_entry->host_port, 80); | 2209 | lsa = host2sockaddr(proxy_entry->host_port, 80); |
2177 | if (!lsa) | 2210 | if (!lsa) |
2178 | send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); | 2211 | send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); |
@@ -2181,6 +2214,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2181 | send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); | 2214 | send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); |
2182 | if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0) | 2215 | if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0) |
2183 | send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); | 2216 | send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); |
2217 | /* Disable peer header reading timeout */ | ||
2218 | alarm(0); | ||
2184 | /* Config directive was of the form: | 2219 | /* Config directive was of the form: |
2185 | * P:/url:[http://]hostname[:port]/new/path | 2220 | * P:/url:[http://]hostname[:port]/new/path |
2186 | * When /urlSFX is requested, reverse proxy it | 2221 | * When /urlSFX is requested, reverse proxy it |
@@ -2190,7 +2225,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2190 | prequest, /* "GET" or "POST" */ | 2225 | prequest, /* "GET" or "POST" */ |
2191 | proxy_entry->url_to, /* "/new/path" */ | 2226 | proxy_entry->url_to, /* "/new/path" */ |
2192 | urlcopy + strlen(proxy_entry->url_from), /* "SFX" */ | 2227 | urlcopy + strlen(proxy_entry->url_from), /* "SFX" */ |
2193 | HTTP_slash /* HTTP/xyz" or "" */ | 2228 | HTTP_slash /* "HTTP/xyz" */ |
2194 | ); | 2229 | ); |
2195 | cgi_io_loop_and_exit(proxy_fd, proxy_fd, /*max POST length:*/ INT_MAX); | 2230 | cgi_io_loop_and_exit(proxy_fd, proxy_fd, /*max POST length:*/ INT_MAX); |
2196 | } | 2231 | } |
@@ -2323,125 +2358,122 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2323 | #if ENABLE_FEATURE_HTTPD_CGI | 2358 | #if ENABLE_FEATURE_HTTPD_CGI |
2324 | total_headers_len = 0; | 2359 | total_headers_len = 0; |
2325 | #endif | 2360 | #endif |
2326 | if (http_major_version >= '0') { | ||
2327 | /* Request was with "... HTTP/nXXX", and n >= 0 */ | ||
2328 | 2361 | ||
2329 | /* Read until blank line */ | 2362 | /* Read until blank line */ |
2330 | while (1) { | 2363 | while (1) { |
2331 | unsigned iobuf_len = get_line(); | 2364 | unsigned iobuf_len = get_line(); |
2332 | if (!iobuf_len) | 2365 | if (!iobuf_len) |
2333 | break; /* EOF or error or empty line */ | 2366 | break; /* EOF or error or empty line */ |
2334 | #if ENABLE_FEATURE_HTTPD_CGI | 2367 | #if ENABLE_FEATURE_HTTPD_CGI |
2335 | /* Prevent unlimited growth of HTTP_xyz envvars */ | 2368 | /* Prevent unlimited growth of HTTP_xyz envvars */ |
2336 | total_headers_len += iobuf_len; | 2369 | total_headers_len += iobuf_len; |
2337 | if (total_headers_len >= MAX_HTTP_HEADERS_SIZE) | 2370 | if (total_headers_len >= MAX_HTTP_HEADERS_SIZE) |
2338 | send_headers_and_exit(HTTP_ENTITY_TOO_LARGE); | 2371 | send_headers_and_exit(HTTP_ENTITY_TOO_LARGE); |
2339 | #endif | 2372 | #endif |
2340 | if (DEBUG) | 2373 | if (DEBUG) |
2341 | bb_error_msg("header: '%s'", iobuf); | 2374 | bb_error_msg("header: '%s'", iobuf); |
2342 | #if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY | 2375 | #if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY |
2343 | /* Try and do our best to parse more lines */ | 2376 | /* Try and do our best to parse more lines */ |
2344 | if ((STRNCASECMP(iobuf, "Content-Length:") == 0)) { | 2377 | if (STRNCASECMP(iobuf, "Content-Length:") == 0) { |
2345 | /* extra read only for POST */ | 2378 | /* extra read only for POST */ |
2346 | if (prequest != request_GET | 2379 | if (prequest != request_GET |
2347 | # if ENABLE_FEATURE_HTTPD_CGI | 2380 | # if ENABLE_FEATURE_HTTPD_CGI |
2348 | && prequest != request_HEAD | 2381 | && prequest != request_HEAD |
2349 | # endif | 2382 | # endif |
2350 | ) { | 2383 | ) { |
2351 | tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1); | 2384 | tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1); |
2352 | if (!tptr[0]) | 2385 | if (!tptr[0]) |
2353 | send_headers_and_exit(HTTP_BAD_REQUEST); | 2386 | send_headers_and_exit(HTTP_BAD_REQUEST); |
2354 | /* not using strtoul: it ignores leading minus! */ | 2387 | /* not using strtoul: it ignores leading minus! */ |
2355 | length = bb_strtou(tptr, NULL, 10); | 2388 | length = bb_strtou(tptr, NULL, 10); |
2356 | /* length is "ulong", but we need to pass it to int later */ | 2389 | /* length is "ulong", but we need to pass it to int later */ |
2357 | if (errno || length > INT_MAX) | 2390 | if (errno || length > INT_MAX) |
2358 | send_headers_and_exit(HTTP_BAD_REQUEST); | 2391 | send_headers_and_exit(HTTP_BAD_REQUEST); |
2359 | } | ||
2360 | continue; | ||
2361 | } | 2392 | } |
2393 | continue; | ||
2394 | } | ||
2362 | #endif | 2395 | #endif |
2363 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 2396 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
2364 | if (STRNCASECMP(iobuf, "Authorization:") == 0) { | 2397 | if (STRNCASECMP(iobuf, "Authorization:") == 0) { |
2365 | /* We only allow Basic credentials. | 2398 | /* We only allow Basic credentials. |
2366 | * It shows up as "Authorization: Basic <user>:<passwd>" where | 2399 | * It shows up as "Authorization: Basic <user>:<passwd>" where |
2367 | * "<user>:<passwd>" is base64 encoded. | 2400 | * "<user>:<passwd>" is base64 encoded. |
2368 | */ | 2401 | */ |
2369 | tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1); | 2402 | tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1); |
2370 | if (STRNCASECMP(tptr, "Basic") != 0) | 2403 | if (STRNCASECMP(tptr, "Basic") == 0) { |
2371 | continue; | ||
2372 | tptr += sizeof("Basic")-1; | 2404 | tptr += sizeof("Basic")-1; |
2373 | /* decodeBase64() skips whitespace itself */ | 2405 | /* decodeBase64() skips whitespace itself */ |
2374 | decodeBase64(tptr); | 2406 | decodeBase64(tptr); |
2375 | authorized = check_user_passwd(urlcopy, tptr); | 2407 | authorized = check_user_passwd(urlcopy, tptr); |
2376 | continue; | 2408 | continue; |
2377 | } | 2409 | } |
2410 | } | ||
2378 | #endif | 2411 | #endif |
2379 | #if ENABLE_FEATURE_HTTPD_RANGES | 2412 | #if ENABLE_FEATURE_HTTPD_RANGES |
2380 | if (STRNCASECMP(iobuf, "Range:") == 0) { | 2413 | if (STRNCASECMP(iobuf, "Range:") == 0) { |
2381 | /* We know only bytes=NNN-[MMM] */ | 2414 | /* We know only bytes=NNN-[MMM] */ |
2382 | char *s = skip_whitespace(iobuf + sizeof("Range:")-1); | 2415 | char *s = skip_whitespace(iobuf + sizeof("Range:")-1); |
2383 | if (is_prefixed_with(s, "bytes=")) { | 2416 | if (is_prefixed_with(s, "bytes=")) { |
2384 | s += sizeof("bytes=")-1; | 2417 | s += sizeof("bytes=")-1; |
2385 | range_start = BB_STRTOOFF(s, &s, 10); | 2418 | range_start = BB_STRTOOFF(s, &s, 10); |
2386 | if (s[0] != '-' || range_start < 0) { | 2419 | if (s[0] != '-' || range_start < 0) { |
2420 | range_start = -1; | ||
2421 | } else if (s[1]) { | ||
2422 | range_end = BB_STRTOOFF(s+1, NULL, 10); | ||
2423 | if (errno || range_end < range_start) | ||
2387 | range_start = -1; | 2424 | range_start = -1; |
2388 | } else if (s[1]) { | ||
2389 | range_end = BB_STRTOOFF(s+1, NULL, 10); | ||
2390 | if (errno || range_end < range_start) | ||
2391 | range_start = -1; | ||
2392 | } | ||
2393 | } | 2425 | } |
2394 | continue; | ||
2395 | } | 2426 | } |
2427 | continue; | ||
2428 | } | ||
2396 | #endif | 2429 | #endif |
2397 | #if ENABLE_FEATURE_HTTPD_GZIP | 2430 | #if ENABLE_FEATURE_HTTPD_GZIP |
2398 | if (STRNCASECMP(iobuf, "Accept-Encoding:") == 0) { | 2431 | if (STRNCASECMP(iobuf, "Accept-Encoding:") == 0) { |
2399 | /* Note: we do not support "gzip;q=0" | 2432 | /* Note: we do not support "gzip;q=0" |
2400 | * method of _disabling_ gzip | 2433 | * method of _disabling_ gzip |
2401 | * delivery. No one uses that, though */ | 2434 | * delivery. No one uses that, though */ |
2402 | const char *s = strstr(iobuf, "gzip"); | 2435 | const char *s = strstr(iobuf, "gzip"); |
2403 | if (s) { | 2436 | if (s) { |
2404 | // want more thorough checks? | 2437 | // want more thorough checks? |
2405 | //if (s[-1] == ' ' | 2438 | //if (s[-1] == ' ' |
2406 | // || s[-1] == ',' | 2439 | // || s[-1] == ',' |
2407 | // || s[-1] == ':' | 2440 | // || s[-1] == ':' |
2408 | //) { | 2441 | //) { |
2409 | content_gzip = 1; | 2442 | content_gzip = 1; |
2410 | //} | 2443 | //} |
2411 | } | ||
2412 | continue; | ||
2413 | } | 2444 | } |
2445 | continue; | ||
2446 | } | ||
2414 | #endif | 2447 | #endif |
2415 | #if ENABLE_FEATURE_HTTPD_CGI | 2448 | #if ENABLE_FEATURE_HTTPD_CGI |
2416 | if (cgi_type != CGI_NONE) { | 2449 | if (cgi_type != CGI_NONE) { |
2417 | bool ct = (STRNCASECMP(iobuf, "Content-Type:") == 0); | 2450 | bool ct = (STRNCASECMP(iobuf, "Content-Type:") == 0); |
2418 | char *cp; | 2451 | char *cp; |
2419 | char *colon = strchr(iobuf, ':'); | 2452 | char *colon = strchr(iobuf, ':'); |
2420 | 2453 | ||
2421 | if (!colon) | 2454 | if (!colon) |
2455 | continue; | ||
2456 | cp = iobuf; | ||
2457 | while (cp < colon) { | ||
2458 | /* a-z => A-Z, not-alnum => _ */ | ||
2459 | char c = (*cp & ~0x20); /* toupper for A-Za-z, undef for others */ | ||
2460 | if ((unsigned)(c - 'A') <= ('Z' - 'A')) { | ||
2461 | *cp++ = c; | ||
2422 | continue; | 2462 | continue; |
2423 | cp = iobuf; | ||
2424 | while (cp < colon) { | ||
2425 | /* a-z => A-Z, not-alnum => _ */ | ||
2426 | char c = (*cp & ~0x20); /* toupper for A-Za-z, undef for others */ | ||
2427 | if ((unsigned)(c - 'A') <= ('Z' - 'A')) { | ||
2428 | *cp++ = c; | ||
2429 | continue; | ||
2430 | } | ||
2431 | if (!isdigit(*cp)) | ||
2432 | *cp = '_'; | ||
2433 | cp++; | ||
2434 | } | 2463 | } |
2435 | /* "Content-Type:" gets no HTTP_ prefix, all others do */ | 2464 | if (!isdigit(*cp)) |
2436 | cp = xasprintf(ct ? "HTTP_%.*s=%s" + 5 : "HTTP_%.*s=%s", | 2465 | *cp = '_'; |
2437 | (int)(colon - iobuf), iobuf, | 2466 | cp++; |
2438 | skip_whitespace(colon + 1) | ||
2439 | ); | ||
2440 | putenv(cp); | ||
2441 | } | 2467 | } |
2468 | /* "Content-Type:" gets no HTTP_ prefix, all others do */ | ||
2469 | cp = xasprintf(ct ? "HTTP_%.*s=%s" + 5 : "HTTP_%.*s=%s", | ||
2470 | (int)(colon - iobuf), iobuf, | ||
2471 | skip_whitespace(colon + 1) | ||
2472 | ); | ||
2473 | putenv(cp); | ||
2474 | } | ||
2442 | #endif | 2475 | #endif |
2443 | } /* while extra header reading */ | 2476 | } /* while extra header reading */ |
2444 | } | ||
2445 | 2477 | ||
2446 | /* We are done reading headers, disable peer timeout */ | 2478 | /* We are done reading headers, disable peer timeout */ |
2447 | alarm(0); | 2479 | alarm(0); |
diff --git a/shell/ash.c b/shell/ash.c index ad7b8f4dd..b82c51029 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -13747,6 +13747,10 @@ expandstr(const char *ps, int syntax_type) | |||
13747 | { | 13747 | { |
13748 | union node n; | 13748 | union node n; |
13749 | int saveprompt; | 13749 | int saveprompt; |
13750 | struct parsefile *file_stop = g_parsefile; | ||
13751 | volatile int saveint; | ||
13752 | struct jmploc *volatile savehandler = exception_handler; | ||
13753 | struct jmploc jmploc; | ||
13750 | 13754 | ||
13751 | /* XXX Fix (char *) cast. */ | 13755 | /* XXX Fix (char *) cast. */ |
13752 | setinputstring((char *)ps); | 13756 | setinputstring((char *)ps); |
@@ -13758,29 +13762,35 @@ expandstr(const char *ps, int syntax_type) | |||
13758 | * Try a prompt with syntactically wrong command: | 13762 | * Try a prompt with syntactically wrong command: |
13759 | * PS1='$(date "+%H:%M:%S) > ' | 13763 | * PS1='$(date "+%H:%M:%S) > ' |
13760 | */ | 13764 | */ |
13761 | { | 13765 | SAVE_INT(saveint); |
13762 | volatile int saveint; | 13766 | if (setjmp(jmploc.loc) == 0) { |
13763 | struct jmploc *volatile savehandler = exception_handler; | 13767 | exception_handler = &jmploc; |
13764 | struct jmploc jmploc; | 13768 | readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); |
13765 | SAVE_INT(saveint); | ||
13766 | if (setjmp(jmploc.loc) == 0) { | ||
13767 | exception_handler = &jmploc; | ||
13768 | readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); | ||
13769 | } | ||
13770 | exception_handler = savehandler; | ||
13771 | RESTORE_INT(saveint); | ||
13772 | } | 13769 | } |
13770 | exception_handler = savehandler; | ||
13771 | RESTORE_INT(saveint); | ||
13773 | 13772 | ||
13774 | doprompt = saveprompt; | 13773 | doprompt = saveprompt; |
13775 | 13774 | ||
13776 | popfile(); | 13775 | /* Try: PS1='`xxx(`' */ |
13776 | unwindfiles(file_stop); | ||
13777 | 13777 | ||
13778 | n.narg.type = NARG; | 13778 | n.narg.type = NARG; |
13779 | n.narg.next = NULL; | 13779 | n.narg.next = NULL; |
13780 | n.narg.text = wordtext; | 13780 | n.narg.text = wordtext; |
13781 | n.narg.backquote = backquotelist; | 13781 | n.narg.backquote = backquotelist; |
13782 | 13782 | ||
13783 | expandarg(&n, NULL, EXP_QUOTED); | 13783 | /* expandarg() might fail too: |
13784 | * PS1='$((123+))' | ||
13785 | */ | ||
13786 | SAVE_INT(saveint); | ||
13787 | if (setjmp(jmploc.loc) == 0) { | ||
13788 | exception_handler = &jmploc; | ||
13789 | expandarg(&n, NULL, EXP_QUOTED); | ||
13790 | } | ||
13791 | exception_handler = savehandler; | ||
13792 | RESTORE_INT(saveint); | ||
13793 | |||
13784 | return stackblock(); | 13794 | return stackblock(); |
13785 | } | 13795 | } |
13786 | 13796 | ||
diff --git a/shell/hush.c b/shell/hush.c index d745148f4..b3ae73b9b 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -363,9 +363,6 @@ | |||
363 | #ifndef F_DUPFD_CLOEXEC | 363 | #ifndef F_DUPFD_CLOEXEC |
364 | # define F_DUPFD_CLOEXEC F_DUPFD | 364 | # define F_DUPFD_CLOEXEC F_DUPFD |
365 | #endif | 365 | #endif |
366 | #ifndef PIPE_BUF | ||
367 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ | ||
368 | #endif | ||
369 | 366 | ||
370 | #if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !(ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH) | 367 | #if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !(ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH) |
371 | # include "embedded_scripts.h" | 368 | # include "embedded_scripts.h" |
diff --git a/testsuite/dc.tests b/testsuite/dc.tests index 1708a4835..8c3af4156 100755 --- a/testsuite/dc.tests +++ b/testsuite/dc.tests | |||
@@ -41,6 +41,9 @@ testing "dc complex without spaces (multiple args)" \ | |||
41 | "16\n" \ | 41 | "16\n" \ |
42 | "" "" | 42 | "" "" |
43 | 43 | ||
44 | optional FEATURE_DC_BIG | ||
45 | # All tests below depend on FEATURE_DC_BIG | ||
46 | |||
44 | testing "dc read" \ | 47 | testing "dc read" \ |
45 | "dc -finput" \ | 48 | "dc -finput" \ |
46 | "2\n9\n1\n" \ | 49 | "2\n9\n1\n" \ |
@@ -51,9 +54,6 @@ testing "dc read string" \ | |||
51 | "2\nstr\n1\n" \ | 54 | "2\nstr\n1\n" \ |
52 | "1?2\nf" "[str]\n" | 55 | "1?2\nf" "[str]\n" |
53 | 56 | ||
54 | optional FEATURE_DC_BIG | ||
55 | # All tests below depend on FEATURE_DC_BIG | ||
56 | |||
57 | testing "dc '>a' (conditional execute string) 1" \ | 57 | testing "dc '>a' (conditional execute string) 1" \ |
58 | "dc" \ | 58 | "dc" \ |
59 | "1\n9\n" \ | 59 | "1\n9\n" \ |