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