diff options
context:
space:
mode:
-rw-r--r--source/ui-empty.c8
-rw-r--r--source/ui-shared.c69
-rw-r--r--source/ui-shared.h1
-rw-r--r--source/ui-summary.c8
-rwxr-xr-xtests/t0102-summary.sh21
5 files changed, 93 insertions, 14 deletions
diff --git a/source/ui-empty.c b/source/ui-empty.c
index a65f49b..dd8dc64 100644
--- a/source/ui-empty.c
+++ b/source/ui-empty.c
@@ -13,13 +13,7 @@
static void print_clone_url(const char *url)
{
- html("<tr><td class='clone-url'><a rel='vcs-git' href='");
- html_url_path(url);
- html("' title='");
- html_attr(ctx.repo->name);
- html(" Git repository'>");
- html_txt(url);
- html("</a></td></tr>\n");
+ cgit_print_clone_row(url, 0);
}
/*
diff --git a/source/ui-shared.c b/source/ui-shared.c
index 85712bf..5cf9428 100644
--- a/source/ui-shared.c
+++ b/source/ui-shared.c
@@ -317,8 +317,26 @@ static void print_rel_date(time_t t, int tz, double count, const char *class,
htmlf("'>%.0f %s</time>", count, suffix);
}
+/*
+ * Whether a clone url opens with a URI scheme. The scp form git@host:path
+ * has none, and a link element's href must hold a URI, so that form stays
+ * out of the document head.
+ */
+static int has_uri_scheme(const char *url)
+{
+ const char *p = url;
+
+ if (!isalpha((unsigned char)*p))
+ return 0;
+ while (isalnum((unsigned char)*p) || *p == '+' || *p == '-' || *p == '.')
+ p++;
+ return *p == ':';
+}
+
static void print_rel_vcs_link(const char *url)
{
+ if (!has_uri_scheme(url))
+ return;
html("<link rel='vcs-git' href='");
html_attr(url);
html("' title='");
@@ -1620,6 +1638,57 @@ void cgit_add_clone_urls(void (*fn)(const char *))
add_clone_urls(fn, ctx.cfg.clone_prefix, ctx.repo->url);
}
+static char *http_clone_url;
+static int http_clone_url_scanned;
+
+// Scheme names compare case-insensitively.
+static int is_http_url(const char *url)
+{
+ return istarts_with(url, "http://") || istarts_with(url, "https://");
+}
+
+static void capture_http_clone_url(const char *url)
+{
+ if (!http_clone_url && is_http_url(url))
+ http_clone_url = xstrdup(url);
+}
+
+/*
+ * One row of the clone table. The url is shown as written, and every row is
+ * a link, but a browser cannot follow the ssh, scp or git forms, so those
+ * rows point at the first http url in the clone list, or at the repository's
+ * own page when the list has none, which with http clone enabled is itself a
+ * working clone url. A colspan of zero leaves the attribute out.
+ */
+void cgit_print_clone_row(const char *url, int colspan)
+{
+ const char *href = url;
+ char *fallback = NULL;
+
+ if (!is_http_url(url)) {
+ if (!http_clone_url_scanned) {
+ http_clone_url_scanned = 1;
+ cgit_add_clone_urls(capture_http_clone_url);
+ }
+ href = http_clone_url;
+ if (!href)
+ href = fallback = cgit_repourl(ctx.repo->url);
+ }
+
+ if (colspan)
+ htmlf("<tr><td colspan='%d' class='clone-url'>", colspan);
+ else
+ html("<tr><td class='clone-url'>");
+ html("<a rel='vcs-git' title='");
+ html_attr(ctx.repo->name);
+ html(" Git repository' href='");
+ html_attr(href);
+ html("'>");
+ html_txt(url);
+ html("</a></td></tr>\n");
+ free(fallback);
+}
+
void cgit_add_hidden_formfields(int incl_head, int incl_search,
const char *page)
{
diff --git a/source/ui-shared.h b/source/ui-shared.h
index c266951..c421178 100644
--- a/source/ui-shared.h
+++ b/source/ui-shared.h
@@ -24,6 +24,7 @@ extern char *cgit_currenturl(void);
extern char *cgit_currentfullurl(void);
extern const char *cgit_loginurl(void);
extern char *cgit_repourl(const char *reponame);
+extern void cgit_print_clone_row(const char *url, int colspan);
extern char *cgit_fileurl(const char *reponame, const char *pagename,
const char *filename, const char *query);
extern char *cgit_pageurl(const char *reponame, const char *pagename,
diff --git a/source/ui-summary.c b/source/ui-summary.c
index 3658bc5..dacf0f7 100644
--- a/source/ui-summary.c
+++ b/source/ui-summary.c
@@ -48,13 +48,7 @@ static void print_clone_url(const char *url)
htmlf("<tr class='nohover'><th colspan='%d' class='left'>Clone</th></tr>\n", columns);
}
- htmlf("<tr><td colspan='%d' class='clone-url'><a rel='vcs-git' href='", columns);
- html_url_path(url);
- html("' title='");
- html_attr(ctx.repo->name);
- html(" Git repository'>");
- html_txt(url);
- html("</a></td></tr>\n");
+ cgit_print_clone_row(url, columns);
}
/*
diff --git a/tests/t0102-summary.sh b/tests/t0102-summary.sh
index 79f2b11..5ce1fab 100755
--- a/tests/t0102-summary.sh
+++ b/tests/t0102-summary.sh
@@ -32,4 +32,25 @@ test_expect_success 'clone-url expanded correctly' '
grep "git://example.org/bar.git" tmp
'
+# A clone url is shown as written, but a browser cannot follow the ssh, scp
+# or git forms, so those rows link to the first http url in the list, or to
+# the repository's own page when the list has none.
+test_expect_success 'a git clone url row falls back to the page url' '
+ grep "clone-url.><a rel=.vcs-git. title=.bar Git repository. href=./bar/.>git://example.org/bar.git</a>" tmp
+'
+
+test_expect_success 'an scp clone url row links to the http url' '
+ {
+ echo "virtual-root=/" &&
+ echo "cache-size=0" &&
+ echo "repo.url=foo" &&
+ echo "repo.path=$PWD/repos/foo/.git" &&
+ echo "repo.clone-url=git@example.org:foo https://example.org/foo"
+ } >clonerc &&
+ CGIT_CONFIG="$PWD/clonerc" QUERY_STRING="url=foo" cgit >tmp &&
+ grep "title=.foo Git repository. href=.https://example.org/foo.>git@example.org:foo</a>" tmp &&
+ grep "vcs-git. href=.https://example.org/foo." tmp &&
+ ! grep "vcs-git. href=.git@" tmp
+'
+
test_done