protocol: introduce protocol extension mechanisms

Create protocol.{c,h} and provide functions which future servers and clients can use to determine which protocol to use or is being used. Also introduce the 'GIT_PROTOCOL' environment variable which will be used to communicate a colon separated list of keys with optional values to a server. Unknown keys and values must be tolerated. This mechanism is used to communicate which version of the wire protocol a client would like to use with a server. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Brandon Williams committed Oct 16, 2017 at 10:55 UTC 373d70efb2278b76739d8c6538d4a4e59cc81bf7
6 files changed +144
Documentation/config.txt
+17
@@ -2517,6 +2517,23 @@ The protocol names currently used by git are:
2517 `hg` to allow the `git-remote-hg` helper)
2518 --
2519
2520 +protocol.version::
2521 + Experimental. If set, clients will attempt to communicate with a
2522 + server using the specified protocol version. If unset, no
2523 + attempt will be made by the client to communicate using a
2524 + particular protocol version, this results in protocol version 0
2525 + being used.
2526 + Supported versions:
2527 ++
2528 +--
2529 +
2530 +* `0` - the original wire protocol.
2531 +
2532 +* `1` - the original wire protocol with the addition of a version string
2533 + in the initial response from the server.
2534 +
2535 +--
2536 +
2537 pull.ff::
2538 By default, Git does not create an extra merge commit when merging
2539 a commit that is a descendant of the current commit. Instead, the
Documentation/git.txt
+6
@@ -697,6 +697,12 @@ of clones and fetches.
697 which feed potentially-untrusted URLS to git commands. See
698 linkgit:git-config[1] for more details.
699
700 +`GIT_PROTOCOL`::
701 + For internal use only. Used in handshaking the wire protocol.
702 + Contains a colon ':' separated list of keys with optional values
703 + 'key[=value]'. Presence of unknown keys and values must be
704 + ignored.
705 +
706 Discussion[[Discussion]]
707 ------------------------
708
Makefile
+1
@@ -842,6 +842,7 @@ LIB_OBJS += pretty.o
842 LIB_OBJS += prio-queue.o
843 LIB_OBJS += progress.o
844 LIB_OBJS += prompt.o
845 +LIB_OBJS += protocol.o
846 LIB_OBJS += quote.o
847 LIB_OBJS += reachable.o
848 LIB_OBJS += read-cache.o
cache.h
+8
@@ -445,6 +445,14 @@ static inline enum object_type object_type(unsigned int mode)
445 #define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
446 #define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
447
448 +/*
449 + * Environment variable used in handshaking the wire protocol.
450 + * Contains a colon ':' separated list of keys with optional values
451 + * 'key[=value]'. Presence of unknown keys and values must be
452 + * ignored.
453 + */
454 +#define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL"
455 +
456 /*
457 * This environment variable is expected to contain a boolean indicating
458 * whether we should or should not treat:
protocol.c new
+79
@@ -0,0 +1,79 @@
1 +#include "cache.h"
2 +#include "config.h"
3 +#include "protocol.h"
4 +
5 +static enum protocol_version parse_protocol_version(const char *value)
6 +{
7 + if (!strcmp(value, "0"))
8 + return protocol_v0;
9 + else if (!strcmp(value, "1"))
10 + return protocol_v1;
11 + else
12 + return protocol_unknown_version;
13 +}
14 +
15 +enum protocol_version get_protocol_version_config(void)
16 +{
17 + const char *value;
18 + if (!git_config_get_string_const("protocol.version", &value)) {
19 + enum protocol_version version = parse_protocol_version(value);
20 +
21 + if (version == protocol_unknown_version)
22 + die("unknown value for config 'protocol.version': %s",
23 + value);
24 +
25 + return version;
26 + }
27 +
28 + return protocol_v0;
29 +}
30 +
31 +enum protocol_version determine_protocol_version_server(void)
32 +{
33 + const char *git_protocol = getenv(GIT_PROTOCOL_ENVIRONMENT);
34 + enum protocol_version version = protocol_v0;
35 +
36 + /*
37 + * Determine which protocol version the client has requested. Since
38 + * multiple 'version' keys can be sent by the client, indicating that
39 + * the client is okay to speak any of them, select the greatest version
40 + * that the client has requested. This is due to the assumption that
41 + * the most recent protocol version will be the most state-of-the-art.
42 + */
43 + if (git_protocol) {
44 + struct string_list list = STRING_LIST_INIT_DUP;
45 + const struct string_list_item *item;
46 + string_list_split(&list, git_protocol, ':', -1);
47 +
48 + for_each_string_list_item(item, &list) {
49 + const char *value;
50 + enum protocol_version v;
51 +
52 + if (skip_prefix(item->string, "version=", &value)) {
53 + v = parse_protocol_version(value);
54 + if (v > version)
55 + version = v;
56 + }
57 + }
58 +
59 + string_list_clear(&list, 0);
60 + }
61 +
62 + return version;
63 +}
64 +
65 +enum protocol_version determine_protocol_version_client(const char *server_response)
66 +{
67 + enum protocol_version version = protocol_v0;
68 +
69 + if (skip_prefix(server_response, "version ", &server_response)) {
70 + version = parse_protocol_version(server_response);
71 +
72 + if (version == protocol_unknown_version)
73 + die("server is speaking an unknown protocol");
74 + if (version == protocol_v0)
75 + die("protocol error: server explicitly said version 0");
76 + }
77 +
78 + return version;
79 +}
protocol.h new
+33
@@ -0,0 +1,33 @@
1 +#ifndef PROTOCOL_H
2 +#define PROTOCOL_H
3 +
4 +enum protocol_version {
5 + protocol_unknown_version = -1,
6 + protocol_v0 = 0,
7 + protocol_v1 = 1,
8 +};
9 +
10 +/*
11 + * Used by a client to determine which protocol version to request be used when
12 + * communicating with a server, reflecting the configured value of the
13 + * 'protocol.version' config. If unconfigured, a value of 'protocol_v0' is
14 + * returned.
15 + */
16 +extern enum protocol_version get_protocol_version_config(void);
17 +
18 +/*
19 + * Used by a server to determine which protocol version should be used based on
20 + * a client's request, communicated via the 'GIT_PROTOCOL' environment variable
21 + * by setting appropriate values for the key 'version'. If a client doesn't
22 + * request a particular protocol version, a default of 'protocol_v0' will be
23 + * used.
24 + */
25 +extern enum protocol_version determine_protocol_version_server(void);
26 +
27 +/*
28 + * Used by a client to determine which protocol version the server is speaking
29 + * based on the server's initial response.
30 + */
31 +extern enum protocol_version determine_protocol_version_client(const char *server_response);
32 +
33 +#endif /* PROTOCOL_H */