aboutsummaryrefslogtreecommitdiffstats
path: root/www-apps/cgit/files/cgit-1.2.3-git-http-backend.patch
blob: 93bd4eb12ea2e9ed2fce8838cc28426bacfb2def (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
From 6c9eb981818260af3b7f4235185ab8b0f94c4f5e Mon Sep 17 00:00:00 2001
From: Wynn Wolf Arbor <wolf@oriole.systems>
Date: Sat, 30 May 2020 21:51:39 +0200
Subject: [PATCH] Support Git over HTTP by proxying git-http-backend(1)

cgit lacks an easy way to support the "smart" HTTP protocol out of the
box. A patch [1] has been proposed in the past, but was never merged.
A few years later there was a short discussion at [2] which did not go
anywhere.

The majority of users who want to support the "smart" HTTP protocol
right now seem to conditionally point their web server to
git-http-backend(1) directly. This relies on proper path-matching and
regular expression support in the web server as seen in the EXMAPLES
section of git-http-backend(1).

As proposed in [3], it is possible to have cgit interface with the
necessary functionality in Git directly, but that would require more
work. It does not seem that this is something forthcoming in cgit.

Instead, for now, use a modified version of the patch suggested in [1],
which simply executes git-http-backend(1) when needed. This removes the
need for any additional plumbing in the web server.

Notable changes to the original patch:

 * Remove automatic handling of GIT_PROJECT_ROOT in favour of having the
   user set the variable correctly themselves. This reduces complexity.

 * Use the correct function to generate error pages. The original patch
   used html_status(), which does not exist anymore.

 * In cmd.c, adjust the struct entries to fit. Sadly we cannot use the
   def_cmd() macro directly, as the endpoints "git-upload-pack" and
   "git-receive-pack" contain dashes.

 * The original patch did not account for caching support, which will
   break the whole clone process if enabled. Work around this by
   disabling the cache for commands that have is_clone set to true.

[1] https://lists.zx2c4.com/pipermail/cgit/2014-December/002312.html
[2] https://lists.zx2c4.com/pipermail/cgit/2016-February/002907.html
[3] https://lists.zx2c4.com/pipermail/cgit/2016-February/002926.html
---
 cache.c      | 11 +++++++++++
 cgit.c       |  3 +++
 cgit.h       |  1 +
 cgitrc.5.txt |  8 ++++++++
 cmd.c        | 13 +++++++++++++
 ui-clone.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 ui-clone.h   |  2 ++
 7 files changed, 80 insertions(+)

diff --git a/cache.c b/cache.c
index 2c70be7..bb4fc47 100644
--- a/cache.c
+++ b/cache.c
@@ -15,6 +15,7 @@
 
 #include "cgit.h"
 #include "cache.h"
+#include "cmd.h"
 #include "html.h"
 #ifdef HAVE_LINUX_SENDFILE
 #include <sys/sendfile.h>
@@ -356,6 +357,7 @@ int cache_process(int size, const char *path, const char *key, int ttl,
 	struct strbuf filename = STRBUF_INIT;
 	struct strbuf lockname = STRBUF_INIT;
 	struct cache_slot slot;
+	struct cgit_cmd *cmd;
 	int result;
 
 	/* If the cache is disabled, just generate the content */
@@ -370,6 +372,15 @@ int cache_process(int size, const char *path, const char *key, int ttl,
 		fn();
 		return 0;
 	}
+
+	cmd = cgit_get_cmd();
+
+	/* Do not cache files that are being cloned */
+	if (cmd && cmd->is_clone) {
+		fn();
+		return 0;
+	}
+
 	if (!key)
 		key = "";
 	hash = hash_str(key) % size;
diff --git a/cgit.c b/cgit.c
index c4320f0..fc85c18 100644
--- a/cgit.c
+++ b/cgit.c
@@ -151,6 +151,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, "logo-link"))
@@ -379,6 +381,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 7ec46b4..cd29892 100644
--- a/cgit.h
+++ b/cgit.h
@@ -200,6 +200,7 @@ struct cgit_config {
 	char *footer;
 	char *head_include;
 	char *header;
+	char *http_backend_path;
 	char *logo;
 	char *logo_link;
 	char *mimetype_file;
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 33a6a8c..820cfa6 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -234,6 +234,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 binary. Setting this allows the git clone to
+	fetch/push via Git over HTTP. You'll also need to set enable-http-clone
+	for this to work. See git-http-backend(1). 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".
@@ -824,6 +829,9 @@ enable-index-owner=1
 # Allow http transport git clone
 enable-http-clone=1
 
+# Use git-http-backend to serve 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 bf6d8f5..7f1ca98 100644
--- a/cmd.c
+++ b/cmd.c
@@ -164,6 +164,17 @@ 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_vpath, is_clone) \
 	{#name, name##_fn, want_repo, want_vpath, is_clone}
 
@@ -191,6 +202,8 @@ struct cgit_cmd *cgit_get_cmd(void)
 		def_cmd(summary, 1, 0, 0),
 		def_cmd(tag, 1, 0, 0),
 		def_cmd(tree, 1, 1, 0),
+		{"git-upload-pack", git_upload_pack_fn, 1, 0, 1},
+		{"git-receive-pack", git_receive_pack_fn, 1, 0, 1},
 	};
 	int i;
 
diff --git a/ui-clone.c b/ui-clone.c
index 5dccb63..5dea33c 100644
--- a/ui-clone.c
+++ b/ui-clone.c
@@ -77,8 +77,24 @@ static void send_file(const char *path)
 	html_include(path);
 }
 
+static void dispatch_to_git_http_backend(void)
+{
+	if (access(ctx.cfg.http_backend_path, X_OK) == -1) {
+		fprintf(stderr, "[cgit] http-backend-path (%s) is not executable: %s\n",
+				ctx.cfg.http_backend_path, strerror(errno));
+		cgit_print_error_page(500, "Internal Server Error", "Internal Server Error");
+		return;
+	}
+
+	execl(ctx.cfg.http_backend_path, "git-http-backend", NULL);
+}
+
 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")) {
 		cgit_print_error_page(400, "Bad request", "Bad request");
 		return;
@@ -94,6 +110,10 @@ void cgit_clone_objects(void)
 {
 	char *p;
 
+	if (ctx.cfg.http_backend_path) {
+		return dispatch_to_git_http_backend();
+	}
+
 	if (!ctx.qry.path)
 		goto err;
 
@@ -122,5 +142,27 @@ err:
 
 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();
+	}
+
+	cgit_print_error_page(404, "Not found", "Not found");
+}
+
+void cgit_clone_git_receive_pack(void)
+{
+	if (ctx.cfg.http_backend_path) {
+		return dispatch_to_git_http_backend();
+	}
+
+	cgit_print_error_page(404, "Not found", "Not found");
+}
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.27.0