[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