From 452570ce53d4362fbab4b694068dfa327af28915 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sat, 17 Oct 2026 17:09:14 -1000 Subject: Answer the plain view once for duplicate entries A tree can hold two entries of one name when fsck is off, and the walk went on after the first answered: a second file put two responses in one body, and a directory under the same name printed headers from the mimetype string the first had already freed. --- source/ui-plain.c | 8 +++++++- tests/t0105-plain.sh | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/source/ui-plain.c b/source/ui-plain.c index 67b2044..57e4699 100644 --- a/source/ui-plain.c +++ b/source/ui-plain.c @@ -84,7 +84,9 @@ static void print_object(const struct object_id *oid, const char *path) ctx.page.size = size; cgit_print_http_headers(); html_raw(buf, size); - free(mimetype); + // ctx.page.mimetype may still point into mimetype, and the headers + // are read again by whatever renders after this, so it stays alive + // for the rest of the request. free(buf); } @@ -166,6 +168,10 @@ static int walk_tree(const struct object_id *oid, struct strbuf *base, { struct walk_tree_context *walk = context; + // A tree can hold two entries of one name, and only the first answers: + // a second response would follow the first in the same body. + if (walk->response != RESPONSE_NONE && walk->dir_len >= 0 && base->len == (size_t)walk->dir_len) + return 0; if (walk->dir_len >= 0 && base->len == (size_t)walk->dir_len) { if (S_ISREG(mode) || S_ISLNK(mode)) { print_object(oid, pathname); diff --git a/tests/t0105-plain.sh b/tests/t0105-plain.sh index 27e8daa..2e5513f 100755 --- a/tests/t0105-plain.sh +++ b/tests/t0105-plain.sh @@ -71,4 +71,29 @@ test_expect_success 'only text and xml types carry a charset' ' sed "/^$/q" tmp | grep "^Content-Type: image/svg+xml; charset=UTF-8$" ' +# A tree can carry two entries of one name, which only a repository with +# fsck off accepts, and the plain view answers the first alone. +test_expect_success 'plain answers once for duplicate tree entries' ' + test_create_repo repos/dup && + ( + cd repos/dup && + blob=$(printf PNGDATA | git hash-object -w --stdin) && + inner=$(printf "100644 blob %s\\tinside\\n" $blob | git mktree) && + top=$(printf "100644 blob %s\\tx.png\\n040000 tree %s\\tx.png\\n" $blob $inner | git mktree --missing) && + c=$(echo dup | git commit-tree $top) && + git update-ref refs/heads/master $c + ) && + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "mimetype.png=image/png" && + echo "repo.url=dup" && + echo "repo.path=$PWD/repos/dup/.git" + } >duprc && + CGIT_CONFIG="$PWD/duprc" QUERY_STRING="url=dup/plain/x.png" cgit >tmp && + test $(grep -c "^Status:" tmp) = 1 && + test $(grep -c "^Content-Type:" tmp) = 1 && + grep "^Content-Type: image/png" tmp +' + test_done -- cgit