Skip to content

Commit 373d70e

Browse files
bmwillgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5d2124b commit 373d70e

File tree

6 files changed

+144
-0
lines changed

6 files changed

+144
-0
lines changed

Documentation/config.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2517,6 +2517,23 @@ The protocol names currently used by git are:
25172517
`hg` to allow the `git-remote-hg` helper)
25182518
--
25192519

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+
25202537
pull.ff::
25212538
By default, Git does not create an extra merge commit when merging
25222539
a commit that is a descendant of the current commit. Instead, the

Documentation/git.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,12 @@ of clones and fetches.
697697
which feed potentially-untrusted URLS to git commands. See
698698
linkgit:git-config[1] for more details.
699699

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+
700706
Discussion[[Discussion]]
701707
------------------------
702708

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,7 @@ LIB_OBJS += pretty.o
842842
LIB_OBJS += prio-queue.o
843843
LIB_OBJS += progress.o
844844
LIB_OBJS += prompt.o
845+
LIB_OBJS += protocol.o
845846
LIB_OBJS += quote.o
846847
LIB_OBJS += reachable.o
847848
LIB_OBJS += read-cache.o

cache.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,14 @@ static inline enum object_type object_type(unsigned int mode)
445445
#define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
446446
#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
447447

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+
448456
/*
449457
* This environment variable is expected to contain a boolean indicating
450458
* whether we should or should not treat:

protocol.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */

0 commit comments

Comments
 (0)