Web lists-archives.com

[PATCH 1/1] protocol: limit max protocol version per service




For services other than git-receive-pack, clients currently advertise
that they support the version set in the protocol.version config,
regardless of whether or not there is actually an implementation of that
service for the given protocol version. This causes backwards-
compatibility problems when a new implementation for the given
protocol version is added.

This patch sets maximum allowed protocol versions for git-receive-pack,
git-upload-archive, and git-upload-pack.

Previously, git-receive-pack would downgrade from v2 to v0, but would
allow v1 if set in protocol.version. Now, it will downgrade from v2 to
v1.

Signed-off-by: Josh Steadmon <steadmon@xxxxxxxxxx>
---
 connect.c     | 11 ++++-------
 protocol.c    | 13 +++++++++++++
 protocol.h    |  7 +++++++
 remote-curl.c | 11 ++++-------
 4 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/connect.c b/connect.c
index 94547e5056..4a8cd78239 100644
--- a/connect.c
+++ b/connect.c
@@ -1228,14 +1228,11 @@ struct child_process *git_connect(int fd[2], const char *url,
 	struct child_process *conn;
 	enum protocol protocol;
 	enum protocol_version version = get_protocol_version_config();
+	enum protocol_version max_version;
 
-	/*
-	 * NEEDSWORK: If we are trying to use protocol v2 and we are planning
-	 * to perform a push, then fallback to v0 since the client doesn't know
-	 * how to push yet using v2.
-	 */
-	if (version == protocol_v2 && !strcmp("git-receive-pack", prog))
-		version = protocol_v0;
+	max_version = determine_maximum_protocol_version(prog, version);
+	if (version > max_version)
+		version = max_version;
 
 	/* Without this we cannot rely on waitpid() to tell
 	 * what happened to our children.
diff --git a/protocol.c b/protocol.c
index 5e636785d1..1c553d8b99 100644
--- a/protocol.c
+++ b/protocol.c
@@ -79,3 +79,16 @@ enum protocol_version determine_protocol_version_client(const char *server_respo
 
 	return version;
 }
+
+enum protocol_version determine_maximum_protocol_version(
+		const char *service, enum protocol_version default_version)
+{
+	if (!strcmp(service, "git-receive-pack"))
+		return protocol_v1;
+	else if (!strcmp(service, "git-upload-archive"))
+		return protocol_v1;
+	else if (!strcmp(service, "git-upload-pack"))
+		return protocol_v2;
+
+	return default_version;
+}
diff --git a/protocol.h b/protocol.h
index 2ad35e433c..eabc0c5fab 100644
--- a/protocol.h
+++ b/protocol.h
@@ -31,4 +31,11 @@ extern enum protocol_version determine_protocol_version_server(void);
  */
 extern enum protocol_version determine_protocol_version_client(const char *server_response);
 
+/*
+ * Used by a client to determine the maximum protocol version to advertise for a
+ * particular service. If the service is unrecognized, return default_version.
+ */
+extern enum protocol_version determine_maximum_protocol_version(
+		const char *service, enum protocol_version default_version);
+
 #endif /* PROTOCOL_H */
diff --git a/remote-curl.c b/remote-curl.c
index fb28309e85..028adb76ae 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -344,6 +344,7 @@ static struct discovery *discover_refs(const char *service, int for_push)
 	int http_ret, maybe_smart = 0;
 	struct http_get_options http_options;
 	enum protocol_version version = get_protocol_version_config();
+	enum protocol_version max_version;
 
 	if (last && !strcmp(service, last->service))
 		return last;
@@ -360,13 +361,9 @@ static struct discovery *discover_refs(const char *service, int for_push)
 		strbuf_addf(&refs_url, "service=%s", service);
 	}
 
-	/*
-	 * NEEDSWORK: If we are trying to use protocol v2 and we are planning
-	 * to perform a push, then fallback to v0 since the client doesn't know
-	 * how to push yet using v2.
-	 */
-	if (version == protocol_v2 && !strcmp("git-receive-pack", service))
-		version = protocol_v0;
+	max_version = determine_maximum_protocol_version(service, version);
+	if (version > max_version)
+		version = max_version;
 
 	/* Add the extra Git-Protocol header */
 	if (get_protocol_http_header(version, &protocol_header))
-- 
2.19.0.605.g01d371f741-goog