diff options
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Keep every control byte out of a header value
A quoted header value escaped only the quote, the backslash, CR and LF. A web server refuses a response whose header holds any other control byte, so a file named with one could not be downloaded at all.
Diffstat (limited to '')
-rw-r--r--source/html.c4
-rwxr-xr-xtests/t0105-plain.sh14
2 files changed, 18 insertions, 0 deletions
diff --git a/source/html.c b/source/html.c
index b6e62a6..d1e28f8 100644
--- a/source/html.c
+++ b/source/html.c
@@ -367,6 +367,10 @@ void html_header_arg_in_quotes(const char *txt)
esc = "\\n";
else if (c == '"')
esc = "\\\"";
+ // A header line carries no other control byte either, and a web
+ // server refuses the whole response over one.
+ else if (c < 0x20 || c == 0x7f)
+ esc = "?";
if (esc) {
html_raw(txt, p - txt);
html(esc);
diff --git a/tests/t0105-plain.sh b/tests/t0105-plain.sh
index 2e5513f..4615dc5 100755
--- a/tests/t0105-plain.sh
+++ b/tests/t0105-plain.sh
@@ -96,4 +96,18 @@ test_expect_success 'plain answers once for duplicate tree entries' '
grep "^Content-Type: image/png" tmp
'
+# A header line cannot carry a control byte, and a web server refuses the
+# whole response over one, so a file name holding one is sent with a stand-in.
+test_expect_success 'a control character in a file name stays out of the headers' '
+ (
+ cd repos/dup &&
+ blob=$(printf x | git hash-object -w --stdin) &&
+ top=$(printf "100644 blob %s\\tctl\\001name.txt\\n" $blob | git mktree) &&
+ c=$(echo ctl | git commit-tree $top) &&
+ git update-ref refs/heads/ctl $c
+ ) &&
+ CGIT_CONFIG="$PWD/duprc" QUERY_STRING="url=dup/plain/ctl%01name.txt&h=ctl" cgit >tmp &&
+ grep "^Content-Disposition: inline; filename=.ctl?name.txt.$" tmp
+'
+
test_done