server_supports(): parse feature list more carefully

We have been carefully choosing feature names used in the protocol extensions so that the vocabulary does not contain a word that is a substring of another word, so it is not a real problem, but we have recently added "quiet" feature word, which would mean we cannot later add some other word with "quiet" (e.g. "quiet-push"), which is awkward. Let's make sure that we can eventually be able to do so by teaching the clients and servers that feature words consist of non whitespace letters. This parser also allows us to later add features with parameters e.g. "feature=1.5" (parameter values need to be quoted for whitespaces, but we will worry about the detauls when we do introduce them). Signed-off-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Clemens Buchacher <drizzd@aon.at> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Jan 8, 2012 at 22:06 UTC f47182c852601c045f62bd7f669360a920516311
4 files changed +38 -13
builtin/receive-pack.c
+3 -2
@@ -731,9 +731,10 @@ static struct command *read_head_info(void)
731 refname = line + 82;
732 reflen = strlen(refname);
733 if (reflen + 82 < len) {
734 - if (strstr(refname + reflen + 1, "report-status"))
734 + const char *feature_list = refname + reflen + 1;
735 + if (parse_feature_request(feature_list, "report-status"))
736 report_status = 1;
736 - if (strstr(refname + reflen + 1, "side-band-64k"))
737 + if (parse_feature_request(feature_list, "side-band-64k"))
738 use_sideband = LARGE_PACKET_MAX;
739 }
740 cmd = xcalloc(1, sizeof(struct command) + len - 80);
cache.h
+1
@@ -1037,6 +1037,7 @@ struct extra_have_objects {
1037 };
1038 extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *);
1039 extern int server_supports(const char *feature);
1040 +extern const char *parse_feature_request(const char *features, const char *feature);
1041
1042 extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
1043
connect.c
+21 -2
@@ -101,8 +101,27 @@ struct ref **get_remote_heads(int in, struct ref **list,
101
102 int server_supports(const char *feature)
103 {
104 - return server_capabilities &&
105 - strstr(server_capabilities, feature) != NULL;
104 + return !!parse_feature_request(server_capabilities, feature);
105 +}
106 +
107 +const char *parse_feature_request(const char *feature_list, const char *feature)
108 +{
109 + int len;
110 +
111 + if (!feature_list)
112 + return NULL;
113 +
114 + len = strlen(feature);
115 + while (*feature_list) {
116 + const char *found = strstr(feature_list, feature);
117 + if (!found)
118 + return NULL;
119 + if ((feature_list == found || isspace(found[-1])) &&
120 + (!found[len] || isspace(found[len]) || found[len] == '='))
121 + return found;
122 + feature_list = found + 1;
123 + }
124 + return NULL;
125 }
126
127 enum protocol {
upload-pack.c
+13 -9
@@ -585,6 +585,7 @@ static void receive_needs(void)
585 write_str_in_full(debug_fd, "#S\n");
586 for (;;) {
587 struct object *o;
588 + const char *features;
589 unsigned char sha1_buf[20];
590 len = packet_read_line(0, line, sizeof(line));
591 reset_timeout();
@@ -616,23 +617,26 @@ static void receive_needs(void)
617 get_sha1_hex(line+5, sha1_buf))
618 die("git upload-pack: protocol error, "
619 "expected to get sha, not '%s'", line);
619 - if (strstr(line+45, "multi_ack_detailed"))
620 +
621 + features = line + 45;
622 +
623 + if (parse_feature_request(features, "multi_ack_detailed"))
624 multi_ack = 2;
621 - else if (strstr(line+45, "multi_ack"))
625 + else if (parse_feature_request(features, "multi_ack"))
626 multi_ack = 1;
623 - if (strstr(line+45, "no-done"))
627 + if (parse_feature_request(features, "no-done"))
628 no_done = 1;
625 - if (strstr(line+45, "thin-pack"))
629 + if (parse_feature_request(features, "thin-pack"))
630 use_thin_pack = 1;
627 - if (strstr(line+45, "ofs-delta"))
631 + if (parse_feature_request(features, "ofs-delta"))
632 use_ofs_delta = 1;
629 - if (strstr(line+45, "side-band-64k"))
633 + if (parse_feature_request(features, "side-band-64k"))
634 use_sideband = LARGE_PACKET_MAX;
631 - else if (strstr(line+45, "side-band"))
635 + else if (parse_feature_request(features, "side-band"))
636 use_sideband = DEFAULT_PACKET_MAX;
633 - if (strstr(line+45, "no-progress"))
637 + if (parse_feature_request(features, "no-progress"))
638 no_progress = 1;
635 - if (strstr(line+45, "include-tag"))
639 + if (parse_feature_request(features, "include-tag"))
640 use_include_tag = 1;
641
642 o = lookup_object(sha1_buf);