diff options
Diffstat (limited to 'serve.c')
-rw-r--r-- | serve.c | 70 |
1 files changed, 59 insertions, 11 deletions
@@ -3,11 +3,13 @@ #include "config.h" #include "pkt-line.h" #include "version.h" -#include "argv-array.h" +#include "strvec.h" #include "ls-refs.h" #include "serve.h" #include "upload-pack.h" +static int advertise_sid; + static int always_advertise(struct repository *r, struct strbuf *value) { @@ -22,6 +24,23 @@ static int agent_advertise(struct repository *r, return 1; } +static int object_format_advertise(struct repository *r, + struct strbuf *value) +{ + if (value) + strbuf_addstr(value, r->hash_algo->name); + return 1; +} + +static int session_id_advertise(struct repository *r, struct strbuf *value) +{ + if (!advertise_sid) + return 0; + if (value) + strbuf_addstr(value, trace2_session_id()); + return 1; +} + struct protocol_capability { /* * The name of the capability. The server uses this name when @@ -48,7 +67,7 @@ struct protocol_capability { * This field should be NULL for capabilities which are not commands. */ int (*command)(struct repository *r, - struct argv_array *keys, + struct strvec *keys, struct packet_reader *request); }; @@ -57,6 +76,8 @@ static struct protocol_capability capabilities[] = { { "ls-refs", always_advertise, ls_refs }, { "fetch", upload_pack_advertise, upload_pack_v2 }, { "server-option", always_advertise, NULL }, + { "object-format", object_format_advertise, NULL }, + { "session-id", session_id_advertise, NULL }, }; static void advertise_capabilities(void) @@ -133,13 +154,13 @@ static int is_command(const char *key, struct protocol_capability **command) return 0; } -int has_capability(const struct argv_array *keys, const char *capability, +int has_capability(const struct strvec *keys, const char *capability, const char **value) { int i; - for (i = 0; i < keys->argc; i++) { + for (i = 0; i < keys->nr; i++) { const char *out; - if (skip_prefix(keys->argv[i], capability, &out) && + if (skip_prefix(keys->v[i], capability, &out) && (!*out || *out == '=')) { if (value) { if (*out == '=') @@ -153,6 +174,22 @@ int has_capability(const struct argv_array *keys, const char *capability, return 0; } +static void check_algorithm(struct repository *r, struct strvec *keys) +{ + int client = GIT_HASH_SHA1, server = hash_algo_by_ptr(r->hash_algo); + const char *algo_name; + + if (has_capability(keys, "object-format", &algo_name)) { + client = hash_algo_by_name(algo_name); + if (client == GIT_HASH_UNKNOWN) + die("unknown object format '%s'", algo_name); + } + + if (client != server) + die("mismatched object format: server %s; client %s\n", + r->hash_algo->name, hash_algos[client].name); +} + enum request_state { PROCESS_REQUEST_KEYS, PROCESS_REQUEST_DONE, @@ -162,12 +199,14 @@ static int process_request(void) { enum request_state state = PROCESS_REQUEST_KEYS; struct packet_reader reader; - struct argv_array keys = ARGV_ARRAY_INIT; + struct strvec keys = STRVEC_INIT; struct protocol_capability *command = NULL; + const char *client_sid; packet_reader_init(&reader, 0, NULL, 0, PACKET_READ_CHOMP_NEWLINE | - PACKET_READ_GENTLE_ON_EOF); + PACKET_READ_GENTLE_ON_EOF | + PACKET_READ_DIE_ON_ERR_PACKET); /* * Check to see if the client closed their end before sending another @@ -175,7 +214,7 @@ static int process_request(void) */ if (packet_reader_peek(&reader) == PACKET_READ_EOF) return 1; - reader.options = PACKET_READ_CHOMP_NEWLINE; + reader.options &= ~PACKET_READ_GENTLE_ON_EOF; while (state != PROCESS_REQUEST_DONE) { switch (packet_reader_peek(&reader)) { @@ -185,7 +224,7 @@ static int process_request(void) /* collect request; a sequence of keys and values */ if (is_command(reader.line, &command) || is_valid_capability(reader.line)) - argv_array_push(&keys, reader.line); + strvec_push(&keys, reader.line); else die("unknown capability '%s'", reader.line); @@ -197,7 +236,7 @@ static int process_request(void) * If no command and no keys were given then the client * wanted to terminate the connection. */ - if (!keys.argc) + if (!keys.nr) return 1; /* @@ -216,21 +255,30 @@ static int process_request(void) state = PROCESS_REQUEST_DONE; break; + case PACKET_READ_RESPONSE_END: + BUG("unexpected stateless separator packet"); } } if (!command) die("no command requested"); + check_algorithm(the_repository, &keys); + + if (has_capability(&keys, "session-id", &client_sid)) + trace2_data_string("transfer", NULL, "client-sid", client_sid); + command->command(the_repository, &keys, &reader); - argv_array_clear(&keys); + strvec_clear(&keys); return 0; } /* Main serve loop for protocol version 2 */ void serve(struct serve_options *options) { + git_config_get_bool("transfer.advertisesid", &advertise_sid); + if (options->advertise_capabilities || !options->stateless_rpc) { /* serve by default supports v2 */ packet_write_fmt(1, "version 2\n"); |