]> git.ipfire.org Git - thirdparty/git.git/blame - serve.c
Git 2.45-rc0
[thirdparty/git.git] / serve.c
CommitLineData
15db4e7f 1#include "git-compat-util.h"
ed10cb95
BW
2#include "repository.h"
3#include "config.h"
b9a7ac2c 4#include "hash-ll.h"
ed10cb95
BW
5#include "pkt-line.h"
6#include "version.h"
72d0ea00 7#include "ls-refs.h"
a2ba162c 8#include "protocol-caps.h"
ed10cb95 9#include "serve.h"
3145ea95 10#include "upload-pack.h"
8b8d9a22 11#include "bundle-uri.h"
15db4e7f 12#include "trace2.h"
ed10cb95 13
eea7f7a9 14static int advertise_sid = -1;
8c735b11 15static int advertise_object_info = -1;
c7d3aabd 16static int client_hash_algo = GIT_HASH_SHA1;
6b5b6e42 17
74595cca
JK
18static int always_advertise(struct repository *r UNUSED,
19 struct strbuf *value UNUSED)
72d0ea00
BW
20{
21 return 1;
22}
23
74595cca 24static int agent_advertise(struct repository *r UNUSED,
ed10cb95
BW
25 struct strbuf *value)
26{
27 if (value)
28 strbuf_addstr(value, git_user_agent_sanitized());
29 return 1;
30}
31
9de0dd36 32static int object_format_advertise(struct repository *r,
33 struct strbuf *value)
34{
35 if (value)
36 strbuf_addstr(value, r->hash_algo->name);
37 return 1;
38}
39
74595cca 40static void object_format_receive(struct repository *r UNUSED,
c7d3aabd
JK
41 const char *algo_name)
42{
43 if (!algo_name)
44 die("object-format capability requires an argument");
45
46 client_hash_algo = hash_algo_by_name(algo_name);
47 if (client_hash_algo == GIT_HASH_UNKNOWN)
48 die("unknown object format '%s'", algo_name);
49}
50
6b5b6e42
JS
51static int session_id_advertise(struct repository *r, struct strbuf *value)
52{
eea7f7a9 53 if (advertise_sid == -1 &&
4b4e75dd 54 repo_config_get_bool(r, "transfer.advertisesid", &advertise_sid))
eea7f7a9 55 advertise_sid = 0;
6b5b6e42
JS
56 if (!advertise_sid)
57 return 0;
58 if (value)
59 strbuf_addstr(value, trace2_session_id());
60 return 1;
61}
62
74595cca 63static void session_id_receive(struct repository *r UNUSED,
ab539c90
JK
64 const char *client_sid)
65{
66 if (!client_sid)
67 client_sid = "";
68 trace2_data_string("transfer", NULL, "client-sid", client_sid);
69}
70
8c735b11
TB
71static int object_info_advertise(struct repository *r, struct strbuf *value UNUSED)
72{
73 if (advertise_object_info == -1 &&
74 repo_config_get_bool(r, "transfer.advertiseobjectinfo",
75 &advertise_object_info)) {
76 /* disabled by default */
77 advertise_object_info = 0;
78 }
79 return advertise_object_info;
80}
81
ed10cb95
BW
82struct protocol_capability {
83 /*
84 * The name of the capability. The server uses this name when
85 * advertising this capability, and the client uses this name to
86 * specify this capability.
87 */
88 const char *name;
89
90 /*
91 * Function queried to see if a capability should be advertised.
92 * Optionally a value can be specified by adding it to 'value'.
93 * If a value is added to 'value', the server will advertise this
94 * capability as "<name>=<value>" instead of "<name>".
95 */
96 int (*advertise)(struct repository *r, struct strbuf *value);
97
98 /*
99 * Function called when a client requests the capability as a command.
28a592e4 100 * Will be provided a struct packet_reader 'request' which it should
ed10cb95
BW
101 * use to read the command specific part of the request. Every command
102 * MUST read until a flush packet is seen before sending a response.
103 *
104 * This field should be NULL for capabilities which are not commands.
105 */
28a592e4 106 int (*command)(struct repository *r, struct packet_reader *request);
e56e5306
JK
107
108 /*
109 * Function called when a client requests the capability as a
110 * non-command. This may be NULL if the capability does nothing.
111 *
112 * For a capability of the form "foo=bar", the value string points to
113 * the content after the "=" (i.e., "bar"). For simple capabilities
114 * (just "foo"), it is NULL.
115 */
116 void (*receive)(struct repository *r, const char *value);
ed10cb95
BW
117};
118
119static struct protocol_capability capabilities[] = {
85baaed4
ÆAB
120 {
121 .name = "agent",
122 .advertise = agent_advertise,
123 },
124 {
125 .name = "ls-refs",
126 .advertise = ls_refs_advertise,
127 .command = ls_refs,
128 },
129 {
130 .name = "fetch",
131 .advertise = upload_pack_advertise,
132 .command = upload_pack_v2,
133 },
134 {
135 .name = "server-option",
136 .advertise = always_advertise,
137 },
138 {
139 .name = "object-format",
140 .advertise = object_format_advertise,
c7d3aabd 141 .receive = object_format_receive,
85baaed4
ÆAB
142 },
143 {
144 .name = "session-id",
145 .advertise = session_id_advertise,
ab539c90 146 .receive = session_id_receive,
85baaed4
ÆAB
147 },
148 {
149 .name = "object-info",
8c735b11 150 .advertise = object_info_advertise,
85baaed4
ÆAB
151 .command = cap_object_info,
152 },
8b8d9a22
ÆAB
153 {
154 .name = "bundle-uri",
155 .advertise = bundle_uri_advertise,
156 .command = bundle_uri_command,
157 },
ed10cb95
BW
158};
159
f234da80 160void protocol_v2_advertise_capabilities(void)
ed10cb95
BW
161{
162 struct strbuf capability = STRBUF_INIT;
163 struct strbuf value = STRBUF_INIT;
164 int i;
165
5befe8a1
ÆAB
166 /* serve by default supports v2 */
167 packet_write_fmt(1, "version 2\n");
168
ed10cb95
BW
169 for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
170 struct protocol_capability *c = &capabilities[i];
171
172 if (c->advertise(the_repository, &value)) {
173 strbuf_addstr(&capability, c->name);
174
175 if (value.len) {
176 strbuf_addch(&capability, '=');
177 strbuf_addbuf(&capability, &value);
178 }
179
180 strbuf_addch(&capability, '\n');
181 packet_write(1, capability.buf, capability.len);
182 }
183
184 strbuf_reset(&capability);
185 strbuf_reset(&value);
186 }
187
188 packet_flush(1);
189 strbuf_release(&capability);
190 strbuf_release(&value);
191}
192
5ef260d2 193static struct protocol_capability *get_capability(const char *key, const char **value)
ed10cb95
BW
194{
195 int i;
196
197 if (!key)
198 return NULL;
199
200 for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
201 struct protocol_capability *c = &capabilities[i];
202 const char *out;
5ef260d2
JK
203 if (!skip_prefix(key, c->name, &out))
204 continue;
205 if (!*out) {
206 *value = NULL;
ed10cb95 207 return c;
5ef260d2
JK
208 }
209 if (*out++ == '=') {
210 *value = out;
211 return c;
212 }
ed10cb95
BW
213 }
214
215 return NULL;
216}
217
e56e5306 218static int receive_client_capability(const char *key)
ed10cb95 219{
5ef260d2
JK
220 const char *value;
221 const struct protocol_capability *c = get_capability(key, &value);
ed10cb95 222
0ab7eecc 223 if (!c || c->command || !c->advertise(the_repository, NULL))
e56e5306
JK
224 return 0;
225
226 if (c->receive)
227 c->receive(the_repository, value);
228 return 1;
ed10cb95
BW
229}
230
76804526 231static int parse_command(const char *key, struct protocol_capability **command)
ed10cb95
BW
232{
233 const char *out;
234
235 if (skip_prefix(key, "command=", &out)) {
5ef260d2
JK
236 const char *value;
237 struct protocol_capability *cmd = get_capability(out, &value);
ed10cb95
BW
238
239 if (*command)
240 die("command '%s' requested after already requesting command '%s'",
241 out, (*command)->name);
108c265f 242 if (!cmd || !cmd->advertise(the_repository, NULL) || !cmd->command || value)
ed10cb95
BW
243 die("invalid command '%s'", out);
244
245 *command = cmd;
246 return 1;
247 }
248
249 return 0;
250}
251
ed10cb95
BW
252enum request_state {
253 PROCESS_REQUEST_KEYS,
254 PROCESS_REQUEST_DONE,
255};
256
257static int process_request(void)
258{
259 enum request_state state = PROCESS_REQUEST_KEYS;
260 struct packet_reader reader;
f0a35c9c 261 int seen_capability_or_command = 0;
ed10cb95
BW
262 struct protocol_capability *command = NULL;
263
264 packet_reader_init(&reader, 0, NULL, 0,
265 PACKET_READ_CHOMP_NEWLINE |
2d103c31
MS
266 PACKET_READ_GENTLE_ON_EOF |
267 PACKET_READ_DIE_ON_ERR_PACKET);
ed10cb95
BW
268
269 /*
270 * Check to see if the client closed their end before sending another
271 * request. If so we can terminate the connection.
272 */
273 if (packet_reader_peek(&reader) == PACKET_READ_EOF)
274 return 1;
2d103c31 275 reader.options &= ~PACKET_READ_GENTLE_ON_EOF;
ed10cb95
BW
276
277 while (state != PROCESS_REQUEST_DONE) {
278 switch (packet_reader_peek(&reader)) {
279 case PACKET_READ_EOF:
280 BUG("Should have already died when seeing EOF");
281 case PACKET_READ_NORMAL:
76804526 282 if (parse_command(reader.line, &command) ||
e56e5306 283 receive_client_capability(reader.line))
f0a35c9c 284 seen_capability_or_command = 1;
ed10cb95
BW
285 else
286 die("unknown capability '%s'", reader.line);
287
288 /* Consume the peeked line */
289 packet_reader_read(&reader);
290 break;
291 case PACKET_READ_FLUSH:
292 /*
293 * If no command and no keys were given then the client
294 * wanted to terminate the connection.
295 */
f0a35c9c 296 if (!seen_capability_or_command)
ed10cb95
BW
297 return 1;
298
299 /*
300 * The flush packet isn't consume here like it is in
301 * the other parts of this switch statement. This is
302 * so that the command can read the flush packet and
303 * see the end of the request in the same way it would
304 * if command specific arguments were provided after a
305 * delim packet.
306 */
307 state = PROCESS_REQUEST_DONE;
308 break;
309 case PACKET_READ_DELIM:
310 /* Consume the peeked line */
311 packet_reader_read(&reader);
312
313 state = PROCESS_REQUEST_DONE;
314 break;
0181b600 315 case PACKET_READ_RESPONSE_END:
8232a0ff 316 BUG("unexpected response end packet");
ed10cb95
BW
317 }
318 }
319
320 if (!command)
321 die("no command requested");
322
c7d3aabd
JK
323 if (client_hash_algo != hash_algo_by_ptr(the_repository->hash_algo))
324 die("mismatched object format: server %s; client %s\n",
325 the_repository->hash_algo->name,
326 hash_algos[client_hash_algo].name);
9de0dd36 327
28a592e4 328 command->command(the_repository, &reader);
ed10cb95 329
ed10cb95
BW
330 return 0;
331}
332
f234da80 333void protocol_v2_serve_loop(int stateless_rpc)
ed10cb95 334{
f234da80
ÆAB
335 if (!stateless_rpc)
336 protocol_v2_advertise_capabilities();
ed10cb95
BW
337
338 /*
339 * If stateless-rpc was requested then exit after
340 * a single request/response exchange
341 */
f234da80 342 if (stateless_rpc) {
ed10cb95
BW
343 process_request();
344 } else {
345 for (;;)
346 if (process_request())
347 break;
348 }
349}