From 4f5e9b0d6c1090681c489a10179ff1a7c215ac19 Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Mon, 29 Dec 2014 17:05:07 +0100 Subject: Support Git over HTTP using git-http-backend 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 --- cgit.c | 3 +++ cgit.h | 1 + cgitrc.5.txt | 8 ++++++++ cmd.c | 12 ++++++++++++ ui-clone.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ui-clone.h | 2 ++ 6 files changed, 87 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..91d8306 100644 --- a/ui-clone.c +++ b/ui-clone.c @@ -69,8 +69,43 @@ 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 + 1); + 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 +117,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 +136,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 */ -- cgit v1.2.3-24-g4f1b