From: Thomas Warburton <45946278+oopscentral@users.noreply.github.com> Date: Mon, 17 Dec 2018 14:23:18 +0000 (+0000) Subject: webui, htsbuf: Content-Disposition escape chars are not correct. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a11733fed0f74da5cb309aa624a7039918b21126;p=thirdparty%2Ftvheadend.git webui, htsbuf: Content-Disposition escape chars are not correct. When attempting to download a recording with a comma Google Chrome will fail with ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION. This is because the comma ',' in the filename*=UTF-8'' field was not escaped. This commit implements the defined list of non-escape characters from RFC8187 based on htsbuf_append_and_escape_url. The same problem occurs in issue #2086. Fixed in 2fdfe4836 "webui: fix the attachment; filename encoding, fixes #2086" and broken again in ab9fc249a "fix htsbuf_append_and_escape_url() - don't escape more allowed characters, fixes #3721". Only tested in release/4.2. https://bugs.chromium.org/p/chromium/issues/detail?id=454165 --- diff --git a/src/htsbuf.c b/src/htsbuf.c index 545eacdbe..50f22a500 100644 --- a/src/htsbuf.c +++ b/src/htsbuf.c @@ -447,6 +447,61 @@ htsbuf_append_and_escape_url(htsbuf_queue_t *hq, const char *s) } } +/** + * RFC8187 (RFC5987) HTTP Header non-ASCII field encoding + */ +void +htsbuf_append_and_escape_rfc8187(htsbuf_queue_t *hq, const char *s) +{ + const char *c = s; + const char *e = s + strlen(s); + char C; + if(e == s) + return; + + while(1) { + const char *esc; + char buf[4]; + C = *c++; + + /* RFC 8187, section 3.2.1, attr-char */ + if((C >= '0' && C <= '9') || + (C >= 'a' && C <= 'z') || + (C >= 'A' && C <= 'Z') || + C == '!' || + C == '#' || + C == '$' || + C == '&' || + C == '+' || + C == '-' || + C == '.' || + C == '^' || + C == '_' || + C == '`' || + C == '|' || + C == '~') { + esc = NULL; + } else { + static const char hexchars[16] = "0123456789ABCDEF"; + buf[0] = '%'; + buf[1] = hexchars[(C >> 4) & 0xf]; + buf[2] = hexchars[C & 0xf]; + buf[3] = 0; + esc = buf; + } + + if(esc != NULL) { + htsbuf_append(hq, s, c - s - 1); + htsbuf_append_str(hq, esc); + s = c; + } + + if(c == e) { + htsbuf_append(hq, s, c - s); + break; + } + } +} /** * diff --git a/src/htsbuf.h b/src/htsbuf.h index a770e2000..093299400 100644 --- a/src/htsbuf.h +++ b/src/htsbuf.h @@ -79,6 +79,8 @@ void htsbuf_append_and_escape_xml(htsbuf_queue_t *hq, const char *str); void htsbuf_append_and_escape_url(htsbuf_queue_t *hq, const char *s); +void htsbuf_append_and_escape_rfc8187(htsbuf_queue_t *hq, const char *s); + void htsbuf_append_and_escape_jsonstr(htsbuf_queue_t *hq, const char *s); void htsbuf_dump_raw_stderr(htsbuf_queue_t *hq); diff --git a/src/webui/webui.c b/src/webui/webui.c index 2d7d135e3..b7da55c4c 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -1705,7 +1705,7 @@ http_serve_file(http_connection_t *hc, const char *fname, return HTTP_STATUS_INTERNAL; } htsbuf_queue_init(&q, 0); - htsbuf_append_and_escape_url(&q, basename); + htsbuf_append_and_escape_rfc8187(&q, basename); str = htsbuf_to_string(&q); r = 50 + strlen(str0) + strlen(str); disposition = alloca(r);