From 210b52476c86fb8411f6b0fd12d4e76875c474e5 Mon Sep 17 00:00:00 2001 From: Alexander Vickberg Date: Wed, 17 Apr 2019 11:34:21 +0200 Subject: httpd: When sending gzipped content use content-length header Today for gzipped content httpd is using a header with name Transfer-Length. However I can't find a header with that name in the standards. Instead use Content-Length. function old new delta .rodata 157940 157936 -4 send_headers 980 939 -41 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-45) Total: -45 bytes Signed-off-by: Alexander Vickberg Signed-off-by: Denys Vlasenko --- networking/httpd.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index 2b0acd7dc..0f4f22669 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1150,18 +1150,61 @@ static void send_headers(unsigned responseNum) file_size = range_end - range_start + 1; } #endif + +//RFC 2616 4.4 Message Length +// The transfer-length of a message is the length of the message-body as +// it appears in the message; that is, after any transfer-codings have +// been applied. When a message-body is included with a message, the +// transfer-length of that body is determined by one of the following +// (in order of precedence): +// 1.Any response message which "MUST NOT" include a message-body (such +// as the 1xx, 204, and 304 responses and any response to a HEAD +// request) is always terminated by the first empty line after the +// header fields, regardless of the entity-header fields present in +// the message. +// 2.If a Transfer-Encoding header field (section 14.41) is present and +// has any value other than "identity", then the transfer-length is +// defined by use of the "chunked" transfer-coding (section 3.6), +// unless the message is terminated by closing the connection. +// 3.If a Content-Length header field (section 14.13) is present, its +// decimal value in OCTETs represents both the entity-length and the +// transfer-length. The Content-Length header field MUST NOT be sent +// if these two lengths are different (i.e., if a Transfer-Encoding +// header field is present). If a message is received with both a +// Transfer-Encoding header field and a Content-Length header field, +// the latter MUST be ignored. +// 4.If the message uses the media type "multipart/byteranges" ... +// 5.By the server closing the connection. +// +// (NB: standards do not define "Transfer-Length:" _header_, +// transfer-length above is just a concept). + len += sprintf(iobuf + len, #if ENABLE_FEATURE_HTTPD_RANGES "Accept-Ranges: bytes\r\n" #endif "Last-Modified: %s\r\n" - "%s-Length: %"OFF_FMT"u\r\n", + /* Because of 4.4 (5), we can forgo sending of "Content-Length" + * since we close connection afterwards, but it helps clients + * to e.g. estimate download times, show progress bars etc. + * Theoretically we should not send it if page is compressed, + * but de-facto standard is to send it (see comment below). + */ + "Content-Length: %"OFF_FMT"u\r\n", date_str, - content_gzip ? "Transfer" : "Content", file_size ); } + /* This should be "Transfer-Encoding", not "Content-Encoding": + * "data is compressed for transfer", not "data is an archive". + * But many clients were not handling "Transfer-Encoding" correctly + * (they were not uncompressing gzipped pages, tried to show + * raw compressed data), and servers worked around it by using + * "Content-Encoding" instead... and this become de-facto standard. + * https://bugzilla.mozilla.org/show_bug.cgi?id=68517 + * https://bugs.chromium.org/p/chromium/issues/detail?id=94730 + */ if (content_gzip) len += sprintf(iobuf + len, "Content-Encoding: gzip\r\n"); -- cgit v1.2.3-55-g6feb From 049670fbbe8022e0e38909aa3de189c06e34ad7d Mon Sep 17 00:00:00 2001 From: Alexander Vickberg Date: Thu, 18 Apr 2019 10:05:53 +0200 Subject: httpd: pass authorization header to CGI if not Basic Pass the Authorization header to CGI if not of type Basic. This will make it possible for CGI to verify authorization headers of type Bearer . function old new delta handle_incoming_and_exit 2370 2379 +9 Signed-off-by: Alexander Vickberg Signed-off-by: Denys Vlasenko --- networking/httpd.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index 0f4f22669..0b5d2b481 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2384,7 +2384,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) bb_error_msg("header: '%s'", iobuf); #if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY /* Try and do our best to parse more lines */ - if ((STRNCASECMP(iobuf, "Content-Length:") == 0)) { + if (STRNCASECMP(iobuf, "Content-Length:") == 0) { /* extra read only for POST */ if (prequest != request_GET # if ENABLE_FEATURE_HTTPD_CGI @@ -2410,13 +2410,13 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) * ":" is base64 encoded. */ tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1); - if (STRNCASECMP(tptr, "Basic") != 0) + if (STRNCASECMP(tptr, "Basic") == 0) { + tptr += sizeof("Basic")-1; + /* decodeBase64() skips whitespace itself */ + decodeBase64(tptr); + authorized = check_user_passwd(urlcopy, tptr); continue; - tptr += sizeof("Basic")-1; - /* decodeBase64() skips whitespace itself */ - decodeBase64(tptr); - authorized = check_user_passwd(urlcopy, tptr); - continue; + } } #endif #if ENABLE_FEATURE_HTTPD_RANGES -- cgit v1.2.3-55-g6feb From 32c8ce4def177a98a9aef0896bdb2d8262b364ec Mon Sep 17 00:00:00 2001 From: Chen Qi Date: Wed, 17 Apr 2019 09:39:25 +0800 Subject: dc.tests: fix two test case to also depend on DC_BIG Signed-off-by: Chen Qi Signed-off-by: Denys Vlasenko --- testsuite/dc.tests | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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)" \ "16\n" \ "" "" +optional FEATURE_DC_BIG +# All tests below depend on FEATURE_DC_BIG + testing "dc read" \ "dc -finput" \ "2\n9\n1\n" \ @@ -51,9 +54,6 @@ testing "dc read string" \ "2\nstr\n1\n" \ "1?2\nf" "[str]\n" -optional FEATURE_DC_BIG -# All tests below depend on FEATURE_DC_BIG - testing "dc '>a' (conditional execute string) 1" \ "dc" \ "1\n9\n" \ -- cgit v1.2.3-55-g6feb From 48645b83502a5add5429b6cbb19cf3a083f1adf4 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 18 Apr 2019 09:48:13 +0100 Subject: ash: prevent error in backquotes in PS1 from exiting shell Setting PS1 to: PS1='`xxx(`' causes the shell to terminate with the error: sh: syntax error: unexpected end of file (expecting ")") This happens because old-style backquotes require the input to be reread and thus call setinputstring() a second time. Prevent the problem by unwinding all recently opened files in expandstr(). function old new delta unwindfiles - 22 +22 expandstr 247 262 +15 forkchild 631 625 -6 evalcommand 1694 1685 -9 ash_main 1346 1336 -10 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/3 up/down: 37/-25) Total: 12 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index b707d00d0..f3a2c6952 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13042,6 +13042,7 @@ expandstr(const char *ps, int syntax_type) { union node n; int saveprompt; + struct parsefile *file_stop = g_parsefile; /* XXX Fix (char *) cast. */ setinputstring((char *)ps); @@ -13068,7 +13069,8 @@ expandstr(const char *ps, int syntax_type) doprompt = saveprompt; - popfile(); + /* Try: PS1='`xxx(`' */ + unwindfiles(file_stop); n.narg.type = NARG; n.narg.next = NULL; -- cgit v1.2.3-55-g6feb From d1a2fa2a4e013960bf56dfef8a71ed2d08fc756b Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 18 Apr 2019 09:49:13 +0100 Subject: ash: catch error in arithmetic expansion in PS1 Setting PS1 to: PS1='$((123+))' causes the shell to enter an infinite error loop: sh: arithmetic syntax error Catch any exception raised by expandarg() in expandstr() and allow processing to continue. function old new delta expandstr 262 344 +82 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 82/0) Total: 82 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index f3a2c6952..924e17f32 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13043,6 +13043,9 @@ expandstr(const char *ps, int syntax_type) union node n; int saveprompt; struct parsefile *file_stop = g_parsefile; + volatile int saveint; + struct jmploc *volatile savehandler = exception_handler; + struct jmploc jmploc; /* XXX Fix (char *) cast. */ setinputstring((char *)ps); @@ -13054,18 +13057,13 @@ expandstr(const char *ps, int syntax_type) * Try a prompt with syntactically wrong command: * PS1='$(date "+%H:%M:%S) > ' */ - { - volatile int saveint; - struct jmploc *volatile savehandler = exception_handler; - struct jmploc jmploc; - SAVE_INT(saveint); - if (setjmp(jmploc.loc) == 0) { - exception_handler = &jmploc; - readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); - } - exception_handler = savehandler; - RESTORE_INT(saveint); + SAVE_INT(saveint); + if (setjmp(jmploc.loc) == 0) { + exception_handler = &jmploc; + readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); } + exception_handler = savehandler; + RESTORE_INT(saveint); doprompt = saveprompt; @@ -13077,7 +13075,17 @@ expandstr(const char *ps, int syntax_type) n.narg.text = wordtext; n.narg.backquote = backquotelist; - expandarg(&n, NULL, EXP_QUOTED); + /* expandarg() might fail too: + * PS1='$((123+))' + */ + SAVE_INT(saveint); + if (setjmp(jmploc.loc) == 0) { + exception_handler = &jmploc; + expandarg(&n, NULL, EXP_QUOTED); + } + exception_handler = savehandler; + RESTORE_INT(saveint); + return stackblock(); } -- cgit v1.2.3-55-g6feb From ad29ba73ee00d4c78b3ab85a6b943a8c63075f50 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 19 Apr 2019 13:59:58 +0200 Subject: httpd: require "HTTP/xyz" at the end of request line function old new delta handle_incoming_and_exit 2379 2362 -17 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-17) Total: -17 bytes text data bss dec hex filename 981787 485 7296 989568 f1980 busybox_old 981779 485 7296 989560 f1978 busybox_unstripped Signed-off-by: Denys Vlasenko --- networking/httpd.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index 0b5d2b481..f8a1e2556 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2128,7 +2128,6 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) #if ENABLE_FEATURE_HTTPD_BASIC_AUTH smallint authorized = -1; #endif - char http_major_version; char *HTTP_slash; /* Allocation of iobuf is postponed until now @@ -2191,16 +2190,12 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) if (urlp[0] != '/') send_headers_and_exit(HTTP_BAD_REQUEST); - /* Find end of URL and parse HTTP version, if any */ -//TODO: maybe just reject all queries which have no " HTTP/xyz" suffix? -//Then 'http_major_version' can be deleted - http_major_version = ('0' - 1); /* "less than 0th" version */ - HTTP_slash = strchrnul(urlp, ' '); + /* Find end of URL */ + HTTP_slash = strchr(urlp, ' '); /* Is it " HTTP/"? */ - if (HTTP_slash[0] && strncmp(HTTP_slash + 1, HTTP_200, 5) == 0) { - http_major_version = HTTP_slash[6]; - *HTTP_slash++ = '\0'; - } + if (!HTTP_slash || strncmp(HTTP_slash + 1, HTTP_200, 5) != 0) + send_headers_and_exit(HTTP_BAD_REQUEST); + *HTTP_slash++ = '\0'; /* Copy URL from after "GET "/"POST " to stack-allocated char[] */ urlcopy = alloca((HTTP_slash - urlp) + 2 + strlen(index_page)); @@ -2216,6 +2211,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) Htaccess_Proxy *proxy_entry = find_proxy_entry(urlcopy); if (proxy_entry) { + if (verbose > 1) + bb_error_msg("proxy:%s", urlcopy); lsa = host2sockaddr(proxy_entry->host_port, 80); if (!lsa) send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); @@ -2233,7 +2230,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) prequest, /* "GET" or "POST" */ proxy_entry->url_to, /* "/new/path" */ urlcopy + strlen(proxy_entry->url_from), /* "SFX" */ - HTTP_slash /* HTTP/xyz" or "" */ + HTTP_slash /* "HTTP/xyz" */ ); cgi_io_loop_and_exit(proxy_fd, proxy_fd, /*max POST length:*/ INT_MAX); } @@ -2366,8 +2363,6 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) #if ENABLE_FEATURE_HTTPD_CGI total_headers_len = 0; #endif - if (http_major_version >= '0') { - /* Request was with "... HTTP/nXXX", and n >= 0 */ /* Read until blank line */ while (1) { @@ -2484,7 +2479,6 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) } #endif } /* while extra header reading */ - } /* We are done reading headers, disable peer timeout */ alarm(0); -- cgit v1.2.3-55-g6feb From bca888a73ef755e7fe52ac7aff5bd884f71d32f9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 19 Apr 2019 14:02:51 +0200 Subject: httpd: deindent code block, no code changes Signed-off-by: Denys Vlasenko --- networking/httpd.c | 182 ++++++++++++++++++++++++++--------------------------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index f8a1e2556..d06bc2776 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2364,121 +2364,121 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) total_headers_len = 0; #endif - /* Read until blank line */ - while (1) { - unsigned iobuf_len = get_line(); - if (!iobuf_len) - break; /* EOF or error or empty line */ + /* Read until blank line */ + while (1) { + unsigned iobuf_len = get_line(); + if (!iobuf_len) + break; /* EOF or error or empty line */ #if ENABLE_FEATURE_HTTPD_CGI - /* Prevent unlimited growth of HTTP_xyz envvars */ - total_headers_len += iobuf_len; - if (total_headers_len >= MAX_HTTP_HEADERS_SIZE) - send_headers_and_exit(HTTP_ENTITY_TOO_LARGE); + /* Prevent unlimited growth of HTTP_xyz envvars */ + total_headers_len += iobuf_len; + if (total_headers_len >= MAX_HTTP_HEADERS_SIZE) + send_headers_and_exit(HTTP_ENTITY_TOO_LARGE); #endif - if (DEBUG) - bb_error_msg("header: '%s'", iobuf); + if (DEBUG) + bb_error_msg("header: '%s'", iobuf); #if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY - /* Try and do our best to parse more lines */ - if (STRNCASECMP(iobuf, "Content-Length:") == 0) { - /* extra read only for POST */ - if (prequest != request_GET + /* Try and do our best to parse more lines */ + if (STRNCASECMP(iobuf, "Content-Length:") == 0) { + /* extra read only for POST */ + if (prequest != request_GET # if ENABLE_FEATURE_HTTPD_CGI - && prequest != request_HEAD + && prequest != request_HEAD # endif - ) { - tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1); - if (!tptr[0]) - send_headers_and_exit(HTTP_BAD_REQUEST); - /* not using strtoul: it ignores leading minus! */ - length = bb_strtou(tptr, NULL, 10); - /* length is "ulong", but we need to pass it to int later */ - if (errno || length > INT_MAX) - send_headers_and_exit(HTTP_BAD_REQUEST); - } - continue; + ) { + tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1); + if (!tptr[0]) + send_headers_and_exit(HTTP_BAD_REQUEST); + /* not using strtoul: it ignores leading minus! */ + length = bb_strtou(tptr, NULL, 10); + /* length is "ulong", but we need to pass it to int later */ + if (errno || length > INT_MAX) + send_headers_and_exit(HTTP_BAD_REQUEST); } + continue; + } #endif #if ENABLE_FEATURE_HTTPD_BASIC_AUTH - if (STRNCASECMP(iobuf, "Authorization:") == 0) { - /* We only allow Basic credentials. - * It shows up as "Authorization: Basic :" where - * ":" is base64 encoded. - */ - tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1); - if (STRNCASECMP(tptr, "Basic") == 0) { - tptr += sizeof("Basic")-1; - /* decodeBase64() skips whitespace itself */ - decodeBase64(tptr); - authorized = check_user_passwd(urlcopy, tptr); - continue; - } + if (STRNCASECMP(iobuf, "Authorization:") == 0) { + /* We only allow Basic credentials. + * It shows up as "Authorization: Basic :" where + * ":" is base64 encoded. + */ + tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1); + if (STRNCASECMP(tptr, "Basic") == 0) { + tptr += sizeof("Basic")-1; + /* decodeBase64() skips whitespace itself */ + decodeBase64(tptr); + authorized = check_user_passwd(urlcopy, tptr); + continue; } + } #endif #if ENABLE_FEATURE_HTTPD_RANGES - if (STRNCASECMP(iobuf, "Range:") == 0) { - /* We know only bytes=NNN-[MMM] */ - char *s = skip_whitespace(iobuf + sizeof("Range:")-1); - if (is_prefixed_with(s, "bytes=")) { - s += sizeof("bytes=")-1; - range_start = BB_STRTOOFF(s, &s, 10); - if (s[0] != '-' || range_start < 0) { + if (STRNCASECMP(iobuf, "Range:") == 0) { + /* We know only bytes=NNN-[MMM] */ + char *s = skip_whitespace(iobuf + sizeof("Range:")-1); + if (is_prefixed_with(s, "bytes=")) { + s += sizeof("bytes=")-1; + range_start = BB_STRTOOFF(s, &s, 10); + if (s[0] != '-' || range_start < 0) { + range_start = -1; + } else if (s[1]) { + range_end = BB_STRTOOFF(s+1, NULL, 10); + if (errno || range_end < range_start) range_start = -1; - } else if (s[1]) { - range_end = BB_STRTOOFF(s+1, NULL, 10); - if (errno || range_end < range_start) - range_start = -1; - } } - continue; } + continue; + } #endif #if ENABLE_FEATURE_HTTPD_GZIP - if (STRNCASECMP(iobuf, "Accept-Encoding:") == 0) { - /* Note: we do not support "gzip;q=0" - * method of _disabling_ gzip - * delivery. No one uses that, though */ - const char *s = strstr(iobuf, "gzip"); - if (s) { - // want more thorough checks? - //if (s[-1] == ' ' - // || s[-1] == ',' - // || s[-1] == ':' - //) { - content_gzip = 1; - //} - } - continue; + if (STRNCASECMP(iobuf, "Accept-Encoding:") == 0) { + /* Note: we do not support "gzip;q=0" + * method of _disabling_ gzip + * delivery. No one uses that, though */ + const char *s = strstr(iobuf, "gzip"); + if (s) { + // want more thorough checks? + //if (s[-1] == ' ' + // || s[-1] == ',' + // || s[-1] == ':' + //) { + content_gzip = 1; + //} } + continue; + } #endif #if ENABLE_FEATURE_HTTPD_CGI - if (cgi_type != CGI_NONE) { - bool ct = (STRNCASECMP(iobuf, "Content-Type:") == 0); - char *cp; - char *colon = strchr(iobuf, ':'); + if (cgi_type != CGI_NONE) { + bool ct = (STRNCASECMP(iobuf, "Content-Type:") == 0); + char *cp; + char *colon = strchr(iobuf, ':'); - if (!colon) + if (!colon) + continue; + cp = iobuf; + while (cp < colon) { + /* a-z => A-Z, not-alnum => _ */ + char c = (*cp & ~0x20); /* toupper for A-Za-z, undef for others */ + if ((unsigned)(c - 'A') <= ('Z' - 'A')) { + *cp++ = c; continue; - cp = iobuf; - while (cp < colon) { - /* a-z => A-Z, not-alnum => _ */ - char c = (*cp & ~0x20); /* toupper for A-Za-z, undef for others */ - if ((unsigned)(c - 'A') <= ('Z' - 'A')) { - *cp++ = c; - continue; - } - if (!isdigit(*cp)) - *cp = '_'; - cp++; } - /* "Content-Type:" gets no HTTP_ prefix, all others do */ - cp = xasprintf(ct ? "HTTP_%.*s=%s" + 5 : "HTTP_%.*s=%s", - (int)(colon - iobuf), iobuf, - skip_whitespace(colon + 1) - ); - putenv(cp); + if (!isdigit(*cp)) + *cp = '_'; + cp++; } + /* "Content-Type:" gets no HTTP_ prefix, all others do */ + cp = xasprintf(ct ? "HTTP_%.*s=%s" + 5 : "HTTP_%.*s=%s", + (int)(colon - iobuf), iobuf, + skip_whitespace(colon + 1) + ); + putenv(cp); + } #endif - } /* while extra header reading */ + } /* while extra header reading */ /* We are done reading headers, disable peer timeout */ alarm(0); -- cgit v1.2.3-55-g6feb From af6012a1a7dcfc8eb2321e3adaaae3a0778d5a15 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 19 Apr 2019 14:03:37 +0200 Subject: httpd: do not set alarm() timeout if we read cached header Signed-off-by: Denys Vlasenko --- networking/httpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/httpd.c b/networking/httpd.c index d06bc2776..aa8ce8dcb 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1253,10 +1253,10 @@ static unsigned get_line(void) unsigned count; char c; - alarm(HEADER_READ_TIMEOUT); count = 0; while (1) { if (hdr_cnt <= 0) { + alarm(HEADER_READ_TIMEOUT); hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); if (hdr_cnt <= 0) goto ret; -- cgit v1.2.3-55-g6feb From 1c356948f137d46872d6af17d586960517cf100a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 19 Apr 2019 14:19:41 +0200 Subject: httpd: use full size of iobuf[] when piping CGI data Signed-off-by: Denys Vlasenko --- networking/httpd.c | 15 ++++----------- shell/hush.c | 3 --- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index aa8ce8dcb..d44ec271a 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -259,18 +259,11 @@ #if ENABLE_FEATURE_USE_SENDFILE # include #endif -/* amount of buffering in a pipe */ -#ifndef PIPE_BUF -# define PIPE_BUF 4096 -#endif #define DEBUG 0 #define IOBUF_SIZE 8192 -#define MAX_HTTP_HEADERS_SIZE ((8*1024) - 16) -#if PIPE_BUF >= IOBUF_SIZE -# error "PIPE_BUF >= IOBUF_SIZE" -#endif +#define MAX_HTTP_HEADERS_SIZE (32*1024) #define HEADER_READ_TIMEOUT 60 @@ -1413,10 +1406,10 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post * CGI may output a few first bytes and then wait * for POSTDATA without closing stdout. * With full_read we may wait here forever. */ - count = safe_read(fromCgi_rd, rbuf + out_cnt, PIPE_BUF - 8); + count = safe_read(fromCgi_rd, rbuf + out_cnt, IOBUF_SIZE - 8); if (count <= 0) { /* eof (or error) and there was no "HTTP", - * so write it, then write received data */ + * send "HTTP/1.0 200 OK\r\n", then send received data */ if (out_cnt) { full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1); full_write(STDOUT_FILENO, rbuf, out_cnt); @@ -1454,7 +1447,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post out_cnt = -1; /* buffering off */ } } else { - count = safe_read(fromCgi_rd, rbuf, PIPE_BUF); + count = safe_read(fromCgi_rd, rbuf, IOBUF_SIZE); if (count <= 0) break; /* eof (or error) */ } 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 @@ #ifndef F_DUPFD_CLOEXEC # define F_DUPFD_CLOEXEC F_DUPFD #endif -#ifndef PIPE_BUF -# define PIPE_BUF 4096 /* amount of buffering in a pipe */ -#endif #if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !(ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH) # include "embedded_scripts.h" -- cgit v1.2.3-55-g6feb From e49a572b529dc7dcfb052c679074b9b87577e388 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 19 Apr 2019 14:24:57 +0200 Subject: httpd: do disable header reading timeout even if proxying function old new delta handle_incoming_and_exit 2362 2369 +7 Signed-off-by: Denys Vlasenko --- networking/httpd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/networking/httpd.c b/networking/httpd.c index d44ec271a..3f1e02ec8 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2214,6 +2214,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0) send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR); + /* Disable peer header reading timeout */ + alarm(0); /* Config directive was of the form: * P:/url:[http://]hostname[:port]/new/path * When /urlSFX is requested, reverse proxy it -- cgit v1.2.3-55-g6feb