Fix several bugs identified in v3, clarify commit message, and clean up
extern keyword in protocol.h.
Josh Steadmon (1):
protocol: advertise multiple supported versions
builtin/archive.c | 3 +
builtin/clone.c | 4 ++
builtin/fetch-pack.c | 4 ++
builtin/fetch.c | 5 ++
builtin/ls-remote.c | 5 ++
builtin/pull.c | 5 ++
builtin/push.c | 4 ++
builtin/receive-pack.c | 3 +
builtin/send-pack.c | 3 +
builtin/upload-archive.c | 3 +
builtin/upload-pack.c | 4 ++
connect.c | 47 +++++++--------
protocol.c | 122 ++++++++++++++++++++++++++++++++++++---
protocol.h | 23 +++++++-
remote-curl.c | 28 ++++++---
t/t5570-git-daemon.sh | 2 +-
t/t5700-protocol-v1.sh | 8 +--
t/t5702-protocol-v2.sh | 16 +++--
transport-helper.c | 6 ++
19 files changed, 237 insertions(+), 58 deletions(-)
Range-diff against v3:
1: b9968e3fb0 ! 1: 3c023991c0 protocol: advertise multiple supported versions
@@ -4,22 +4,25 @@
Currently the client advertises that it supports the wire protocol
version set in the protocol.version config. However, not all services
- support the same set of protocol versions. When connecting to
- git-receive-pack, the client automatically downgrades to v0 if
- config.protocol is set to v2, but this check is not performed for other
- services.
+ support the same set of protocol versions. For example,
git-receive-pack
+ supports v1 and v0, but not v2. If a client connects to
git-receive-pack
+ and requests v2, it will instead be downgraded to v0. Other services,
+ such as git-upload-archive, do not do any version negotiation checks.
- This patch creates a protocol version registry. Individual operations
- register all the protocol versions they support prior to communicating
- with a server. Versions should be listed in preference order; the
- version specified in protocol.version will automatically be moved to
the
- front of the registry.
+ This patch creates a protocol version registry. Individual client and
+ server programs register all the protocol versions they support prior
to
+ communicating with a remote instance. Versions should be listed in
+ preference order; the version specified in protocol.version will
+ automatically be moved to the front of the registry.
The protocol version registry is passed to remote helpers via the
GIT_PROTOCOL environment variable.
Clients now advertise the full list of registered versions. Servers
- select the first recognized version from this advertisement.
+ select the first allowed version from this advertisement.
+
+ While we're at it, remove unnecessary externs from function
declarations
+ in protocol.h.
Signed-off-by: Josh Steadmon <[email protected]>
@@ -165,6 +168,20 @@
git_config(git_push_config, &flags);
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
+ diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
+ --- a/builtin/receive-pack.c
+ +++ b/builtin/receive-pack.c
+@@
+
+ packet_trace_identity("receive-pack");
+
++ register_allowed_protocol_version(protocol_v1);
++ register_allowed_protocol_version(protocol_v0);
++
+ argc = parse_options(argc, argv, prefix, options, receive_pack_usage,
0);
+
+ if (argc > 1)
+
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -179,6 +196,42 @@
argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);
if (argc > 0) {
+ diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
+ --- a/builtin/upload-archive.c
+ +++ b/builtin/upload-archive.c
+@@
+ #include "builtin.h"
+ #include "archive.h"
+ #include "pkt-line.h"
++#include "protocol.h"
+ #include "sideband.h"
+ #include "run-command.h"
+ #include "argv-array.h"
+@@
+ if (argc == 2 && !strcmp(argv[1], "-h"))
+ usage(upload_archive_usage);
+
++ register_allowed_protocol_version(protocol_v0);
++
+ /*
+ * Set up sideband subprocess.
+ *
+
+ diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
+ --- a/builtin/upload-pack.c
+ +++ b/builtin/upload-pack.c
+@@
+ packet_trace_identity("upload-pack");
+ read_replace_refs = 0;
+
++ register_allowed_protocol_version(protocol_v2);
++ register_allowed_protocol_version(protocol_v1);
++ register_allowed_protocol_version(protocol_v0);
++
+ argc = parse_options(argc, argv, NULL, options, upload_pack_usage, 0);
+
+ if (argc != 1)
+
diff --git a/connect.c b/connect.c
--- a/connect.c
+++ b/connect.c
@@ -311,7 +364,7 @@
+static enum protocol_version *allowed_versions;
+static int nr_allowed_versions;
+static int alloc_allowed_versions;
-+static int have_advertised_versions_already = 0;
++static int version_registration_locked = 0;
+
+static const char protocol_v0_string[] = "0";
+static const char protocol_v1_string[] = "1";
@@ -357,8 +410,8 @@
+void register_allowed_protocol_version(enum protocol_version version)
+{
-+ if (have_advertised_versions_already)
-+ BUG(_("attempting to register an allowed protocol version after
advertisement"));
++ if (version_registration_locked)
++ BUG("late attempt to register an allowed protocol version");
+
+ ALLOC_GROW(allowed_versions, nr_allowed_versions + 1,
+ alloc_allowed_versions);
@@ -384,13 +437,23 @@
+ string_list_clear(&version_list, 0);
+}
+
++static int is_allowed_protocol_version(enum protocol_version version)
++{
++ int i;
++ version_registration_locked = 1;
++ for (i = 0; i < nr_allowed_versions; i++)
++ if (version == allowed_versions[i])
++ return 1;
++ return 0;
++}
++
+void get_client_protocol_version_advertisement(struct strbuf *advert)
+{
-+ int tmp_nr = nr_allowed_versions;
++ int i, tmp_nr = nr_allowed_versions;
+ enum protocol_version *tmp_allowed_versions, config_version;
+ strbuf_reset(advert);
+
-+ have_advertised_versions_already = 1;
++ version_registration_locked = 1;
+
+ config_version = get_protocol_version_config();
+ if (config_version == protocol_v0) {
@@ -409,20 +472,19 @@
+ }
+
+ if (tmp_allowed_versions[0] != config_version)
-+ for (int i = 1; i < nr_allowed_versions; i++)
++ for (i = 1; i < nr_allowed_versions; i++)
+ if (tmp_allowed_versions[i] == config_version) {
-+ enum protocol_version swap =
-+ tmp_allowed_versions[0];
-+ tmp_allowed_versions[0] =
-+ tmp_allowed_versions[i];
-+ tmp_allowed_versions[i] = swap;
++ SWAP(tmp_allowed_versions[0],
++ tmp_allowed_versions[i]);
+ }
+
+ strbuf_addf(advert, "version=%s",
+ format_protocol_version(tmp_allowed_versions[0]));
-+ for (int i = 1; i < tmp_nr; i++)
++ for (i = 1; i < tmp_nr; i++)
+ strbuf_addf(advert, ":version=%s",
+ format_protocol_version(tmp_allowed_versions[i]));
++
++ free(tmp_allowed_versions);
+}
+
enum protocol_version determine_protocol_version_server(void)
@@ -447,7 +509,8 @@
if (skip_prefix(item->string, "version=", &value)) {
v = parse_protocol_version(value);
- if (v > version)
-+ if (v != protocol_unknown_version) {
++ if (v != protocol_unknown_version &&
++ is_allowed_protocol_version(v)) {
version = v;
+ break;
+ }
@@ -459,29 +522,46 @@
--- a/protocol.h
+++ b/protocol.h
@@
+ * 'protocol.version' config. If unconfigured, a value of 'protocol_v0'
is
+ * returned.
*/
- extern enum protocol_version get_protocol_version_config(void);
-
+-extern enum protocol_version get_protocol_version_config(void);
++enum protocol_version get_protocol_version_config(void);
++
+/*
+ * Register an allowable protocol version for a given operation.
Registration
+ * must occur before attempting to advertise a version to a server
process.
+ */
-+extern void register_allowed_protocol_version(enum protocol_version
version);
++void register_allowed_protocol_version(enum protocol_version version);
+
+/*
+ * Register allowable protocol versions from the GIT_PROTOCOL environment
var.
+ */
-+extern void register_allowed_protocol_versions_from_env(void);
++void register_allowed_protocol_versions_from_env(void);
+
+/*
+ * Fill a strbuf with a version advertisement string suitable for use in
the
+ * GIT_PROTOCOL environment variable or similar version negotiation field.
+ */
-+extern void get_client_protocol_version_advertisement(struct strbuf
*advert);
-+
++void get_client_protocol_version_advertisement(struct strbuf *advert);
+
/*
* Used by a server to determine which protocol version should be used
based on
- * a client's request, communicated via the 'GIT_PROTOCOL' environment
variable
+@@
+ * request a particular protocol version, a default of 'protocol_v0' will
be
+ * used.
+ */
+-extern enum protocol_version determine_protocol_version_server(void);
++enum protocol_version determine_protocol_version_server(void);
+
+ /*
+ * Used by a client to determine which protocol version the server is
speaking
+ * based on the server's initial response.
+ */
+-extern enum protocol_version determine_protocol_version_client(const char
*server_response);
++enum protocol_version determine_protocol_version_client(const char
*server_response);
+
+ #endif /* PROTOCOL_H */
diff --git a/remote-curl.c b/remote-curl.c
--- a/remote-curl.c
--
2.19.1.930.g4563a0d9d0-goog