10
10
#include "upload-pack.h"
11
11
12
12
static int advertise_sid = -1 ;
13
+ static int client_hash_algo = GIT_HASH_SHA1 ;
13
14
14
15
static int always_advertise (struct repository * r ,
15
16
struct strbuf * value )
@@ -33,6 +34,17 @@ static int object_format_advertise(struct repository *r,
33
34
return 1 ;
34
35
}
35
36
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
+
36
48
static int session_id_advertise (struct repository * r , struct strbuf * value )
37
49
{
38
50
if (advertise_sid == -1 &&
@@ -45,6 +57,14 @@ static int session_id_advertise(struct repository *r, struct strbuf *value)
45
57
return 1 ;
46
58
}
47
59
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
+
48
68
struct protocol_capability {
49
69
/*
50
70
* The name of the capability. The server uses this name when
@@ -70,6 +90,16 @@ struct protocol_capability {
70
90
* This field should be NULL for capabilities which are not commands.
71
91
*/
72
92
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 );
73
103
};
74
104
75
105
static struct protocol_capability capabilities [] = {
@@ -94,10 +124,12 @@ static struct protocol_capability capabilities[] = {
94
124
{
95
125
.name = "object-format" ,
96
126
.advertise = object_format_advertise ,
127
+ .receive = object_format_receive ,
97
128
},
98
129
{
99
130
.name = "session-id" ,
100
131
.advertise = session_id_advertise ,
132
+ .receive = session_id_receive ,
101
133
},
102
134
{
103
135
.name = "object-info" ,
@@ -139,7 +171,7 @@ void protocol_v2_advertise_capabilities(void)
139
171
strbuf_release (& value );
140
172
}
141
173
142
- static struct protocol_capability * get_capability (const char * key )
174
+ static struct protocol_capability * get_capability (const char * key , const char * * value )
143
175
{
144
176
int i ;
145
177
@@ -149,31 +181,46 @@ static struct protocol_capability *get_capability(const char *key)
149
181
for (i = 0 ; i < ARRAY_SIZE (capabilities ); i ++ ) {
150
182
struct protocol_capability * c = & capabilities [i ];
151
183
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 ;
153
188
return c ;
189
+ }
190
+ if (* out ++ == '=' ) {
191
+ * value = out ;
192
+ return c ;
193
+ }
154
194
}
155
195
156
196
return NULL ;
157
197
}
158
198
159
- static int is_valid_capability (const char * key )
199
+ static int receive_client_capability (const char * key )
160
200
{
161
- const struct protocol_capability * c = get_capability (key );
201
+ const char * value ;
202
+ const struct protocol_capability * c = get_capability (key , & value );
162
203
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 ;
164
210
}
165
211
166
- static int is_command (const char * key , struct protocol_capability * * command )
212
+ static int parse_command (const char * key , struct protocol_capability * * command )
167
213
{
168
214
const char * out ;
169
215
170
216
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 );
172
219
173
220
if (* command )
174
221
die ("command '%s' requested after already requesting command '%s'" ,
175
222
out , (* command )-> name );
176
- if (!cmd || !cmd -> advertise (the_repository , NULL ) || !cmd -> command )
223
+ if (!cmd || !cmd -> advertise (the_repository , NULL ) || !cmd -> command || value )
177
224
die ("invalid command '%s'" , out );
178
225
179
226
* command = cmd ;
@@ -183,42 +230,6 @@ static int is_command(const char *key, struct protocol_capability **command)
183
230
return 0 ;
184
231
}
185
232
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
-
222
233
enum request_state {
223
234
PROCESS_REQUEST_KEYS ,
224
235
PROCESS_REQUEST_DONE ,
@@ -228,9 +239,8 @@ static int process_request(void)
228
239
{
229
240
enum request_state state = PROCESS_REQUEST_KEYS ;
230
241
struct packet_reader reader ;
231
- struct strvec keys = STRVEC_INIT ;
242
+ int seen_capability_or_command = 0 ;
232
243
struct protocol_capability * command = NULL ;
233
- const char * client_sid ;
234
244
235
245
packet_reader_init (& reader , 0 , NULL , 0 ,
236
246
PACKET_READ_CHOMP_NEWLINE |
@@ -250,10 +260,9 @@ static int process_request(void)
250
260
case PACKET_READ_EOF :
251
261
BUG ("Should have already died when seeing EOF" );
252
262
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 ;
257
266
else
258
267
die ("unknown capability '%s'" , reader .line );
259
268
@@ -265,7 +274,7 @@ static int process_request(void)
265
274
* If no command and no keys were given then the client
266
275
* wanted to terminate the connection.
267
276
*/
268
- if (!keys . nr )
277
+ if (!seen_capability_or_command )
269
278
return 1 ;
270
279
271
280
/*
@@ -292,14 +301,13 @@ static int process_request(void)
292
301
if (!command )
293
302
die ("no command requested" );
294
303
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 );
299
308
300
309
command -> command (the_repository , & reader );
301
310
302
- strvec_clear (& keys );
303
311
return 0 ;
304
312
}
305
313
0 commit comments