Merge branch 'sb/object-store-replace'
[git] / serve.c
1 #include "cache.h"
2 #include "repository.h"
3 #include "config.h"
4 #include "pkt-line.h"
5 #include "version.h"
6 #include "argv-array.h"
7 #include "ls-refs.h"
8 #include "serve.h"
9 #include "upload-pack.h"
10
11 static int always_advertise(struct repository *r,
12                             struct strbuf *value)
13 {
14         return 1;
15 }
16
17 static int agent_advertise(struct repository *r,
18                            struct strbuf *value)
19 {
20         if (value)
21                 strbuf_addstr(value, git_user_agent_sanitized());
22         return 1;
23 }
24
25 struct protocol_capability {
26         /*
27          * The name of the capability.  The server uses this name when
28          * advertising this capability, and the client uses this name to
29          * specify this capability.
30          */
31         const char *name;
32
33         /*
34          * Function queried to see if a capability should be advertised.
35          * Optionally a value can be specified by adding it to 'value'.
36          * If a value is added to 'value', the server will advertise this
37          * capability as "<name>=<value>" instead of "<name>".
38          */
39         int (*advertise)(struct repository *r, struct strbuf *value);
40
41         /*
42          * Function called when a client requests the capability as a command.
43          * The function will be provided the capabilities requested via 'keys'
44          * as well as a struct packet_reader 'request' which the command should
45          * use to read the command specific part of the request.  Every command
46          * MUST read until a flush packet is seen before sending a response.
47          *
48          * This field should be NULL for capabilities which are not commands.
49          */
50         int (*command)(struct repository *r,
51                        struct argv_array *keys,
52                        struct packet_reader *request);
53 };
54
55 static struct protocol_capability capabilities[] = {
56         { "agent", agent_advertise, NULL },
57         { "ls-refs", always_advertise, ls_refs },
58         { "fetch", upload_pack_advertise, upload_pack_v2 },
59 };
60
61 static void advertise_capabilities(void)
62 {
63         struct strbuf capability = STRBUF_INIT;
64         struct strbuf value = STRBUF_INIT;
65         int i;
66
67         for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
68                 struct protocol_capability *c = &capabilities[i];
69
70                 if (c->advertise(the_repository, &value)) {
71                         strbuf_addstr(&capability, c->name);
72
73                         if (value.len) {
74                                 strbuf_addch(&capability, '=');
75                                 strbuf_addbuf(&capability, &value);
76                         }
77
78                         strbuf_addch(&capability, '\n');
79                         packet_write(1, capability.buf, capability.len);
80                 }
81
82                 strbuf_reset(&capability);
83                 strbuf_reset(&value);
84         }
85
86         packet_flush(1);
87         strbuf_release(&capability);
88         strbuf_release(&value);
89 }
90
91 static struct protocol_capability *get_capability(const char *key)
92 {
93         int i;
94
95         if (!key)
96                 return NULL;
97
98         for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
99                 struct protocol_capability *c = &capabilities[i];
100                 const char *out;
101                 if (skip_prefix(key, c->name, &out) && (!*out || *out == '='))
102                         return c;
103         }
104
105         return NULL;
106 }
107
108 static int is_valid_capability(const char *key)
109 {
110         const struct protocol_capability *c = get_capability(key);
111
112         return c && c->advertise(the_repository, NULL);
113 }
114
115 static int is_command(const char *key, struct protocol_capability **command)
116 {
117         const char *out;
118
119         if (skip_prefix(key, "command=", &out)) {
120                 struct protocol_capability *cmd = get_capability(out);
121
122                 if (*command)
123                         die("command '%s' requested after already requesting command '%s'",
124                             out, (*command)->name);
125                 if (!cmd || !cmd->advertise(the_repository, NULL) || !cmd->command)
126                         die("invalid command '%s'", out);
127
128                 *command = cmd;
129                 return 1;
130         }
131
132         return 0;
133 }
134
135 int has_capability(const struct argv_array *keys, const char *capability,
136                    const char **value)
137 {
138         int i;
139         for (i = 0; i < keys->argc; i++) {
140                 const char *out;
141                 if (skip_prefix(keys->argv[i], capability, &out) &&
142                     (!*out || *out == '=')) {
143                         if (value) {
144                                 if (*out == '=')
145                                         out++;
146                                 *value = out;
147                         }
148                         return 1;
149                 }
150         }
151
152         return 0;
153 }
154
155 enum request_state {
156         PROCESS_REQUEST_KEYS,
157         PROCESS_REQUEST_DONE,
158 };
159
160 static int process_request(void)
161 {
162         enum request_state state = PROCESS_REQUEST_KEYS;
163         struct packet_reader reader;
164         struct argv_array keys = ARGV_ARRAY_INIT;
165         struct protocol_capability *command = NULL;
166
167         packet_reader_init(&reader, 0, NULL, 0,
168                            PACKET_READ_CHOMP_NEWLINE |
169                            PACKET_READ_GENTLE_ON_EOF);
170
171         /*
172          * Check to see if the client closed their end before sending another
173          * request.  If so we can terminate the connection.
174          */
175         if (packet_reader_peek(&reader) == PACKET_READ_EOF)
176                 return 1;
177         reader.options = PACKET_READ_CHOMP_NEWLINE;
178
179         while (state != PROCESS_REQUEST_DONE) {
180                 switch (packet_reader_peek(&reader)) {
181                 case PACKET_READ_EOF:
182                         BUG("Should have already died when seeing EOF");
183                 case PACKET_READ_NORMAL:
184                         /* collect request; a sequence of keys and values */
185                         if (is_command(reader.line, &command) ||
186                             is_valid_capability(reader.line))
187                                 argv_array_push(&keys, reader.line);
188                         else
189                                 die("unknown capability '%s'", reader.line);
190
191                         /* Consume the peeked line */
192                         packet_reader_read(&reader);
193                         break;
194                 case PACKET_READ_FLUSH:
195                         /*
196                          * If no command and no keys were given then the client
197                          * wanted to terminate the connection.
198                          */
199                         if (!keys.argc)
200                                 return 1;
201
202                         /*
203                          * The flush packet isn't consume here like it is in
204                          * the other parts of this switch statement.  This is
205                          * so that the command can read the flush packet and
206                          * see the end of the request in the same way it would
207                          * if command specific arguments were provided after a
208                          * delim packet.
209                          */
210                         state = PROCESS_REQUEST_DONE;
211                         break;
212                 case PACKET_READ_DELIM:
213                         /* Consume the peeked line */
214                         packet_reader_read(&reader);
215
216                         state = PROCESS_REQUEST_DONE;
217                         break;
218                 }
219         }
220
221         if (!command)
222                 die("no command requested");
223
224         command->command(the_repository, &keys, &reader);
225
226         argv_array_clear(&keys);
227         return 0;
228 }
229
230 /* Main serve loop for protocol version 2 */
231 void serve(struct serve_options *options)
232 {
233         if (options->advertise_capabilities || !options->stateless_rpc) {
234                 /* serve by default supports v2 */
235                 packet_write_fmt(1, "version 2\n");
236
237                 advertise_capabilities();
238                 /*
239                  * If only the list of capabilities was requested exit
240                  * immediately after advertising capabilities
241                  */
242                 if (options->advertise_capabilities)
243                         return;
244         }
245
246         /*
247          * If stateless-rpc was requested then exit after
248          * a single request/response exchange
249          */
250         if (options->stateless_rpc) {
251                 process_request();
252         } else {
253                 for (;;)
254                         if (process_request())
255                                 break;
256         }
257 }