Diff options
Diffstat (limited to '')
-rw-r--r--source/cgit.c320
1 file changed, 141 insertions, 179 deletions
diff --git a/source/cgit.c b/source/cgit.c
index eaf1d19..f8795d7 100644
--- a/source/cgit.c
+++ b/source/cgit.c
@@ -42,10 +42,6 @@
// every row it skips, so this bounds the work an offset alone can buy.
#define MAX_QUERY_OFFSET 100000
-// cgit knows fewer than eight archive formats, so this stands in for every bit
-// a snapshots mask can carry.
-#define ALL_SNAPSHOT_FORMATS 0xFF
-
// The first branch found is the fallback, so a repository whose default branch
// does not exist still has something to show.
struct refmatch {
@@ -89,11 +85,19 @@ static NORETURN void die_routine(const char *msg, va_list params)
exit(0);
}
+static char *ensure_end(const char *str, char c)
+{
+ size_t len = strlen(str);
+
+ return len && str[len - 1] == c ? xstrdup(str) : xstrfmt("%s%c", str, c);
+}
+
static void prepare_context(void)
{
+ const char *script_name = getenv("SCRIPT_NAME");
+
memset(&ctx, 0, sizeof(ctx));
ctx.cfg.agefile = "info/web/last-modified";
- ctx.cfg.cache_size = 0;
ctx.cfg.cache_root = CGIT_CACHE_ROOT;
ctx.cfg.cache_about_ttl = 15;
ctx.cfg.cache_snapshot_ttl = 5;
@@ -106,11 +110,8 @@ static void prepare_context(void)
// is served but not kept.
ctx.cfg.cache_max_slot_size = 64 * 1024;
ctx.cfg.case_sensitive_sort = 1;
- ctx.cfg.branch_sort = 0;
- ctx.cfg.commit_sort = 0;
ctx.cfg.logo = "/cgit.png";
ctx.cfg.favicon = "/favicon.ico";
- ctx.cfg.local_time = 0;
ctx.cfg.date_mode = date_mode_from_type(DATE_SHORT);
ctx.cfg.enable_header = 1;
ctx.cfg.enable_mailmap = 1;
@@ -119,7 +120,6 @@ static void prepare_context(void)
ctx.cfg.enable_http_clone = 1;
ctx.cfg.enable_index_owner = 1;
ctx.cfg.enable_tree_linenumbers = 1;
- ctx.cfg.enable_git_config = 0;
ctx.cfg.max_repo_count = 50;
ctx.cfg.max_commit_count = 50;
ctx.cfg.max_patch_count = 50;
@@ -131,23 +131,16 @@ static void prepare_context(void)
// Counted in kilobytes, so ten megabytes, which bounds the memory one
// request can be made to allocate for a blob.
ctx.cfg.max_blob_size = 10 * 1024;
- ctx.cfg.max_stats = 0;
- ctx.cfg.project_list = NULL;
ctx.cfg.renamelimit = -1;
- ctx.cfg.remove_suffix = 0;
ctx.cfg.robots = "index, nofollow";
ctx.cfg.root_title = "Git repository browser";
ctx.cfg.root_desc = "a fast webinterface for the git dscm";
- ctx.cfg.scan_hidden_path = 0;
- ctx.cfg.script_name = CGIT_SCRIPT_NAME;
ctx.cfg.section = "";
ctx.cfg.repository_sort = "name";
- ctx.cfg.section_sort = 0;
ctx.cfg.summary_branches = 10;
ctx.cfg.summary_log = 10;
ctx.cfg.summary_tags = 10;
ctx.cfg.max_atom_items = 10;
- ctx.cfg.difftype = DIFF_UNIFIED;
ctx.env.cgit_config = getenv("CGIT_CONFIG");
ctx.env.http_host = getenv("HTTP_HOST");
ctx.env.https = getenv("HTTPS");
@@ -155,21 +148,16 @@ static void prepare_context(void)
ctx.env.path_info = getenv("PATH_INFO");
ctx.env.query_string = getenv("QUERY_STRING");
ctx.env.request_method = getenv("REQUEST_METHOD");
- ctx.env.script_name = getenv("SCRIPT_NAME");
ctx.env.server_name = getenv("SERVER_NAME");
ctx.env.server_port = getenv("SERVER_PORT");
ctx.env.http_cookie = getenv("HTTP_COOKIE");
ctx.env.http_referer = getenv("HTTP_REFERER");
ctx.env.content_length =
getenv("CONTENT_LENGTH") ? strtoul(getenv("CONTENT_LENGTH"), NULL, 10) : 0;
- ctx.env.authenticated = 0;
ctx.page.mimetype = "text/html";
ctx.page.charset = PAGE_ENCODING;
- ctx.page.filename = NULL;
- ctx.page.size = 0;
string_list_init_dup(&ctx.cfg.mimetypes);
- if (ctx.env.script_name)
- ctx.cfg.script_name = xstrdup(ctx.env.script_name);
+ ctx.cfg.virtual_root = ensure_end(script_name ? script_name : CGIT_SCRIPT_NAME, '/');
if (ctx.env.query_string)
ctx.qry.raw = xstrdup(ctx.env.query_string);
if (!ctx.env.cgit_config)
@@ -178,7 +166,7 @@ static void prepare_context(void)
static void print_version(void)
{
- printf("CGit %s | https://github.com/brycekwon/cgit\n\nCompiled in features:\n", CGIT_VERSION);
+ printf("cgit %s | https://github.com/brycekwon/cgit\n\nCompiled in features:\n", CGIT_VERSION);
#ifdef NO_LUA
printf("[-] ");
#else
@@ -262,7 +250,7 @@ static void print_repo(FILE *f, struct cgit_repo *repo)
cgit_fprintf_filter(repo->trailer_filter, f, "repo.trailer-filter=");
if (repo->snapshots != ctx.cfg.snapshots) {
char *formats = build_snapshot_setting(repo->snapshots);
- fprintf(f, "repo.snapshots=%s\n", formats ? formats : "");
+ fprintf(f, "repo.snapshots=%s\n", formats);
free(formats);
}
if (repo->snapshot_prefix)
@@ -279,12 +267,10 @@ static void print_repo(FILE *f, struct cgit_repo *repo)
fprintf(f, "repo.enable-html-serving=%d\n", repo->enable_html_serving);
if (repo->branch_sort == 1)
fprintf(f, "repo.branch-sort=age\n");
- if (repo->commit_sort) {
- if (repo->commit_sort == 1)
- fprintf(f, "repo.commit-sort=date\n");
- else if (repo->commit_sort == 2)
- fprintf(f, "repo.commit-sort=topo\n");
- }
+ if (repo->commit_sort == 1)
+ fprintf(f, "repo.commit-sort=date\n");
+ else if (repo->commit_sort == 2)
+ fprintf(f, "repo.commit-sort=topo\n");
fprintf(f, "repo.hide=%d\n", repo->hide);
fprintf(f, "repo.ignore=%d\n", repo->ignore);
fprintf(f, "\n");
@@ -315,17 +301,6 @@ static void parse_args(int argc, const char **argv)
ctx.env.no_http = "1";
} else if (skip_prefix(argv[i], "--query=", &arg)) {
ctx.qry.raw = xstrdup(arg);
- } else if (skip_prefix(argv[i], "--repo=", &arg)) {
- ctx.qry.repo = xstrdup(arg);
- } else if (skip_prefix(argv[i], "--page=", &arg)) {
- ctx.qry.page = xstrdup(arg);
- } else if (skip_prefix(argv[i], "--head=", &arg)) {
- ctx.qry.head = xstrdup(arg);
- } else if (skip_prefix(argv[i], "--oid=", &arg)) {
- ctx.qry.oid = xstrdup(arg);
- ctx.qry.has_oid = 1;
- } else if (skip_prefix(argv[i], "--ofs=", &arg)) {
- ctx.qry.ofs = atoi(arg);
} else if (
skip_prefix(argv[i], "--scan-tree=", &arg) ||
skip_prefix(argv[i], "--scan-path=", &arg)
@@ -333,73 +308,36 @@ static void parse_args(int argc, const char **argv)
// A repository's snapshots setting is masked with the
// global one, and cgitrc has not been read here, so an
// empty mask would discard what the repository set.
- ctx.cfg.snapshots = ALL_SNAPSHOT_FORMATS;
+ ctx.cfg.snapshots = INT_MAX;
scanned++;
scan_tree(arg);
}
}
if (scanned) {
- cgit_qsort(cgit_repolist.repos, cgit_repolist.count, sizeof(struct cgit_repo), cmp_repos);
+ QSORT(cgit_repolist.repos, cgit_repolist.count, cmp_repos);
print_repolist(stdout, &cgit_repolist, 0);
exit(0);
}
}
/*
- * The lock is a fcntl lock rather than the mere existence of the lock file,
+ * The lock is an flock rather than the mere existence of the lock file,
* because a lock the kernel drops with its process cannot outlive a scan
* killed mid-run. A leftover file would count as a scan forever in progress.
*/
static int generate_cached_repolist(const char *path, const char *cached_rc)
{
struct strbuf locked_rc = STRBUF_INIT;
- struct flock lock = {
- .l_type = F_WRLCK,
- .l_whence = SEEK_SET,
- .l_start = 0,
- .l_len = 0,
- };
- struct stat held, named;
int err = 0;
int fd;
int first;
FILE *f;
strbuf_addf(&locked_rc, "%s.lock", cached_rc);
- fd = open(locked_rc.buf, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
- if (fd == -1) {
- err = errno;
- fprintf(stderr, "[cgit] Unable to open %s: %s (%d)\n", locked_rc.buf, strerror(err), err);
- goto out;
- }
- if (fcntl(fd, F_SETLK, &lock) < 0) {
- // A lock held elsewhere only means concurrent requests, which
- // is not worth a line in the server log. Any other failure, a
- // filesystem without lock support say, silently costs a scan
- // on every request and does deserve one.
- err = errno;
- if (err != EACCES && err != EAGAIN)
- fprintf(stderr, "[cgit] Unable to lock %s: %s (%d)\n", locked_rc.buf, strerror(err), err);
- close(fd);
- goto out;
- }
- // The lock landed on whatever inode the path named at open. A holder
- // finishing in between renames that inode into place as the live
- // list, and once the path is confirmed to still name this file that
- // rename can no longer happen, because it takes the lock held here.
- if (
- fstat(fd, &held) ||
- stat(locked_rc.buf, &named) ||
- held.st_ino != named.st_ino ||
- held.st_dev != named.st_dev
- ) {
- err = EAGAIN;
- close(fd);
+ err = cache_lock_file(locked_rc.buf, &fd);
+ if (err)
goto out;
- }
- // A run that died before its rename leaves the lock file behind, so
- // start from empty now that nobody else can be writing it.
- if (ftruncate(fd, 0) < 0 || !(f = fdopen(fd, "w"))) {
+ if (!(f = fdopen(fd, "w"))) {
err = errno;
fprintf(stderr, "[cgit] Unable to write %s: %s (%d)\n", locked_rc.buf, strerror(err), err);
unlink(locked_rc.buf);
@@ -407,10 +345,7 @@ static int generate_cached_repolist(const char *path, const char *cached_rc)
goto out;
}
first = cgit_repolist.count;
- if (ctx.cfg.project_list)
- scan_projects(path, ctx.cfg.project_list);
- else
- scan_tree(path);
+ scan_tree(path);
print_repolist(f, &cgit_repolist, first);
// Flushed before the rename, because print_repolist writes through
// stdio and a rename of the file would otherwise publish a repolist
@@ -457,12 +392,8 @@ static void process_cached_repolist(const char *path)
if (stat(cached_rc.buf, &st)) {
// Nothing is cached yet, so this request scans in its own
// process, leaving no copy behind when it cannot take the lock.
- if (generate_cached_repolist(path, cached_rc.buf)) {
- if (ctx.cfg.project_list)
- scan_projects(path, ctx.cfg.project_list);
- else
- scan_tree(path);
- }
+ if (generate_cached_repolist(path, cached_rc.buf))
+ scan_tree(path);
goto out;
}
@@ -504,6 +435,46 @@ static void add_mimetype(const char *name, const char *value)
item->util = xstrdup(value);
}
+/*
+ * Accept only the date formats cgit documents, leaving mode unchanged for
+ * anything else. Git's parse_date_format dies on anything unknown, which would
+ * turn a cgitrc typo into a failed request.
+ */
+static void parse_date_setting(const char *format, struct date_mode *mode)
+{
+ static const char * const names[] = {
+ "default", "human", "iso", "iso-strict", "iso8601",
+ "iso8601-strict", "raw", "relative", "rfc",
+ "rfc2822", "short", "unix",
+ };
+ const char *rest;
+ size_t i;
+
+ if (skip_prefix(format, "format:", &rest)) {
+ // An empty strftime format would render every date blank.
+ if (*rest)
+ parse_date_format(format, mode);
+ return;
+ }
+
+ // git reads local only as a whole alias of default-local, and dies on
+ // it with a suffix of its own.
+ if (!strcmp(format, "local")) {
+ parse_date_format(format, mode);
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(names); i++) {
+ if (!skip_prefix(format, names[i], &rest))
+ continue;
+ // "iso" also prefixes "iso8601", so a partial hit is skipped.
+ if (*rest && strcmp(rest, "-local"))
+ continue;
+ parse_date_format(format, mode);
+ return;
+ }
+}
+
static void apply_config(const char *name, const char *value)
{
const char *arg;
@@ -545,7 +516,7 @@ static void apply_config(const char *name, const char *value)
else if (!strcmp(name, "strict-export"))
ctx.cfg.strict_export = cgit_strdup_first_line(value);
else if (!strcmp(name, "virtual-root"))
- ctx.cfg.virtual_root = cgit_ensure_end(value, '/');
+ ctx.cfg.virtual_root = ensure_end(value, '/');
else if (!strcmp(name, "enable-plain-email"))
ctx.cfg.enable_plain_email = atoi(value);
else if (!strcmp(name, "enable-header"))
@@ -657,8 +628,6 @@ static void apply_config(const char *name, const char *value)
else if (!strcmp(name, "scan-path")) {
if (ctx.cfg.cache_size)
process_cached_repolist(cgit_expand_macros(value));
- else if (ctx.cfg.project_list)
- scan_projects(cgit_expand_macros(value), ctx.cfg.project_list);
else
scan_tree(cgit_expand_macros(value));
// The scan grows the repository array, so a record taken before
@@ -699,7 +668,7 @@ static void apply_config(const char *name, const char *value)
else if (!strcmp(name, "local-time"))
ctx.cfg.local_time = atoi(value);
else if (!strcmp(name, "date-format"))
- cgit_parse_date_format(value, &ctx.cfg.date_mode);
+ parse_date_setting(value, &ctx.cfg.date_mode);
else if (!strcmp(name, "commit-sort")) {
if (!strcmp(value, "date"))
ctx.cfg.commit_sort = 1;
@@ -738,9 +707,6 @@ static int query_int(const char *value, int min, int max)
static void apply_query_param(const char *name, const char *value)
{
- if (!value)
- value = "";
-
if (!strcmp(name, "r")) {
ctx.qry.repo = xstrdup(value);
ctx.repo = cgit_get_repoinfo(value);
@@ -757,10 +723,7 @@ static void apply_query_param(const char *name, const char *value)
} else if (!strcmp(name, "qt")) {
ctx.qry.grep = xstrdup(value);
} else if (!strcmp(name, "q")) {
- if (strlen(value) > MAX_SEARCH_LEN)
- ctx.qry.search = xstrndup(value, MAX_SEARCH_LEN);
- else
- ctx.qry.search = xstrdup(value);
+ ctx.qry.search = xstrndup(value, MAX_SEARCH_LEN);
} else if (!strcmp(name, "h")) {
ctx.qry.head = xstrdup(value);
} else if (!strcmp(name, "id")) {
@@ -803,6 +766,23 @@ static void apply_query_param(const char *name, const char *value)
}
}
+static void http_parse_querystring(const char *txt, void (*fn)(const char *name, const char *value))
+{
+ const char *p = txt;
+
+ while (p && *p) {
+ char *name = url_decode_parameter_name(&p);
+ // A name ends at an equals sign or an ampersand, and only the
+ // first is followed by a value.
+ if (*name) {
+ char *value = p[-1] == '=' ? url_decode_parameter_value(&p) : xstrdup("");
+ fn(name, value);
+ free(value);
+ }
+ free(name);
+ }
+}
+
static void open_auth_filter(const char *action)
{
cgit_open_filter(ctx.cfg.auth_filter, action,
@@ -823,7 +803,7 @@ static void open_auth_filter(const char *action)
* The filter answers the login POST itself, writing the status line and every
* header, so nothing here prints any and the process ends before this returns.
*/
-static void authenticate_post(void)
+static NORETURN void authenticate_post(void)
{
char buffer[MAX_AUTHENTICATION_POST_BYTES];
size_t len;
@@ -856,10 +836,8 @@ static void authenticate_cookie(void)
!ctx.repo &&
!strcmp(ctx.env.request_method, "POST") &&
!strcmp(ctx.qry.page, "login")
- ) {
+ )
authenticate_post();
- return;
- }
open_auth_filter("authenticate-cookie");
ctx.env.authenticated = cgit_close_filter(ctx.cfg.auth_filter);
@@ -884,33 +862,6 @@ static int is_full_oid(const char *rev)
}
/*
- * Only these pages render the same bytes for the same id for ever. A log or
- * refs page named with an id still lists branches and tags, which move.
- */
-static int page_is_static(void)
-{
- static const char *const pages[] = {
- "blame",
- "blob",
- "commit",
- "diff",
- "patch",
- "plain",
- "rawdiff",
- "snapshot",
- "tag",
- "tree",
- };
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE(pages); i++) {
- if (!strcmp(ctx.qry.page, pages[i]))
- return 1;
- }
- return 0;
-}
-
-/*
* Every cache-*-ttl setting is written in minutes, and so is this.
*/
static int calc_ttl(void)
@@ -937,7 +888,8 @@ static int calc_ttl(void)
// page to rebuild.
if (
ctx.qry.has_oid &&
- page_is_static() &&
+ cmd &&
+ cmd->is_static &&
(!ctx.qry.oid || is_full_oid(ctx.qry.oid)) &&
(!ctx.qry.oid2 || is_full_oid(ctx.qry.oid2))
)
@@ -991,22 +943,13 @@ static int find_current_ref(const struct reference *ref, void *data)
static char *find_default_branch(struct cgit_repo *repo)
{
- struct refmatch match;
- char *ref;
+ struct refmatch match = { .wanted = repo->defbranch };
- match.wanted = repo->defbranch;
- match.first = NULL;
- match.found = 0;
refs_for_each_branch_ref(get_main_ref_store(the_repository), find_current_ref, &match);
- if (match.found)
- ref = match.wanted;
- else
- ref = match.first;
- if (ref)
- ref = xstrdup(ref);
+ if (!match.found)
+ return match.first;
free(match.first);
-
- return ref;
+ return xstrdup(match.wanted);
}
static char *guess_defbranch(void)
@@ -1046,7 +989,7 @@ static void parse_readme(const char *readme, char **filename, char **ref, struct
}
if (!(*ref) && readme[0] != '/')
- *filename = cgit_fmtalloc("%s/%s", repo->path, readme);
+ *filename = xstrfmt("%s/%s", repo->path, readme);
else
*filename = xstrdup(readme);
}
@@ -1072,7 +1015,7 @@ static void choose_readme(struct cgit_repo *repo)
continue;
}
if (ref) {
- if (cgit_ref_path_exists(filename, ref, 1)) {
+ if (cgit_ref_path_exists(filename, ref)) {
found = 1;
break;
}
@@ -1090,7 +1033,32 @@ static void choose_readme(struct cgit_repo *repo)
string_list_append(&repo->readme, filename)->util = ref;
}
-static void prepare_repo_env(int *nongit, int *err)
+/*
+ * Export the CGIT_REPO_* variables that filters and hooks read.
+ */
+static void prepare_repo_env(struct cgit_repo *repo)
+{
+ const struct {
+ const char *name;
+ const char *value;
+ } vars[] = {
+ { .name = "CGIT_REPO_URL", .value = repo->url },
+ { .name = "CGIT_REPO_NAME", .value = repo->name },
+ { .name = "CGIT_REPO_PATH", .value = repo->path },
+ { .name = "CGIT_REPO_OWNER", .value = repo->owner },
+ { .name = "CGIT_REPO_DEFBRANCH", .value = repo->defbranch },
+ { .name = "CGIT_REPO_SECTION", .value = repo->section },
+ { .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url }
+ };
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(vars); i++)
+ if (vars[i].value && setenv(vars[i].name, vars[i].value, 1))
+ fprintf(stderr, "[cgit] Unable to set %s=%s: %s (%d)\n",
+ vars[i].name, vars[i].value, strerror(errno), errno);
+}
+
+static void open_repo(int *nongit, int *err)
{
// A repository configured without a path has nothing to open.
if (!ctx.repo->path) {
@@ -1104,14 +1072,13 @@ static void prepare_repo_env(int *nongit, int *err)
setup_git_directory_gently(the_repository, nongit);
*err = errno;
// Notes come out of the object store, which a repository that failed
- // to open has none of, and git dies loading a notes ref that names
- // no tree, so such a ref is passed over.
+ // to open has none of. The commit and log pages always ask for them,
+ // so they are set up either way, but a default ref that names no tree
+ // is left out, since git dies loading one.
if (!*nongit) {
struct display_notes_opt opt;
char *ref = default_notes_ref(the_repository);
- // The notes are always set up, since the commit and log pages
- // ask for them, only with no ref when the default names no tree.
init_display_notes(&opt);
opt.use_default_notes = cgit_notes_ref_usable(ref);
load_display_notes(&opt);
@@ -1126,11 +1093,16 @@ static void prepare_repo_env(int *nongit, int *err)
*/
static int prepare_repo_cmd(int nongit, int err, int clone)
{
+ // Static, since the pages replace the title without freeing it. Reset
+ // on entry, since a failed cache fill renders the page a second time.
+ static struct strbuf title = STRBUF_INIT;
struct object_id oid;
+ strbuf_reset(&title);
if (nongit) {
const char *name = ctx.repo->name;
- ctx.page.title = cgit_fmtalloc("%s - %s", ctx.cfg.root_title, "config error");
+ strbuf_addf(&title, "%s - %s", ctx.cfg.root_title, "config error");
+ ctx.page.title = title.buf;
ctx.repo = NULL;
cgit_print_error_page(
404, "Not Found", "Failed to open %s: %s", name,
@@ -1138,7 +1110,8 @@ static int prepare_repo_cmd(int nongit, int err, int clone)
);
return 1;
}
- ctx.page.title = cgit_fmtalloc("%s - %s", ctx.repo->name, ctx.cfg.root_title);
+ strbuf_addf(&title, "%s - %s", ctx.repo->name, ctx.cfg.root_title);
+ ctx.page.title = title.buf;
if (!ctx.repo->defbranch)
ctx.repo->defbranch = guess_defbranch();
@@ -1152,19 +1125,17 @@ static int prepare_repo_cmd(int nongit, int err, int clone)
// The dumb transport serves refs and objects off the disk and
// asks nothing of the head, and an empty repository clones.
if (clone) {
- cgit_prepare_repo_env(ctx.repo);
+ prepare_repo_env(ctx.repo);
return 0;
}
ctx.empty_repo = 1;
// Before the document starts, since the <head> carries
// <link rel='vcs-git'> and those clone urls expand macros such
// as $CGIT_REPO_URL out of this environment.
- cgit_prepare_repo_env(ctx.repo);
- cgit_print_http_headers();
- cgit_print_docstart();
- cgit_print_pageheader();
+ prepare_repo_env(ctx.repo);
+ cgit_print_layout_start();
cgit_print_empty_repo();
- cgit_print_docend();
+ cgit_print_layout_end();
return 1;
}
@@ -1185,7 +1156,7 @@ static int prepare_repo_cmd(int nongit, int err, int clone)
return 1;
}
string_list_sort(&ctx.repo->submodules);
- cgit_prepare_repo_env(ctx.repo);
+ prepare_repo_env(ctx.repo);
choose_readme(ctx.repo);
return 0;
}
@@ -1199,17 +1170,15 @@ static void process_request(void)
// whatever page it asked for.
if (!ctx.env.authenticated) {
ctx.page.title = "Authentication Required";
- cgit_print_http_headers();
- cgit_print_docstart();
- cgit_print_pageheader();
+ cgit_print_layout_start();
open_auth_filter("body");
cgit_close_filter(ctx.cfg.auth_filter);
- cgit_print_docend();
+ cgit_print_layout_end();
return;
}
if (ctx.repo)
- prepare_repo_env(&nongit, &err);
+ open_repo(&nongit, &err);
cmd = cgit_get_cmd();
if (!cmd || (!ctx.cfg.enable_http_clone && cmd->is_clone)) {
@@ -1340,18 +1309,12 @@ int cmd_main(int argc, const char **argv)
set_die_routine(die_routine);
prepare_context();
- cgit_repolist.length = 0;
- cgit_repolist.count = 0;
- cgit_repolist.repos = NULL;
parse_args(argc, argv);
config_file_parse(cgit_expand_macros(ctx.env.cgit_config), apply_config);
ctx.repo = NULL;
http_parse_querystring(ctx.qry.raw, apply_query_param);
- if (!ctx.cfg.virtual_root && ctx.cfg.script_name)
- ctx.cfg.virtual_root = cgit_ensure_end(ctx.cfg.script_name, '/');
-
// Falling back to PATH_INFO lets cgit serve virtual urls without a
// rewrite rule in the web server, and folding it into the raw query
// string keeps it part of the cache key.
@@ -1362,7 +1325,7 @@ int cmd_main(int argc, const char **argv)
path++;
ctx.qry.url = xstrdup(path);
if (ctx.qry.raw) {
- char *path_and_query = cgit_fmtalloc("%s?%s", path, ctx.qry.raw);
+ char *path_and_query = xstrfmt("%s?%s", path, ctx.qry.raw);
free(ctx.qry.raw);
ctx.qry.raw = path_and_query;
} else {
@@ -1387,7 +1350,6 @@ int cmd_main(int argc, const char **argv)
max_bytes, process_request);
strbuf_release(&cache_key);
- cgit_cleanup_filters();
// A slot that could not be sent because the client went away is not
// worth an error page nobody will read.
if (err && err != EPIPE)