[PATCH] Support Git over HTTP using git-http-backend
Florian Pritz
bluewind at xinu.at
Mon Dec 29 17:13:18 CET 2014
This saves users from the hassle of setting up git-http-backend when
they already run cgit.
References: man git-http-backend
Signed-off-by: Florian Pritz <bluewind at xinu.at>
---
I've messed up updating my master branch and used git-send-email on it. You
might have gotten 1 or 2 patches that are already applied because of that.
Sorry.
cgit.c | 3 +++
cgit.h | 1 +
cgitrc.5.txt | 8 ++++++++
cmd.c | 12 ++++++++++++
ui-clone.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ui-clone.h | 2 ++
6 files changed, 86 insertions(+)
diff --git a/cgit.c b/cgit.c
index 79019c2..0c4a292 100644
--- a/cgit.c
+++ b/cgit.c
@@ -124,6 +124,8 @@ static void config_cb(const char *name, const char *value)
ctx.cfg.head_include = xstrdup(value);
else if (!strcmp(name, "header"))
ctx.cfg.header = xstrdup(value);
+ else if (!strcmp(name, "http-backend-path"))
+ ctx.cfg.http_backend_path = xstrdup(value);
else if (!strcmp(name, "logo"))
ctx.cfg.logo = xstrdup(value);
else if (!strcmp(name, "index-header"))
@@ -353,6 +355,7 @@ static void prepare_context(void)
ctx.cfg.css = "/cgit.css";
ctx.cfg.logo = "/cgit.png";
ctx.cfg.favicon = "/favicon.ico";
+ ctx.cfg.http_backend_path = NULL;
ctx.cfg.local_time = 0;
ctx.cfg.enable_http_clone = 1;
ctx.cfg.enable_index_owner = 1;
diff --git a/cgit.h b/cgit.h
index 42140ac..dcd44f0 100644
--- a/cgit.h
+++ b/cgit.h
@@ -190,6 +190,7 @@ struct cgit_config {
char *footer;
char *head_include;
char *header;
+ char *http_backend_path;
char *index_header;
char *index_info;
char *logo;
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index be6703f..62b73ba 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -218,6 +218,11 @@ header::
The content of the file specified with this option will be included
verbatim at the top of all pages. Default value: none.
+http-backend-path::
+ Path to the git-http-backend smart HTTP backend binary. Setting this
+ allows the git clone to fetch/push via Git over HTTP. You'll also
+ need to enable enable-http-clone for this to work. Default value: none.
+
include::
Name of a configfile to include before the rest of the current config-
file is parsed. Default value: none. See also: "MACRO EXPANSION".
@@ -766,6 +771,9 @@ enable-index-owner=1
# Allow http transport git clone
enable-http-clone=1
+# Use Git over HTTP
+http-backend-path=/usr/lib/git-core/git-http-backend
+
# Show extra links for each repository on the index page
enable-index-links=1
diff --git a/cmd.c b/cmd.c
index 188cd56..889ed05 100644
--- a/cmd.c
+++ b/cmd.c
@@ -136,6 +136,16 @@ static void tree_fn(void)
cgit_print_tree(ctx.qry.sha1, ctx.qry.path);
}
+static void git_upload_pack_fn(void)
+{
+ cgit_clone_git_upload_pack();
+}
+
+static void git_receive_pack_fn(void)
+{
+ cgit_clone_git_receive_pack();
+}
+
#define def_cmd(name, want_repo, want_layout, want_vpath, is_clone) \
{#name, name##_fn, want_repo, want_layout, want_vpath, is_clone}
@@ -162,6 +172,8 @@ struct cgit_cmd *cgit_get_cmd(void)
def_cmd(summary, 1, 1, 0, 0),
def_cmd(tag, 1, 1, 0, 0),
def_cmd(tree, 1, 1, 1, 0),
+ {"git-upload-pack", git_upload_pack_fn, 1, 0, 0, 1},
+ {"git-receive-pack", git_receive_pack_fn, 1, 0, 0, 1},
};
int i;
diff --git a/ui-clone.c b/ui-clone.c
index a4ffd6e..15bd78b 100644
--- a/ui-clone.c
+++ b/ui-clone.c
@@ -69,8 +69,42 @@ static void send_file(char *path)
html_include(path);
}
+static void dispatch_to_git_http_backend(void)
+{
+ if (access(ctx.cfg.http_backend_path, X_OK) != -1) {
+ size_t git_root_len;
+ char *git_root = NULL;
+
+ // git-http-backend does it's own URL parsing and concatenates
+ // GIT_PROJECT_ROOT and PATH_INFO to find the git repo.
+ // The root is the same as scan-path, but scan-path is not
+ // always available so we calculate the root path.
+ // Example:
+ // repo.path = /srv/git/some/more/dirs/
+ // qry.repo = some/more/dirs
+ // -> git_root = /srv/git/
+ strip_suffix(ctx.repo->path, "/", &git_root_len);
+ strip_suffix_mem(ctx.repo->path, &git_root_len, ctx.qry.repo);
+
+ git_root = xmalloc(git_root_len);
+ strncpy(git_root, ctx.repo->path, git_root_len);
+ git_root[git_root_len] = '\0';
+
+ setenv("GIT_PROJECT_ROOT", git_root, 1);
+ execl(ctx.cfg.http_backend_path, "git-http-backend", NULL);
+ } else {
+ fprintf(stderr, "[cgit] http-backend-path (%s) is not executable: %s\n",
+ ctx.cfg.http_backend_path, strerror(errno));
+ html_status(500, "Internal Server Error", 0);
+ }
+}
+
void cgit_clone_info(void)
{
+ if (ctx.cfg.http_backend_path) {
+ return dispatch_to_git_http_backend();
+ }
+
if (!ctx.qry.path || strcmp(ctx.qry.path, "refs"))
return;
@@ -82,6 +116,10 @@ void cgit_clone_info(void)
void cgit_clone_objects(void)
{
+ if (ctx.cfg.http_backend_path) {
+ return dispatch_to_git_http_backend();
+ }
+
if (!ctx.qry.path) {
html_status(400, "Bad request", 0);
return;
@@ -97,5 +135,27 @@ void cgit_clone_objects(void)
void cgit_clone_head(void)
{
+ if (ctx.cfg.http_backend_path) {
+ return dispatch_to_git_http_backend();
+ }
+
send_file(git_path("%s", "HEAD"));
}
+
+void cgit_clone_git_upload_pack(void)
+{
+ if (ctx.cfg.http_backend_path) {
+ return dispatch_to_git_http_backend();
+ }
+
+ html_status(404, "Not found", 0);
+}
+
+void cgit_clone_git_receive_pack(void)
+{
+ if (ctx.cfg.http_backend_path) {
+ return dispatch_to_git_http_backend();
+ }
+
+ html_status(404, "Not found", 0);
+}
diff --git a/ui-clone.h b/ui-clone.h
index 3e460a3..b27087e 100644
--- a/ui-clone.h
+++ b/ui-clone.h
@@ -4,5 +4,7 @@
void cgit_clone_info(void);
void cgit_clone_objects(void);
void cgit_clone_head(void);
+void cgit_clone_git_upload_pack(void);
+void cgit_clone_git_receive_pack(void);
#endif /* UI_CLONE_H */
--
2.2.1
More information about the CGit
mailing list