]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
webui, htsbuf: Content-Disposition escape chars are not correct.
authorThomas Warburton <45946278+oopscentral@users.noreply.github.com>
Mon, 17 Dec 2018 14:23:18 +0000 (14:23 +0000)
committerJaroslav Kysela <perex@perex.cz>
Wed, 19 Dec 2018 14:09:59 +0000 (15:09 +0100)
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

src/htsbuf.c
src/htsbuf.h
src/webui/webui.c

index 545eacdbedc34333493ea2ee047f6b267038cef4..50f22a5006ba64d425af455b14c2bd1752986b46 100644 (file)
@@ -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;
+    }
+  }
+}
 
 /**
  *
index a770e2000b9d7175f72f18d398ad2f1cef397ed2..093299400c59ccb1fddddbb1eece4982e247626e 100644 (file)
@@ -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);
index 2d7d135e3db1e5efb5767c5c86118c4a0eb0b1c1..b7da55c4cd97fe4bc290fa306760d40acc2609b6 100644 (file)
@@ -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);