#!/bin/sh # Checks the ceilings a config can put on a page, that is the caps on refs # listed, on the lines and the files a diff renders inline, and on the size # of a blob any view will inflate, along with the clamp on how long an index # query may be. Crossing one of these has to trim the page or point the # reader at somewhere better suited, never drop the request, so each case # watches what survives as closely as what is left out. The last case is the # same idea applied to a filter, which degrades to escaped text rather than # failing when its highlighting library is absent. test_description='Check the ref listing and diff size limits' . ./setup.sh if test "$CGIT_HAS_LUA" -eq 1 then test_set_prereq LUA fi # The limits only show themselves against content that crosses them, so the # fixture carries more branches and tags than max-ref-count allows and a # commit whose oversized file diff sits beside a small one, which is what # tells a per file limit apart from a whole page one. test_expect_success 'set up limit fixtures' ' mkrepo repos/limits 1 && ( cd repos/limits && test_seq 1 60 >big.c && printf "int x;\n" >small.c && git add -A && git commit -m sources && test_seq 301 360 >big.c && printf "int y;\n" >small.c && git commit -am change && for i in 1 2 3; do git branch branch-$i || exit 1; done && for i in 1 2 3; do git tag tag-$i || exit 1; done ) && { echo "virtual-root=/" && echo "cache-size=0" && echo "max-ref-count=2" && echo "max-diff-lines=20" && echo "max-diff-files=0" && echo "repo.url=limits" && echo "repo.path=$PWD/repos/limits/.git" } >limitrc && { echo "virtual-root=/" && echo "cache-size=0" && echo "max-diff-files=1" && echo "repo.url=limits" && echo "repo.path=$PWD/repos/limits/.git" } >limitfilesrc ' limitq() { CGIT_CONFIG="$PWD/limitrc" QUERY_STRING="$1" cgit; } # An index query is compared against every repository the listing holds, so # an enormous one multiplies out across the whole index. Clamping it rather # than refusing it keeps the cost bounded without making an ordinary search # behave any differently. test_expect_success 'an enormous query is clamped, not rejected' ' long=$(awk "BEGIN{s=\"\";for(i=0;i<4000;i++)s=s \"a\"; print s}") && test ${#long} -eq 4000 && cgit_query "q=$long" >tmp && grep "" tmp && longest=$(grep -o "aaaa*" tmp | awk "{print length}" | sort -n | tail -1) && test "$longest" -eq 512 ' test_expect_success 'an ordinary query still filters the index' ' cgit_query "q=foo" >tmp && grep "foo" tmp && ! grep ">bar<" tmp ' # The combined refs page caps branches and tags separately, and the pages it # hands the overflow to page on their own, so a limit that leaked between the # two sections would show up as the wrong link or the wrong count here. test_expect_success 'refs page lists max-ref-count branches and tags' ' limitq "url=limits/refs/" >tmp && test $(grep -c "log/?h=" tmp) -eq 2 && test $(grep -c "/tag/?h=tag-" tmp) -eq 2 ' test_expect_success 'refs page links each overflow to its own category' ' grep "refs/heads" tmp && grep "refs/tags" tmp ' test_expect_success 'branch page paginates independently' ' limitq "url=limits/refs/heads/" >tmp && test $(grep -c "log/?h=" tmp) -eq 2 && grep "\[next\]" tmp && limitq "url=limits/refs/heads/&ofs=2" >tmp && grep "\[prev\]" tmp && ! grep "/tag/?h=tag-" tmp ' test_expect_success 'tag page paginates independently' ' limitq "url=limits/refs/tags/&ofs=2" >tmp && grep "/tag/?h=tag-" tmp && grep "\[prev\]" tmp && ! grep "log/?h=" tmp ' # A file that busts max-diff-lines is replaced by a link to its own page, # where the reader asked for that one file and the limit no longer applies. # The rest of the commit still renders, so one huge file cannot hide the # small change beside it. test_expect_success 'oversized file diff is replaced by a link' ' limitq "url=limits/commit/" >tmp && grep "too large to be rendered inline" tmp && grep "View it on its own page" tmp ' test_expect_success 'small file in the same commit still renders inline' ' grep "class=.add.>+int y;" tmp ' test_expect_success 'the single-file diff page always renders in full' ' limitq "url=limits/diff/big.c" >tmp && grep "class=.hunk." tmp && ! grep "too large to be rendered inline" tmp ' # max-diff-files counts the files in a commit rather than the lines in one, # so it drops the whole body back to the diffstat while a request naming a # single file stays unaffected. test_expect_success 'a commit changing too many files shows stat only' ' CGIT_CONFIG="$PWD/limitfilesrc" QUERY_STRING="url=limits/commit/" cgit >tmp && grep "too large to be rendered inline" tmp && ! grep "class=.hunk." tmp ' test_expect_success 'the single-file page is not limited by max-diff-files' ' CGIT_CONFIG="$PWD/limitfilesrc" QUERY_STRING="url=limits/diff/small.c" cgit >tmp && grep "class=.hunk." tmp ' # The diff views must not inflate a blob past max-blob-size merely to render # it, which is the same defence the tree and plain views make and is easy to # miss on this path. Such a file is reported as binary instead. test_expect_success 'a diff of an oversized blob is not inlined' ' mkrepo repos/blobdiff 1 && ( cd repos/blobdiff && awk "BEGIN{for(i=0;i<400;i++)print \"aaaaaaaa\"}" >big.txt && git add -A && git commit -m add && awk "BEGIN{for(i=0;i<401;i++)print \"aaaaaaaa\"}" >big.txt && git commit -am change ) && { echo "virtual-root=/" && echo "cache-size=0" && echo "max-blob-size=1" && echo "repo.url=blobdiff" && echo "repo.path=$PWD/repos/blobdiff/.git" } >blobdiffrc && sha=$(git -C repos/blobdiff rev-parse HEAD) && CGIT_CONFIG="$PWD/blobdiffrc" QUERY_STRING="url=blobdiff/commit/&id=$sha" cgit >tmp && grep "Binary files differ" tmp && ! grep "aaaaaaaa" tmp ' # A missing scintillua leaves the shipped filter with nothing to highlight # with, and a filter that failed there would take the whole page down with # it, so it has to hand the source back escaped instead. test_expect_success LUA 'highlight filter passes text through without scintillua' ' { echo "virtual-root=/" && echo "cache-size=0" && echo "source-filter=lua:$(cd ../../custom/extensions && pwd)/syntax-highlight.lua" && echo "repo.url=limits" && echo "repo.path=$PWD/repos/limits/.git" } >hlrc && CGIT_SCINTILLUA_PATH=/nonexistent CGIT_CONFIG="$PWD/hlrc" \ QUERY_STRING="url=limits/tree/small.c" cgit >tmp && grep "int y;" tmp ' test_done