X-Git-Url: https://git.cameronkatri.com/cgit.git/blobdiff_plain/30304d8156a72ffc95e45e1aa9407319b81bd253..898b9e19e0eacd67456ddcc91ff173055e1c0e99:/cgit.c diff --git a/cgit.c b/cgit.c index d84b4be..2f07e6d 100644 --- a/cgit.c +++ b/cgit.c @@ -23,7 +23,7 @@ static void add_mimetype(const char *name, const char *value) { struct string_list_item *item; - item = string_list_insert(&ctx.cfg.mimetypes, xstrdup(name)); + item = string_list_insert(&ctx.cfg.mimetypes, name); item->util = xstrdup(value); } @@ -31,6 +31,7 @@ static void process_cached_repolist(const char *path); static void repo_config(struct cgit_repo *repo, const char *name, const char *value) { + const char *path; struct string_list_item *item; if (!strcmp(name, "name")) @@ -41,8 +42,12 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va repo->desc = xstrdup(value); else if (!strcmp(name, "owner")) repo->owner = xstrdup(value); + else if (!strcmp(name, "homepage")) + repo->homepage = xstrdup(value); else if (!strcmp(name, "defbranch")) repo->defbranch = xstrdup(value); + else if (!strcmp(name, "extra-head-content")) + repo->extra_head_content = xstrdup(value); else if (!strcmp(name, "snapshots")) repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); else if (!strcmp(name, "enable-commit-graph")) @@ -55,6 +60,8 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va repo->enable_remote_branches = atoi(value); else if (!strcmp(name, "enable-subject-links")) repo->enable_subject_links = atoi(value); + else if (!strcmp(name, "enable-html-serving")) + repo->enable_html_serving = atoi(value); else if (!strcmp(name, "branch-sort")) { if (!strcmp(value, "age")) repo->branch_sort = 1; @@ -69,11 +76,13 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va repo->max_stats = cgit_find_stats_period(value, NULL); else if (!strcmp(name, "module-link")) repo->module_link= xstrdup(value); - else if (starts_with(name, "module-link.")) { - item = string_list_append(&repo->submodules, xstrdup(name + 12)); + else if (skip_prefix(name, "module-link.", &path)) { + item = string_list_append(&repo->submodules, xstrdup(path)); item->util = xstrdup(value); } else if (!strcmp(name, "section")) repo->section = xstrdup(value); + else if (!strcmp(name, "snapshot-prefix")) + repo->snapshot_prefix = xstrdup(value); else if (!strcmp(name, "readme") && value != NULL) { if (repo->readme.items == ctx.cfg.readme.items) memset(&repo->readme, 0, sizeof(repo->readme)); @@ -102,15 +111,17 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va static void config_cb(const char *name, const char *value) { - if (!strcmp(name, "section") || !strcmp(name, "repo.group")) + const char *arg; + + if (!strcmp(name, "section")) ctx.cfg.section = xstrdup(value); else if (!strcmp(name, "repo.url")) ctx.repo = cgit_add_repo(value); else if (ctx.repo && !strcmp(name, "repo.path")) ctx.repo->path = trim_end(value, '/'); - else if (ctx.repo && starts_with(name, "repo.")) - repo_config(ctx.repo, name + 5, value); - else if (!strcmp(name, "readme") && value != NULL) + else if (ctx.repo && skip_prefix(name, "repo.", &arg)) + repo_config(ctx.repo, arg, value); + else if (!strcmp(name, "readme")) string_list_append(&ctx.cfg.readme, xstrdup(value)); else if (!strcmp(name, "root-title")) ctx.cfg.root_title = xstrdup(value); @@ -130,20 +141,14 @@ static void config_cb(const char *name, const char *value) ctx.cfg.header = xstrdup(value); else if (!strcmp(name, "logo")) ctx.cfg.logo = xstrdup(value); - else if (!strcmp(name, "index-header")) - ctx.cfg.index_header = xstrdup(value); - else if (!strcmp(name, "index-info")) - ctx.cfg.index_info = xstrdup(value); else if (!strcmp(name, "logo-link")) ctx.cfg.logo_link = xstrdup(value); else if (!strcmp(name, "module-link")) ctx.cfg.module_link = xstrdup(value); else if (!strcmp(name, "strict-export")) ctx.cfg.strict_export = xstrdup(value); - else if (!strcmp(name, "virtual-root")) { + else if (!strcmp(name, "virtual-root")) ctx.cfg.virtual_root = ensure_end(value, '/'); - } else if (!strcmp(name, "nocache")) - ctx.cfg.nocache = atoi(value); else if (!strcmp(name, "noplainemail")) ctx.cfg.noplainemail = atoi(value); else if (!strcmp(name, "noheader")) @@ -160,6 +165,8 @@ static void config_cb(const char *name, const char *value) ctx.cfg.enable_index_links = atoi(value); else if (!strcmp(name, "enable-index-owner")) ctx.cfg.enable_index_owner = atoi(value); + else if (!strcmp(name, "enable-blame")) + ctx.cfg.enable_blame = atoi(value); else if (!strcmp(name, "enable-commit-graph")) ctx.cfg.enable_commit_graph = atoi(value); else if (!strcmp(name, "enable-log-filecount")) @@ -170,6 +177,8 @@ static void config_cb(const char *name, const char *value) ctx.cfg.enable_remote_branches = atoi(value); else if (!strcmp(name, "enable-subject-links")) ctx.cfg.enable_subject_links = atoi(value); + else if (!strcmp(name, "enable-html-serving")) + ctx.cfg.enable_html_serving = atoi(value); else if (!strcmp(name, "enable-tree-linenumbers")) ctx.cfg.enable_tree_linenumbers = atoi(value); else if (!strcmp(name, "enable-git-config")) @@ -223,7 +232,7 @@ static void config_cb(const char *name, const char *value) else if (!strcmp(name, "project-list")) ctx.cfg.project_list = xstrdup(expand_macros(value)); else if (!strcmp(name, "scan-path")) - if (!ctx.cfg.nocache && ctx.cfg.cache_size) + if (ctx.cfg.cache_size) process_cached_repolist(expand_macros(value)); else if (ctx.cfg.project_list) scan_projects(expand_macros(value), @@ -274,8 +283,8 @@ static void config_cb(const char *name, const char *value) ctx.cfg.branch_sort = 1; if (!strcmp(value, "name")) ctx.cfg.branch_sort = 0; - } else if (starts_with(name, "mimetype.")) - add_mimetype(name + 9, value); + } else if (skip_prefix(name, "mimetype.", &arg)) + add_mimetype(arg, value); else if (!strcmp(name, "include")) parse_configfile(expand_macros(value), config_cb); } @@ -314,8 +323,6 @@ static void querystring_cb(const char *name, const char *value) ctx.qry.path = trim_end(value, '/'); } else if (!strcmp(name, "name")) { ctx.qry.name = xstrdup(value); - } else if (!strcmp(name, "mimetype")) { - ctx.qry.mimetype = xstrdup(value); } else if (!strcmp(name, "s")) { ctx.qry.sort = xstrdup(value); } else if (!strcmp(name, "showmsg")) { @@ -344,7 +351,6 @@ static void prepare_context(void) { memset(&ctx, 0, sizeof(ctx)); ctx.cfg.agefile = "info/web/last-modified"; - ctx.cfg.nocache = 0; ctx.cfg.cache_size = 0; ctx.cfg.cache_max_create_time = 5; ctx.cfg.cache_root = CGIT_CACHE_ROOT; @@ -410,7 +416,7 @@ static void prepare_context(void) ctx.page.modified = time(NULL); ctx.page.expires = ctx.page.modified; ctx.page.etag = NULL; - memset(&ctx.cfg.mimetypes, 0, sizeof(struct string_list)); + string_list_init(&ctx.cfg.mimetypes, 1); if (ctx.env.script_name) ctx.cfg.script_name = xstrdup(ctx.env.script_name); if (ctx.env.query_string) @@ -466,14 +472,15 @@ static char *find_default_branch(struct cgit_repo *repo) static char *guess_defbranch(void) { - const char *ref; - unsigned char sha1[20]; + const char *ref, *refname; + struct object_id oid; - ref = resolve_ref_unsafe("HEAD", 0, sha1, NULL); - if (!ref || !starts_with(ref, "refs/heads/")) + ref = resolve_ref_unsafe("HEAD", 0, &oid, NULL); + if (!ref || !skip_prefix(ref, "refs/heads/", &refname)) return "master"; - return xstrdup(ref + 11); + return xstrdup(refname); } + /* The caller must free filename and ref after calling this. */ static inline void parse_readme(const char *readme, char **filename, char **ref, struct cgit_repo *repo) { @@ -551,12 +558,8 @@ static void print_no_repo_clone_urls(const char *url) html("\n"); } -static int prepare_repo_cmd(void) +static void prepare_repo_env(int *nongit) { - unsigned char sha1[20]; - int nongit = 0; - int rc; - /* The path to the git repository. */ setenv("GIT_DIR", ctx.repo->path, 1); @@ -569,8 +572,13 @@ static int prepare_repo_cmd(void) /* Setup the git directory and initialize the notes system. Both of these * load local configuration from the git repository, so we do them both while * the HOME variables are unset. */ - setup_git_directory_gently(&nongit); + setup_git_directory_gently(nongit); init_display_notes(NULL); +} +static int prepare_repo_cmd(int nongit) +{ + struct object_id oid; + int rc; if (nongit) { const char *name = ctx.repo->name; @@ -611,17 +619,12 @@ static int prepare_repo_cmd(void) return 1; } - if (get_sha1(ctx.qry.head, sha1)) { - char *tmp = xstrdup(ctx.qry.head); - ctx.qry.head = ctx.repo->defbranch; - ctx.page.status = 404; - ctx.page.statusmsg = "Not found"; - cgit_print_http_headers(); - cgit_print_docstart(); - cgit_print_pageheader(); - cgit_print_error("Invalid branch: %s", tmp); - cgit_print_docend(); - free(tmp); + if (get_oid(ctx.qry.head, &oid)) { + char *old_head = ctx.qry.head; + ctx.qry.head = xstrdup(ctx.repo->defbranch); + cgit_print_error_page(404, "Not found", + "Invalid branch: %s", old_head); + free(old_head); return 1; } string_list_sort(&ctx.repo->submodules); @@ -642,7 +645,7 @@ static inline void open_auth_filter(const char *function) ctx.env.https ? ctx.env.https : "", ctx.qry.repo ? ctx.qry.repo : "", ctx.qry.page ? ctx.qry.page : "", - ctx.qry.url ? ctx.qry.url : "", + cgit_currentfullurl(), cgit_loginurl()); } @@ -656,13 +659,13 @@ static inline void open_auth_filter(const char *function) static inline void authenticate_post(void) { char buffer[MAX_AUTHENTICATION_POST_BYTES]; - int len; + ssize_t len; open_auth_filter("authenticate-post"); len = ctx.env.content_length; if (len > MAX_AUTHENTICATION_POST_BYTES) len = MAX_AUTHENTICATION_POST_BYTES; - if (read(STDIN_FILENO, buffer, len) < 0) + if ((len = read(STDIN_FILENO, buffer, len)) < 0) die_errno("Could not read POST from stdin"); if (write(STDOUT_FILENO, buffer, len) < 0) die_errno("Could not write POST to stdout"); @@ -695,6 +698,7 @@ static inline void authenticate_cookie(void) static void process_request(void) { struct cgit_cmd *cmd; + int nongit = 0; /* If we're not yet authenticated, no matter what page we're on, * display the authentication body from the auth_filter. This should @@ -710,21 +714,25 @@ static void process_request(void) return; } + if (ctx.repo) + prepare_repo_env(&nongit); + cmd = cgit_get_cmd(); if (!cmd) { ctx.page.title = "cgit error"; - ctx.page.status = 404; - ctx.page.statusmsg = "Not found"; - cgit_print_http_headers(); - cgit_print_docstart(); - cgit_print_pageheader(); - cgit_print_error("Invalid request"); - cgit_print_docend(); + cgit_print_error_page(404, "Not found", "Invalid request"); return; } if (!ctx.cfg.enable_http_clone && cmd->is_clone) { - html_status(404, "Not found", 0); + ctx.page.title = "cgit error"; + cgit_print_error_page(404, "Not found", "Invalid request"); + return; + } + + if (cmd->want_repo && !ctx.repo) { + cgit_print_error_page(400, "Bad request", + "No repository selected"); return; } @@ -734,31 +742,10 @@ static void process_request(void) */ ctx.qry.vpath = cmd->want_vpath ? ctx.qry.path : NULL; - if (cmd->want_repo && !ctx.repo) { - cgit_print_http_headers(); - cgit_print_docstart(); - cgit_print_pageheader(); - cgit_print_error("No repository selected"); - cgit_print_docend(); - return; - } - - if (ctx.repo && prepare_repo_cmd()) + if (ctx.repo && prepare_repo_cmd(nongit)) return; - if (cmd->pre) - cmd->pre(); - - if (cmd->want_layout) { - cgit_print_http_headers(); - cgit_print_docstart(); - cgit_print_pageheader(); - } - cmd->fn(); - - if (cmd->want_layout) - cgit_print_docend(); } static int cmp_repos(const void *a, const void *b) @@ -773,7 +760,7 @@ static char *build_snapshot_setting(int bitmap) struct strbuf result = STRBUF_INIT; for (f = cgit_snapshot_formats; f->suffix; f++) { - if (f->bit & bitmap) { + if (cgit_snapshot_format_bit(f) & bitmap) { if (result.len) strbuf_addch(&result, ' '); strbuf_addstr(&result, f->suffix); @@ -812,10 +799,14 @@ static void print_repo(FILE *f, struct cgit_repo *repo) } if (repo->defbranch) fprintf(f, "repo.defbranch=%s\n", repo->defbranch); + if (repo->extra_head_content) + fprintf(f, "repo.extra-head-content=%s\n", repo->extra_head_content); if (repo->module_link) fprintf(f, "repo.module-link=%s\n", repo->module_link); if (repo->section) fprintf(f, "repo.section=%s\n", repo->section); + if (repo->homepage) + fprintf(f, "repo.homepage=%s\n", repo->homepage); if (repo->clone_url) fprintf(f, "repo.clone-url=%s\n", repo->clone_url); fprintf(f, "repo.enable-commit-graph=%d\n", @@ -839,6 +830,8 @@ static void print_repo(FILE *f, struct cgit_repo *repo) fprintf(f, "repo.snapshots=%s\n", tmp ? tmp : ""); free(tmp); } + if (repo->snapshot_prefix) + fprintf(f, "repo.snapshot-prefix=%s\n", repo->snapshot_prefix); if (repo->max_stats != ctx.cfg.max_stats) fprintf(f, "repo.max-stats=%s\n", cgit_find_stats_periodname(repo->max_stats)); @@ -848,6 +841,7 @@ static void print_repo(FILE *f, struct cgit_repo *repo) fprintf(f, "repo.logo-link=%s\n", repo->logo_link); fprintf(f, "repo.enable-remote-branches=%d\n", repo->enable_remote_branches); fprintf(f, "repo.enable-subject-links=%d\n", repo->enable_subject_links); + 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) { @@ -955,11 +949,12 @@ out: static void cgit_parse_args(int argc, const char **argv) { int i; + const char *arg; int scan = 0; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--version")) { - printf("CGit %s | http://git.zx2c4.com/cgit/\n\nCompiled in features:\n", CGIT_VERSION); + printf("CGit %s | https://git.zx2c4.com/cgit/\n\nCompiled in features:\n", CGIT_VERSION); #ifdef NO_LUA printf("[-] "); #else @@ -975,28 +970,26 @@ static void cgit_parse_args(int argc, const char **argv) exit(0); } - if (starts_with(argv[i], "--cache=")) { - ctx.cfg.cache_root = xstrdup(argv[i] + 8); - } else if (!strcmp(argv[i], "--nocache")) { - ctx.cfg.nocache = 1; + if (skip_prefix(argv[i], "--cache=", &arg)) { + ctx.cfg.cache_root = xstrdup(arg); } else if (!strcmp(argv[i], "--nohttp")) { ctx.env.no_http = "1"; - } else if (starts_with(argv[i], "--query=")) { - ctx.qry.raw = xstrdup(argv[i] + 8); - } else if (starts_with(argv[i], "--repo=")) { - ctx.qry.repo = xstrdup(argv[i] + 7); - } else if (starts_with(argv[i], "--page=")) { - ctx.qry.page = xstrdup(argv[i] + 7); - } else if (starts_with(argv[i], "--head=")) { - ctx.qry.head = xstrdup(argv[i] + 7); + } 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); ctx.qry.has_symref = 1; - } else if (starts_with(argv[i], "--sha1=")) { - ctx.qry.sha1 = xstrdup(argv[i] + 7); + } else if (skip_prefix(argv[i], "--sha1=", &arg)) { + ctx.qry.sha1 = xstrdup(arg); ctx.qry.has_sha1 = 1; - } else if (starts_with(argv[i], "--ofs=")) { - ctx.qry.ofs = atoi(argv[i] + 6); - } else if (starts_with(argv[i], "--scan-tree=") || - starts_with(argv[i], "--scan-path=")) { + } 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)) { /* * HACK: The global snapshot bit mask defines the set * of allowed snapshot formats, but the config file @@ -1010,7 +1003,7 @@ static void cgit_parse_args(int argc, const char **argv) */ ctx.cfg.snapshots = 0xFF; scan++; - scan_tree(argv[i] + 12, repo_config); + scan_tree(arg, repo_config); } } if (scan) { @@ -1044,7 +1037,7 @@ static int calc_ttl(void) return ctx.cfg.cache_repo_ttl; } -int main(int argc, const char **argv) +int cmd_main(int argc, const char **argv) { const char *path; int err, ttl; @@ -1099,8 +1092,6 @@ int main(int argc, const char **argv) else ctx.page.expires += ttl * 60; if (!ctx.env.authenticated || (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))) - ctx.cfg.nocache = 1; - if (ctx.cfg.nocache) ctx.cfg.cache_size = 0; err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, ctx.qry.raw, ttl, process_request);