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 */