Diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Trim a snapshot name without reading out of bounds
For a url of .git, or an empty one, repo_basename stepped its index to
the byte before its buffer, read it, and would have cleared it had it
held a slash. Git's strbuf trims take the same steps safely, and they
lift the 1024-byte cap that failed the page for a longer url.
Diffstat (limited to '')
| -rw-r--r-- | source/ui-shared.c | 38 | |
| -rw-r--r-- | source/ui-shared.h | 3 | |
| -rwxr-xr-x | tests/t0110-snapshot.sh | 30 |
3 files changed, 42 insertions, 29 deletions
diff --git a/source/ui-shared.c b/source/ui-shared.c index 936a6a4..9ad398f 100644 --- a/source/ui-shared.c +++ b/source/ui-shared.c @@ -35,33 +35,6 @@ // into a tab title while it still leaves room to spare in that buffer. #define MAX_TITLE_PATH_LEN 256 -static const char *repo_basename(const char *reponame) -{ - // The result lives in a static buffer, so it is only good until the - // next call. - static char buf[1024]; - const char *slash; - size_t len; - int last; - - len = strlcpy(buf, reponame, sizeof(buf)); - if (len >= sizeof(buf)) - die("Repository name too long: %s", reponame); - last = len - 1; - while (last && buf[last] == '/') - buf[last--] = '\0'; - if (last >= 3 && starts_with(&buf[last - 3], ".git")) { - last -= 3; - buf[last--] = '\0'; - } - while (last && buf[last] == '/') - buf[last--] = '\0'; - slash = strrchr(buf, '/'); - if (slash) - return ++slash; - return buf; -} - static const char *root_url(void) { if (ctx.cfg.virtual_root) @@ -955,10 +928,19 @@ void cgit_tree_url(const char *head, struct strbuf *base, struct strbuf *query) const char *cgit_snapshot_prefix(const struct cgit_repo *repo) { + static struct strbuf name = STRBUF_INIT; + const char *slash; + if (repo->snapshot_prefix) return repo->snapshot_prefix; - return repo_basename(repo->url); + strbuf_reset(&name); + strbuf_addstr(&name, repo->url); + strbuf_trim_trailing_dir_sep(&name); + strbuf_strip_suffix(&name, ".git"); + strbuf_trim_trailing_dir_sep(&name); + slash = strrchr(name.buf, '/'); + return slash ? slash + 1 : name.buf; } void cgit_index_link(const char *name, const char *title, const char *class, diff --git a/source/ui-shared.h b/source/ui-shared.h index da1b889..9abd4c0 100644 --- a/source/ui-shared.h +++ b/source/ui-shared.h @@ -125,7 +125,8 @@ extern void cgit_print_snapshot_links(const struct cgit_repo *repo, const char * /* * The name a snapshot of this repository is downloaded under, which is the - * configured prefix or the last component of the repository URL. + * configured prefix or the last component of the repository URL. A name taken + * from the URL is only good until the next call. */ extern const char *cgit_snapshot_prefix(const struct cgit_repo *repo); diff --git a/tests/t0110-snapshot.sh b/tests/t0110-snapshot.sh index bec0e3d..e3b8087 100755 --- a/tests/t0110-snapshot.sh +++ b/tests/t0110-snapshot.sh @@ -167,6 +167,36 @@ test_expect_success 'an empty snapshot-prefix puts no slash ahead of the members ! grep "^/" members ' +# A snapshot is named after the last component of the url once its .git +# suffix is gone, so a url of .git alone leaves the ref as the whole name. +test_expect_success 'set up repositories whose urls end in .git' ' + mkrepo repos/dotgit 1 && + git -C repos/dotgit tag v1.0 && + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "snapshots=tar" && + echo "repo.url=.git" && + echo "repo.path=$PWD/repos/dotgit/.git" && + echo "repo.url=sub/.git" && + echo "repo.path=$PWD/repos/dotgit/.git" + } >dotgitrc +' + +test_expect_success 'a url of .git names a snapshot after the ref alone' ' + CGIT_CONFIG="$PWD/dotgitrc" QUERY_STRING="url=.git/refs/" cgit >tmp && + grep ">v1.0.tar<" tmp && + CGIT_CONFIG="$PWD/dotgitrc" QUERY_STRING="url=.git/snapshot/v1.0.tar" cgit >tmp && + strip_headers <tmp >dotgit.tar && + tar -tf dotgit.tar >members && + grep "^v1.0/file-1$" members +' + +test_expect_success 'a url ending in /.git names a snapshot after its directory' ' + CGIT_CONFIG="$PWD/dotgitrc" QUERY_STRING="url=sub/.git/refs/" cgit >tmp && + grep ">sub-1.0.tar<" tmp +' + # A server may run cgit with no PATH at all, and the compressor is then looked # for on the default path execvp searches. test_expect_success GZIP 'a compressed snapshot is made without a PATH' ' |
