1010#include "upload-pack.h"
1111
1212static int advertise_sid = -1 ;
13+ static int client_hash_algo = GIT_HASH_SHA1 ;
1314
1415static int always_advertise (struct repository * r ,
1516 struct strbuf * value )
@@ -33,6 +34,17 @@ static int object_format_advertise(struct repository *r,
3334 return 1 ;
3435}
3536
37+ static void object_format_receive (struct repository * r ,
38+ const char * algo_name )
39+ {
40+ if (!algo_name )
41+ die ("object-format capability requires an argument" );
42+
43+ client_hash_algo = hash_algo_by_name (algo_name );
44+ if (client_hash_algo == GIT_HASH_UNKNOWN )
45+ die ("unknown object format '%s'" , algo_name );
46+ }
47+
3648static int session_id_advertise (struct repository * r , struct strbuf * value )
3749{
3850 if (advertise_sid == -1 &&
@@ -45,6 +57,14 @@ static int session_id_advertise(struct repository *r, struct strbuf *value)
4557 return 1 ;
4658}
4759
60+ static void session_id_receive (struct repository * r ,
61+ const char * client_sid )
62+ {
63+ if (!client_sid )
64+ client_sid = "" ;
65+ trace2_data_string ("transfer" , NULL , "client-sid" , client_sid );
66+ }
67+
4868struct protocol_capability {
4969 /*
5070 * The name of the capability. The server uses this name when
@@ -70,6 +90,16 @@ struct protocol_capability {
7090 * This field should be NULL for capabilities which are not commands.
7191 */
7292 int (* command )(struct repository * r , struct packet_reader * request );
93+
94+ /*
95+ * Function called when a client requests the capability as a
96+ * non-command. This may be NULL if the capability does nothing.
97+ *
98+ * For a capability of the form "foo=bar", the value string points to
99+ * the content after the "=" (i.e., "bar"). For simple capabilities
100+ * (just "foo"), it is NULL.
101+ */
102+ void (* receive )(struct repository * r , const char * value );
73103};
74104
75105static struct protocol_capability capabilities [] = {
@@ -94,10 +124,12 @@ static struct protocol_capability capabilities[] = {
94124 {
95125 .name = "object-format" ,
96126 .advertise = object_format_advertise ,
127+ .receive = object_format_receive ,
97128 },
98129 {
99130 .name = "session-id" ,
100131 .advertise = session_id_advertise ,
132+ .receive = session_id_receive ,
101133 },
102134 {
103135 .name = "object-info" ,
@@ -139,7 +171,7 @@ void protocol_v2_advertise_capabilities(void)
139171 strbuf_release (& value );
140172}
141173
142- static struct protocol_capability * get_capability (const char * key )
174+ static struct protocol_capability * get_capability (const char * key , const char * * value )
143175{
144176 int i ;
145177
@@ -149,31 +181,46 @@ static struct protocol_capability *get_capability(const char *key)
149181 for (i = 0 ; i < ARRAY_SIZE (capabilities ); i ++ ) {
150182 struct protocol_capability * c = & capabilities [i ];
151183 const char * out ;
152- if (skip_prefix (key , c -> name , & out ) && (!* out || * out == '=' ))
184+ if (!skip_prefix (key , c -> name , & out ))
185+ continue ;
186+ if (!* out ) {
187+ * value = NULL ;
153188 return c ;
189+ }
190+ if (* out ++ == '=' ) {
191+ * value = out ;
192+ return c ;
193+ }
154194 }
155195
156196 return NULL ;
157197}
158198
159- static int is_valid_capability (const char * key )
199+ static int receive_client_capability (const char * key )
160200{
161- const struct protocol_capability * c = get_capability (key );
201+ const char * value ;
202+ const struct protocol_capability * c = get_capability (key , & value );
162203
163- return c && c -> advertise (the_repository , NULL );
204+ if (!c || c -> command || !c -> advertise (the_repository , NULL ))
205+ return 0 ;
206+
207+ if (c -> receive )
208+ c -> receive (the_repository , value );
209+ return 1 ;
164210}
165211
166- static int is_command (const char * key , struct protocol_capability * * command )
212+ static int parse_command (const char * key , struct protocol_capability * * command )
167213{
168214 const char * out ;
169215
170216 if (skip_prefix (key , "command=" , & out )) {
171- struct protocol_capability * cmd = get_capability (out );
217+ const char * value ;
218+ struct protocol_capability * cmd = get_capability (out , & value );
172219
173220 if (* command )
174221 die ("command '%s' requested after already requesting command '%s'" ,
175222 out , (* command )-> name );
176- if (!cmd || !cmd -> advertise (the_repository , NULL ) || !cmd -> command )
223+ if (!cmd || !cmd -> advertise (the_repository , NULL ) || !cmd -> command || value )
177224 die ("invalid command '%s'" , out );
178225
179226 * command = cmd ;
@@ -183,42 +230,6 @@ static int is_command(const char *key, struct protocol_capability **command)
183230 return 0 ;
184231}
185232
186- static int has_capability (const struct strvec * keys , const char * capability ,
187- const char * * value )
188- {
189- int i ;
190- for (i = 0 ; i < keys -> nr ; i ++ ) {
191- const char * out ;
192- if (skip_prefix (keys -> v [i ], capability , & out ) &&
193- (!* out || * out == '=' )) {
194- if (value ) {
195- if (* out == '=' )
196- out ++ ;
197- * value = out ;
198- }
199- return 1 ;
200- }
201- }
202-
203- return 0 ;
204- }
205-
206- static void check_algorithm (struct repository * r , struct strvec * keys )
207- {
208- int client = GIT_HASH_SHA1 , server = hash_algo_by_ptr (r -> hash_algo );
209- const char * algo_name ;
210-
211- if (has_capability (keys , "object-format" , & algo_name )) {
212- client = hash_algo_by_name (algo_name );
213- if (client == GIT_HASH_UNKNOWN )
214- die ("unknown object format '%s'" , algo_name );
215- }
216-
217- if (client != server )
218- die ("mismatched object format: server %s; client %s\n" ,
219- r -> hash_algo -> name , hash_algos [client ].name );
220- }
221-
222233enum request_state {
223234 PROCESS_REQUEST_KEYS ,
224235 PROCESS_REQUEST_DONE ,
@@ -228,9 +239,8 @@ static int process_request(void)
228239{
229240 enum request_state state = PROCESS_REQUEST_KEYS ;
230241 struct packet_reader reader ;
231- struct strvec keys = STRVEC_INIT ;
242+ int seen_capability_or_command = 0 ;
232243 struct protocol_capability * command = NULL ;
233- const char * client_sid ;
234244
235245 packet_reader_init (& reader , 0 , NULL , 0 ,
236246 PACKET_READ_CHOMP_NEWLINE |
@@ -250,10 +260,9 @@ static int process_request(void)
250260 case PACKET_READ_EOF :
251261 BUG ("Should have already died when seeing EOF" );
252262 case PACKET_READ_NORMAL :
253- /* collect request; a sequence of keys and values */
254- if (is_command (reader .line , & command ) ||
255- is_valid_capability (reader .line ))
256- strvec_push (& keys , reader .line );
263+ if (parse_command (reader .line , & command ) ||
264+ receive_client_capability (reader .line ))
265+ seen_capability_or_command = 1 ;
257266 else
258267 die ("unknown capability '%s'" , reader .line );
259268
@@ -265,7 +274,7 @@ static int process_request(void)
265274 * If no command and no keys were given then the client
266275 * wanted to terminate the connection.
267276 */
268- if (!keys . nr )
277+ if (!seen_capability_or_command )
269278 return 1 ;
270279
271280 /*
@@ -292,14 +301,13 @@ static int process_request(void)
292301 if (!command )
293302 die ("no command requested" );
294303
295- check_algorithm ( the_repository , & keys );
296-
297- if ( has_capability ( & keys , "session-id" , & client_sid ))
298- trace2_data_string ( "transfer" , NULL , "client-sid" , client_sid );
304+ if ( client_hash_algo != hash_algo_by_ptr ( the_repository -> hash_algo ))
305+ die ( "mismatched object format: server %s; client %s\n" ,
306+ the_repository -> hash_algo -> name ,
307+ hash_algos [ client_hash_algo ]. name );
299308
300309 command -> command (the_repository , & reader );
301310
302- strvec_clear (& keys );
303311 return 0 ;
304312}
305313
0 commit comments