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