Diffstat (limited to 'ui-ci.c')
| -rw-r--r-- | ui-ci.c | 152 |
1 files changed, 0 insertions, 152 deletions
diff --git a/ui-ci.c b/ui-ci.c deleted file mode 100644 index f2561a2..0000000 --- a/ui-ci.c +++ /dev/null @@ -1,152 +0,0 @@ -/* ui-ci.c: redirect to an external CI system - * - * Copyright (C) 2026 Saya Andy <saya.andy@posteo.com> - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#define USE_THE_REPOSITORY_VARIABLE - -#include "cgit.h" -#include "ui-ci.h" -#include "html.h" -#include "ui-shared.h" - -/* Memoized outcome of resolving the ci url for this request: -1 while - * unresolved, 0 when there is no ci url for the current ref, and 1 when - * ci_url holds the url to redirect to. - */ -static int ci_resolved = -1; -static char *ci_url; - -static int ref_is_tag(const char *ref) -{ - struct strbuf fullref = STRBUF_INIT; - struct object_id oid; - int is_tag; - - strbuf_addf(&fullref, "refs/tags/%s", ref); - is_tag = !repo_get_oid(the_repository, fullref.buf, &oid); - strbuf_release(&fullref); - return is_tag; -} - -/* Append the repository url with any ".git" suffix removed and all - * slashes replaced by dashes, e.g. "sayauz/web.git" becomes - * "sayauz-web". - */ -static void add_repo_slug(struct strbuf *buf, const char *url) -{ - size_t len, i; - - if (!strip_suffix(url, ".git", &len)) - len = strlen(url); - for (i = 0; i < len; i++) - strbuf_addch(buf, url[i] == '/' ? '-' : url[i]); -} - -static char *expand_ci_url(const char *template) -{ - const char *p, *rest; - struct strbuf buf = STRBUF_INIT; - - for (p = template; *p; p++) { - if (*p != '$') { - strbuf_addch(&buf, *p); - continue; - } - if (skip_prefix(p, "$ref", &rest)) - strbuf_addstr(&buf, ctx.qry.head); - else if (skip_prefix(p, "$repo", &rest)) - strbuf_addstr(&buf, ctx.repo->url); - else if (skip_prefix(p, "$slug", &rest)) - add_repo_slug(&buf, ctx.repo->url); - else if (skip_prefix(p, "$$", &rest)) - strbuf_addch(&buf, '$'); - else { - strbuf_addch(&buf, '$'); - continue; - } - p = rest - 1; - } - return strbuf_detach(&buf, NULL); -} - -/* Ask the ci filter whether the pipeline denoted by url actually exists. - * The filter must not write to stdout, and signals "yes" by exiting with - * a zero status. - */ -static int ci_filter_accepts(const char *refkind, const char *url) -{ - struct cgit_filter *filter = ctx.repo->ci_filter; - - if (!filter) - return 1; - if (cgit_open_filter(filter, ctx.qry.head, refkind, url)) - return 0; - return !cgit_close_filter(filter); -} - -static void resolve_ci_url(void) -{ - const char *template, *refkind; - - if (ci_resolved != -1) - return; - ci_resolved = 0; - - if (!ctx.repo || !ctx.qry.head || !cgit_have_repository()) - return; - - if (ref_is_tag(ctx.qry.head)) { - refkind = "tag"; - template = ctx.repo->ci_tag_url; - } else { - refkind = "branch"; - template = ctx.repo->ci_branch_url; - } - if (!template) - template = ctx.repo->ci_url; - if (!template) - return; - - ci_url = expand_ci_url(template); - if (!ci_filter_accepts(refkind, ci_url)) { - free(ci_url); - ci_url = NULL; - return; - } - ci_resolved = 1; -} - -int cgit_ci_available(void) -{ - resolve_ci_url(); - return ci_resolved == 1; -} - -void cgit_print_ci(void) -{ - resolve_ci_url(); - - if (ci_resolved != 1) { - cgit_print_error_page(404, "Not found", - "No ci url available for %s", - ctx.qry.head); - return; - } - - /* The expanded template is emitted verbatim rather than through - * cgit_redirect(), which percent-encodes characters such as '?', - * '=' and '%' that are meaningful in a ci url. Refuse anything - * which could be used to smuggle in extra response headers. - */ - if (strpbrk(ci_url, "\r\n")) { - cgit_print_error_page(500, "Internal server error", - "Malformed ci url"); - return; - } - - htmlf("Status: 302 Found\nLocation: %s\n\n", ci_url); -} |