##// END OF EJS Templates
wireprotov2: define and implement "filesdata" command...
Gregory Szorc -
r40214:46a40bce default
parent child Browse files
Show More
This diff has been collapsed as it changes many lines, (1058 lines changed) Show them Hide them
@@ -0,0 +1,1058 b''
1 $ . $TESTDIR/wireprotohelpers.sh
2
3 $ hg init server
4 $ enablehttpv2 server
5 $ cd server
6 $ cat > a << EOF
7 > a0
8 > 00000000000000000000000000000000000000
9 > 11111111111111111111111111111111111111
10 > EOF
11 $ cat > b << EOF
12 > b0
13 > aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
14 > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
15 > EOF
16 $ mkdir -p dir0/child0 dir0/child1 dir1
17 $ echo c0 > dir0/c
18 $ echo d0 > dir0/d
19 $ echo e0 > dir0/child0/e
20 $ echo f0 > dir0/child1/f
21 $ hg -q commit -A -m 'commit 0'
22
23 $ echo a1 >> a
24 $ echo d1 > dir0/d
25 $ echo g0 > g
26 $ echo h0 > h
27 $ hg -q commit -A -m 'commit 1'
28 $ echo f1 > dir0/child1/f
29 $ echo i0 > dir0/i
30 $ hg -q commit -A -m 'commit 2'
31
32 $ hg -q up -r 0
33 $ echo a2 >> a
34 $ hg commit -m 'commit 3'
35 created new head
36
37 $ hg log -G -T '{rev}:{node} {desc}\n'
38 @ 3:476fbf122cd82f6726f0191ff146f67140946abc commit 3
39 |
40 | o 2:b91c03cbba3519ab149b6cd0a0afbdb5cf1b5c8a commit 2
41 | |
42 | o 1:5b0b1a23577e205ea240e39c9704e28d7697cbd8 commit 1
43 |/
44 o 0:6e875ff18c227659ad6143bb3580c65700734884 commit 0
45
46
47 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
48 $ cat hg.pid > $DAEMON_PIDS
49
50 Missing arguments is an error
51
52 $ sendhttpv2peer << EOF
53 > command filesdata
54 > EOF
55 creating http peer for wire protocol version 2
56 sending filesdata command
57 abort: missing required arguments: revisions!
58 [255]
59
60 Bad pattern to pathfilter is rejected
61
62 $ sendhttpv2peer << EOF
63 > command filesdata
64 > revisions eval:[{
65 > b'type': b'changesetexplicit',
66 > b'nodes': [
67 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
68 > ]}]
69 > pathfilter eval:{b'include': [b'bad:foo']}
70 > EOF
71 creating http peer for wire protocol version 2
72 sending filesdata command
73 abort: include pattern must begin with `path:` or `rootfilesin:`; got bad:foo!
74 [255]
75
76 $ sendhttpv2peer << EOF
77 > command filesdata
78 > revisions eval:[{
79 > b'type': b'changesetexplicit',
80 > b'nodes': [
81 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
82 > ]}]
83 > pathfilter eval:{b'exclude': [b'glob:foo']}
84 > EOF
85 creating http peer for wire protocol version 2
86 sending filesdata command
87 abort: exclude pattern must begin with `path:` or `rootfilesin:`; got glob:foo!
88 [255]
89
90 Fetching a single changeset without parents fetches all files
91
92 $ sendhttpv2peer << EOF
93 > command filesdata
94 > revisions eval:[{
95 > b'type': b'changesetexplicit',
96 > b'nodes': [
97 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
98 > ]}]
99 > EOF
100 creating http peer for wire protocol version 2
101 sending filesdata command
102 response: gen[
103 {
104 b'totalitems': 8,
105 b'totalpaths': 8
106 },
107 {
108 b'path': b'a',
109 b'totalitems': 1
110 },
111 {
112 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
113 },
114 {
115 b'path': b'b',
116 b'totalitems': 1
117 },
118 {
119 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
120 },
121 {
122 b'path': b'dir0/c',
123 b'totalitems': 1
124 },
125 {
126 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
127 },
128 {
129 b'path': b'dir0/child0/e',
130 b'totalitems': 1
131 },
132 {
133 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
134 },
135 {
136 b'path': b'dir0/child1/f',
137 b'totalitems': 1
138 },
139 {
140 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
141 },
142 {
143 b'path': b'dir0/d',
144 b'totalitems': 1
145 },
146 {
147 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
148 },
149 {
150 b'path': b'g',
151 b'totalitems': 1
152 },
153 {
154 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
155 },
156 {
157 b'path': b'h',
158 b'totalitems': 1
159 },
160 {
161 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
162 }
163 ]
164
165 Fetching a single changeset saying parents data is available fetches just new files
166
167 $ sendhttpv2peer << EOF
168 > command filesdata
169 > revisions eval:[{
170 > b'type': b'changesetexplicit',
171 > b'nodes': [
172 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
173 > ]}]
174 > haveparents eval:True
175 > EOF
176 creating http peer for wire protocol version 2
177 sending filesdata command
178 response: gen[
179 {
180 b'totalitems': 4,
181 b'totalpaths': 4
182 },
183 {
184 b'path': b'a',
185 b'totalitems': 1
186 },
187 {
188 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
189 },
190 {
191 b'path': b'dir0/d',
192 b'totalitems': 1
193 },
194 {
195 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
196 },
197 {
198 b'path': b'g',
199 b'totalitems': 1
200 },
201 {
202 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
203 },
204 {
205 b'path': b'h',
206 b'totalitems': 1
207 },
208 {
209 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
210 }
211 ]
212
213 A path filter for a sub-directory is honored
214
215 $ sendhttpv2peer << EOF
216 > command filesdata
217 > revisions eval:[{
218 > b'type': b'changesetexplicit',
219 > b'nodes': [
220 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
221 > ]}]
222 > haveparents eval:True
223 > pathfilter eval:{b'include': [b'path:dir0']}
224 > EOF
225 creating http peer for wire protocol version 2
226 sending filesdata command
227 response: gen[
228 {
229 b'totalitems': 1,
230 b'totalpaths': 1
231 },
232 {
233 b'path': b'dir0/d',
234 b'totalitems': 1
235 },
236 {
237 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
238 }
239 ]
240
241 $ sendhttpv2peer << EOF
242 > command filesdata
243 > revisions eval:[{
244 > b'type': b'changesetexplicit',
245 > b'nodes': [
246 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
247 > ]}]
248 > haveparents eval:True
249 > pathfilter eval:{b'exclude': [b'path:a', b'path:g']}
250 > EOF
251 creating http peer for wire protocol version 2
252 sending filesdata command
253 response: gen[
254 {
255 b'totalitems': 2,
256 b'totalpaths': 2
257 },
258 {
259 b'path': b'dir0/d',
260 b'totalitems': 1
261 },
262 {
263 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
264 },
265 {
266 b'path': b'h',
267 b'totalitems': 1
268 },
269 {
270 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
271 }
272 ]
273
274 Requesting multiple changeset nodes without haveparents sends all data for both
275
276 $ sendhttpv2peer << EOF
277 > command filesdata
278 > revisions eval:[{
279 > b'type': b'changesetexplicit',
280 > b'nodes': [
281 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
282 > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
283 > ]}]
284 > EOF
285 creating http peer for wire protocol version 2
286 sending filesdata command
287 response: gen[
288 {
289 b'totalitems': 10,
290 b'totalpaths': 9
291 },
292 {
293 b'path': b'a',
294 b'totalitems': 1
295 },
296 {
297 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
298 },
299 {
300 b'path': b'b',
301 b'totalitems': 1
302 },
303 {
304 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
305 },
306 {
307 b'path': b'dir0/c',
308 b'totalitems': 1
309 },
310 {
311 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
312 },
313 {
314 b'path': b'dir0/child0/e',
315 b'totalitems': 1
316 },
317 {
318 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
319 },
320 {
321 b'path': b'dir0/child1/f',
322 b'totalitems': 2
323 },
324 {
325 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
326 },
327 {
328 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
329 },
330 {
331 b'path': b'dir0/d',
332 b'totalitems': 1
333 },
334 {
335 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
336 },
337 {
338 b'path': b'dir0/i',
339 b'totalitems': 1
340 },
341 {
342 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
343 },
344 {
345 b'path': b'g',
346 b'totalitems': 1
347 },
348 {
349 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
350 },
351 {
352 b'path': b'h',
353 b'totalitems': 1
354 },
355 {
356 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
357 }
358 ]
359
360 Requesting multiple changeset nodes with haveparents sends incremental data for both
361
362 $ sendhttpv2peer << EOF
363 > command filesdata
364 > revisions eval:[{
365 > b'type': b'changesetexplicit',
366 > b'nodes': [
367 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
368 > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
369 > ]}]
370 > haveparents eval:True
371 > EOF
372 creating http peer for wire protocol version 2
373 sending filesdata command
374 response: gen[
375 {
376 b'totalitems': 6,
377 b'totalpaths': 6
378 },
379 {
380 b'path': b'a',
381 b'totalitems': 1
382 },
383 {
384 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
385 },
386 {
387 b'path': b'dir0/child1/f',
388 b'totalitems': 1
389 },
390 {
391 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
392 },
393 {
394 b'path': b'dir0/d',
395 b'totalitems': 1
396 },
397 {
398 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
399 },
400 {
401 b'path': b'dir0/i',
402 b'totalitems': 1
403 },
404 {
405 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
406 },
407 {
408 b'path': b'g',
409 b'totalitems': 1
410 },
411 {
412 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
413 },
414 {
415 b'path': b'h',
416 b'totalitems': 1
417 },
418 {
419 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
420 }
421 ]
422
423 Requesting parents works
424
425 $ sendhttpv2peer << EOF
426 > command filesdata
427 > revisions eval:[{
428 > b'type': b'changesetexplicit',
429 > b'nodes': [
430 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
431 > ]}]
432 > fields eval:[b'parents']
433 > EOF
434 creating http peer for wire protocol version 2
435 sending filesdata command
436 response: gen[
437 {
438 b'totalitems': 8,
439 b'totalpaths': 8
440 },
441 {
442 b'path': b'a',
443 b'totalitems': 1
444 },
445 {
446 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11',
447 b'parents': [
448 b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
449 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
450 ]
451 },
452 {
453 b'path': b'b',
454 b'totalitems': 1
455 },
456 {
457 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2',
458 b'parents': [
459 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
460 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
461 ]
462 },
463 {
464 b'path': b'dir0/c',
465 b'totalitems': 1
466 },
467 {
468 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01',
469 b'parents': [
470 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
471 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
472 ]
473 },
474 {
475 b'path': b'dir0/child0/e',
476 b'totalitems': 1
477 },
478 {
479 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4',
480 b'parents': [
481 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
482 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
483 ]
484 },
485 {
486 b'path': b'dir0/child1/f',
487 b'totalitems': 1
488 },
489 {
490 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4',
491 b'parents': [
492 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
493 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
494 ]
495 },
496 {
497 b'path': b'dir0/d',
498 b'totalitems': 1
499 },
500 {
501 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G',
502 b'parents': [
503 b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
504 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
505 ]
506 },
507 {
508 b'path': b'g',
509 b'totalitems': 1
510 },
511 {
512 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c',
513 b'parents': [
514 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
515 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
516 ]
517 },
518 {
519 b'path': b'h',
520 b'totalitems': 1
521 },
522 {
523 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K',
524 b'parents': [
525 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
526 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
527 ]
528 }
529 ]
530
531 Requesting revision data works
532 (haveparents defaults to False, so fulltext is emitted)
533
534 $ sendhttpv2peer << EOF
535 > command filesdata
536 > revisions eval:[{
537 > b'type': b'changesetexplicit',
538 > b'nodes': [
539 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
540 > ]}]
541 > fields eval:[b'revision']
542 > EOF
543 creating http peer for wire protocol version 2
544 sending filesdata command
545 response: gen[
546 {
547 b'totalitems': 8,
548 b'totalpaths': 8
549 },
550 {
551 b'path': b'a',
552 b'totalitems': 1
553 },
554 {
555 b'fieldsfollowing': [
556 [
557 b'revision',
558 84
559 ]
560 ],
561 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
562 },
563 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n',
564 {
565 b'path': b'b',
566 b'totalitems': 1
567 },
568 {
569 b'fieldsfollowing': [
570 [
571 b'revision',
572 81
573 ]
574 ],
575 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
576 },
577 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
578 {
579 b'path': b'dir0/c',
580 b'totalitems': 1
581 },
582 {
583 b'fieldsfollowing': [
584 [
585 b'revision',
586 3
587 ]
588 ],
589 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
590 },
591 b'c0\n',
592 {
593 b'path': b'dir0/child0/e',
594 b'totalitems': 1
595 },
596 {
597 b'fieldsfollowing': [
598 [
599 b'revision',
600 3
601 ]
602 ],
603 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
604 },
605 b'e0\n',
606 {
607 b'path': b'dir0/child1/f',
608 b'totalitems': 1
609 },
610 {
611 b'fieldsfollowing': [
612 [
613 b'revision',
614 3
615 ]
616 ],
617 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
618 },
619 b'f0\n',
620 {
621 b'path': b'dir0/d',
622 b'totalitems': 1
623 },
624 {
625 b'fieldsfollowing': [
626 [
627 b'revision',
628 3
629 ]
630 ],
631 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
632 },
633 b'd1\n',
634 {
635 b'path': b'g',
636 b'totalitems': 1
637 },
638 {
639 b'fieldsfollowing': [
640 [
641 b'revision',
642 3
643 ]
644 ],
645 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
646 },
647 b'g0\n',
648 {
649 b'path': b'h',
650 b'totalitems': 1
651 },
652 {
653 b'fieldsfollowing': [
654 [
655 b'revision',
656 3
657 ]
658 ],
659 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
660 },
661 b'h0\n'
662 ]
663
664 haveparents=False should be same as above
665
666 $ sendhttpv2peer << EOF
667 > command filesdata
668 > revisions eval:[{
669 > b'type': b'changesetexplicit',
670 > b'nodes': [
671 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
672 > ]}]
673 > fields eval:[b'revision']
674 > haveparents eval:False
675 > EOF
676 creating http peer for wire protocol version 2
677 sending filesdata command
678 response: gen[
679 {
680 b'totalitems': 8,
681 b'totalpaths': 8
682 },
683 {
684 b'path': b'a',
685 b'totalitems': 1
686 },
687 {
688 b'fieldsfollowing': [
689 [
690 b'revision',
691 84
692 ]
693 ],
694 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
695 },
696 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n',
697 {
698 b'path': b'b',
699 b'totalitems': 1
700 },
701 {
702 b'fieldsfollowing': [
703 [
704 b'revision',
705 81
706 ]
707 ],
708 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
709 },
710 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
711 {
712 b'path': b'dir0/c',
713 b'totalitems': 1
714 },
715 {
716 b'fieldsfollowing': [
717 [
718 b'revision',
719 3
720 ]
721 ],
722 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
723 },
724 b'c0\n',
725 {
726 b'path': b'dir0/child0/e',
727 b'totalitems': 1
728 },
729 {
730 b'fieldsfollowing': [
731 [
732 b'revision',
733 3
734 ]
735 ],
736 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
737 },
738 b'e0\n',
739 {
740 b'path': b'dir0/child1/f',
741 b'totalitems': 1
742 },
743 {
744 b'fieldsfollowing': [
745 [
746 b'revision',
747 3
748 ]
749 ],
750 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
751 },
752 b'f0\n',
753 {
754 b'path': b'dir0/d',
755 b'totalitems': 1
756 },
757 {
758 b'fieldsfollowing': [
759 [
760 b'revision',
761 3
762 ]
763 ],
764 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
765 },
766 b'd1\n',
767 {
768 b'path': b'g',
769 b'totalitems': 1
770 },
771 {
772 b'fieldsfollowing': [
773 [
774 b'revision',
775 3
776 ]
777 ],
778 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
779 },
780 b'g0\n',
781 {
782 b'path': b'h',
783 b'totalitems': 1
784 },
785 {
786 b'fieldsfollowing': [
787 [
788 b'revision',
789 3
790 ]
791 ],
792 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
793 },
794 b'h0\n'
795 ]
796
797 haveparents=True should emit a delta
798
799 $ sendhttpv2peer << EOF
800 > command filesdata
801 > revisions eval:[{
802 > b'type': b'changesetexplicit',
803 > b'nodes': [
804 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
805 > ]}]
806 > fields eval:[b'revision']
807 > haveparents eval:True
808 > EOF
809 creating http peer for wire protocol version 2
810 sending filesdata command
811 response: gen[
812 {
813 b'totalitems': 4,
814 b'totalpaths': 4
815 },
816 {
817 b'path': b'a',
818 b'totalitems': 1
819 },
820 {
821 b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
822 b'fieldsfollowing': [
823 [
824 b'delta',
825 15
826 ]
827 ],
828 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
829 },
830 b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n',
831 {
832 b'path': b'dir0/d',
833 b'totalitems': 1
834 },
835 {
836 b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
837 b'fieldsfollowing': [
838 [
839 b'delta',
840 15
841 ]
842 ],
843 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
844 },
845 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n',
846 {
847 b'path': b'g',
848 b'totalitems': 1
849 },
850 {
851 b'fieldsfollowing': [
852 [
853 b'revision',
854 3
855 ]
856 ],
857 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
858 },
859 b'g0\n',
860 {
861 b'path': b'h',
862 b'totalitems': 1
863 },
864 {
865 b'fieldsfollowing': [
866 [
867 b'revision',
868 3
869 ]
870 ],
871 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
872 },
873 b'h0\n'
874 ]
875
876 Requesting multiple revisions works
877 (first revision is a fulltext since haveparents=False by default)
878
879 $ sendhttpv2peer << EOF
880 > command filesdata
881 > revisions eval:[{
882 > b'type': b'changesetexplicit',
883 > b'nodes': [
884 > b'\x6e\x87\x5f\xf1\x8c\x22\x76\x59\xad\x61\x43\xbb\x35\x80\xc6\x57\x00\x73\x48\x84',
885 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
886 > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
887 > ]}]
888 > fields eval:[b'revision']
889 > EOF
890 creating http peer for wire protocol version 2
891 sending filesdata command
892 response: gen[
893 {
894 b'totalitems': 12,
895 b'totalpaths': 9
896 },
897 {
898 b'path': b'a',
899 b'totalitems': 2
900 },
901 {
902 b'fieldsfollowing': [
903 [
904 b'revision',
905 81
906 ]
907 ],
908 b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9'
909 },
910 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\n',
911 {
912 b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
913 b'fieldsfollowing': [
914 [
915 b'delta',
916 15
917 ]
918 ],
919 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
920 },
921 b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n',
922 {
923 b'path': b'b',
924 b'totalitems': 1
925 },
926 {
927 b'fieldsfollowing': [
928 [
929 b'revision',
930 81
931 ]
932 ],
933 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
934 },
935 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
936 {
937 b'path': b'dir0/c',
938 b'totalitems': 1
939 },
940 {
941 b'fieldsfollowing': [
942 [
943 b'revision',
944 3
945 ]
946 ],
947 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
948 },
949 b'c0\n',
950 {
951 b'path': b'dir0/child0/e',
952 b'totalitems': 1
953 },
954 {
955 b'fieldsfollowing': [
956 [
957 b'revision',
958 3
959 ]
960 ],
961 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
962 },
963 b'e0\n',
964 {
965 b'path': b'dir0/child1/f',
966 b'totalitems': 2
967 },
968 {
969 b'fieldsfollowing': [
970 [
971 b'revision',
972 3
973 ]
974 ],
975 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
976 },
977 b'f0\n',
978 {
979 b'deltabasenode': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4',
980 b'fieldsfollowing': [
981 [
982 b'delta',
983 15
984 ]
985 ],
986 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
987 },
988 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03f1\n',
989 {
990 b'path': b'dir0/d',
991 b'totalitems': 2
992 },
993 {
994 b'fieldsfollowing': [
995 [
996 b'revision',
997 3
998 ]
999 ],
1000 b'node': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&'
1001 },
1002 b'd0\n',
1003 {
1004 b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
1005 b'fieldsfollowing': [
1006 [
1007 b'delta',
1008 15
1009 ]
1010 ],
1011 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
1012 },
1013 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n',
1014 {
1015 b'path': b'dir0/i',
1016 b'totalitems': 1
1017 },
1018 {
1019 b'fieldsfollowing': [
1020 [
1021 b'revision',
1022 3
1023 ]
1024 ],
1025 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
1026 },
1027 b'i0\n',
1028 {
1029 b'path': b'g',
1030 b'totalitems': 1
1031 },
1032 {
1033 b'fieldsfollowing': [
1034 [
1035 b'revision',
1036 3
1037 ]
1038 ],
1039 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
1040 },
1041 b'g0\n',
1042 {
1043 b'path': b'h',
1044 b'totalitems': 1
1045 },
1046 {
1047 b'fieldsfollowing': [
1048 [
1049 b'revision',
1050 3
1051 ]
1052 ],
1053 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
1054 },
1055 b'h0\n'
1056 ]
1057
1058 $ cat error.log
@@ -1,1424 +1,1427 b''
1 1 # configitems.py - centralized declaration of configuration option
2 2 #
3 3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import functools
11 11 import re
12 12
13 13 from . import (
14 14 encoding,
15 15 error,
16 16 )
17 17
18 18 def loadconfigtable(ui, extname, configtable):
19 19 """update config item known to the ui with the extension ones"""
20 20 for section, items in sorted(configtable.items()):
21 21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 22 knownkeys = set(knownitems)
23 23 newkeys = set(items)
24 24 for key in sorted(knownkeys & newkeys):
25 25 msg = "extension '%s' overwrite config item '%s.%s'"
26 26 msg %= (extname, section, key)
27 27 ui.develwarn(msg, config='warn-config')
28 28
29 29 knownitems.update(items)
30 30
31 31 class configitem(object):
32 32 """represent a known config item
33 33
34 34 :section: the official config section where to find this item,
35 35 :name: the official name within the section,
36 36 :default: default value for this item,
37 37 :alias: optional list of tuples as alternatives,
38 38 :generic: this is a generic definition, match name using regular expression.
39 39 """
40 40
41 41 def __init__(self, section, name, default=None, alias=(),
42 42 generic=False, priority=0):
43 43 self.section = section
44 44 self.name = name
45 45 self.default = default
46 46 self.alias = list(alias)
47 47 self.generic = generic
48 48 self.priority = priority
49 49 self._re = None
50 50 if generic:
51 51 self._re = re.compile(self.name)
52 52
53 53 class itemregister(dict):
54 54 """A specialized dictionary that can handle wild-card selection"""
55 55
56 56 def __init__(self):
57 57 super(itemregister, self).__init__()
58 58 self._generics = set()
59 59
60 60 def update(self, other):
61 61 super(itemregister, self).update(other)
62 62 self._generics.update(other._generics)
63 63
64 64 def __setitem__(self, key, item):
65 65 super(itemregister, self).__setitem__(key, item)
66 66 if item.generic:
67 67 self._generics.add(item)
68 68
69 69 def get(self, key):
70 70 baseitem = super(itemregister, self).get(key)
71 71 if baseitem is not None and not baseitem.generic:
72 72 return baseitem
73 73
74 74 # search for a matching generic item
75 75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
76 76 for item in generics:
77 77 # we use 'match' instead of 'search' to make the matching simpler
78 78 # for people unfamiliar with regular expression. Having the match
79 79 # rooted to the start of the string will produce less surprising
80 80 # result for user writing simple regex for sub-attribute.
81 81 #
82 82 # For example using "color\..*" match produces an unsurprising
83 83 # result, while using search could suddenly match apparently
84 84 # unrelated configuration that happens to contains "color."
85 85 # anywhere. This is a tradeoff where we favor requiring ".*" on
86 86 # some match to avoid the need to prefix most pattern with "^".
87 87 # The "^" seems more error prone.
88 88 if item._re.match(key):
89 89 return item
90 90
91 91 return None
92 92
93 93 coreitems = {}
94 94
95 95 def _register(configtable, *args, **kwargs):
96 96 item = configitem(*args, **kwargs)
97 97 section = configtable.setdefault(item.section, itemregister())
98 98 if item.name in section:
99 99 msg = "duplicated config item registration for '%s.%s'"
100 100 raise error.ProgrammingError(msg % (item.section, item.name))
101 101 section[item.name] = item
102 102
103 103 # special value for case where the default is derived from other values
104 104 dynamicdefault = object()
105 105
106 106 # Registering actual config items
107 107
108 108 def getitemregister(configtable):
109 109 f = functools.partial(_register, configtable)
110 110 # export pseudo enum as configitem.*
111 111 f.dynamicdefault = dynamicdefault
112 112 return f
113 113
114 114 coreconfigitem = getitemregister(coreitems)
115 115
116 116 coreconfigitem('alias', '.*',
117 117 default=dynamicdefault,
118 118 generic=True,
119 119 )
120 120 coreconfigitem('annotate', 'nodates',
121 121 default=False,
122 122 )
123 123 coreconfigitem('annotate', 'showfunc',
124 124 default=False,
125 125 )
126 126 coreconfigitem('annotate', 'unified',
127 127 default=None,
128 128 )
129 129 coreconfigitem('annotate', 'git',
130 130 default=False,
131 131 )
132 132 coreconfigitem('annotate', 'ignorews',
133 133 default=False,
134 134 )
135 135 coreconfigitem('annotate', 'ignorewsamount',
136 136 default=False,
137 137 )
138 138 coreconfigitem('annotate', 'ignoreblanklines',
139 139 default=False,
140 140 )
141 141 coreconfigitem('annotate', 'ignorewseol',
142 142 default=False,
143 143 )
144 144 coreconfigitem('annotate', 'nobinary',
145 145 default=False,
146 146 )
147 147 coreconfigitem('annotate', 'noprefix',
148 148 default=False,
149 149 )
150 150 coreconfigitem('annotate', 'word-diff',
151 151 default=False,
152 152 )
153 153 coreconfigitem('auth', 'cookiefile',
154 154 default=None,
155 155 )
156 156 # bookmarks.pushing: internal hack for discovery
157 157 coreconfigitem('bookmarks', 'pushing',
158 158 default=list,
159 159 )
160 160 # bundle.mainreporoot: internal hack for bundlerepo
161 161 coreconfigitem('bundle', 'mainreporoot',
162 162 default='',
163 163 )
164 164 coreconfigitem('censor', 'policy',
165 165 default='abort',
166 166 )
167 167 coreconfigitem('chgserver', 'idletimeout',
168 168 default=3600,
169 169 )
170 170 coreconfigitem('chgserver', 'skiphash',
171 171 default=False,
172 172 )
173 173 coreconfigitem('cmdserver', 'log',
174 174 default=None,
175 175 )
176 176 coreconfigitem('color', '.*',
177 177 default=None,
178 178 generic=True,
179 179 )
180 180 coreconfigitem('color', 'mode',
181 181 default='auto',
182 182 )
183 183 coreconfigitem('color', 'pagermode',
184 184 default=dynamicdefault,
185 185 )
186 186 coreconfigitem('commands', 'grep.all-files',
187 187 default=False,
188 188 )
189 189 coreconfigitem('commands', 'resolve.confirm',
190 190 default=False,
191 191 )
192 192 coreconfigitem('commands', 'resolve.explicit-re-merge',
193 193 default=False,
194 194 )
195 195 coreconfigitem('commands', 'resolve.mark-check',
196 196 default='none',
197 197 )
198 198 coreconfigitem('commands', 'show.aliasprefix',
199 199 default=list,
200 200 )
201 201 coreconfigitem('commands', 'status.relative',
202 202 default=False,
203 203 )
204 204 coreconfigitem('commands', 'status.skipstates',
205 205 default=[],
206 206 )
207 207 coreconfigitem('commands', 'status.terse',
208 208 default='',
209 209 )
210 210 coreconfigitem('commands', 'status.verbose',
211 211 default=False,
212 212 )
213 213 coreconfigitem('commands', 'update.check',
214 214 default=None,
215 215 )
216 216 coreconfigitem('commands', 'update.requiredest',
217 217 default=False,
218 218 )
219 219 coreconfigitem('committemplate', '.*',
220 220 default=None,
221 221 generic=True,
222 222 )
223 223 coreconfigitem('convert', 'bzr.saverev',
224 224 default=True,
225 225 )
226 226 coreconfigitem('convert', 'cvsps.cache',
227 227 default=True,
228 228 )
229 229 coreconfigitem('convert', 'cvsps.fuzz',
230 230 default=60,
231 231 )
232 232 coreconfigitem('convert', 'cvsps.logencoding',
233 233 default=None,
234 234 )
235 235 coreconfigitem('convert', 'cvsps.mergefrom',
236 236 default=None,
237 237 )
238 238 coreconfigitem('convert', 'cvsps.mergeto',
239 239 default=None,
240 240 )
241 241 coreconfigitem('convert', 'git.committeractions',
242 242 default=lambda: ['messagedifferent'],
243 243 )
244 244 coreconfigitem('convert', 'git.extrakeys',
245 245 default=list,
246 246 )
247 247 coreconfigitem('convert', 'git.findcopiesharder',
248 248 default=False,
249 249 )
250 250 coreconfigitem('convert', 'git.remoteprefix',
251 251 default='remote',
252 252 )
253 253 coreconfigitem('convert', 'git.renamelimit',
254 254 default=400,
255 255 )
256 256 coreconfigitem('convert', 'git.saverev',
257 257 default=True,
258 258 )
259 259 coreconfigitem('convert', 'git.similarity',
260 260 default=50,
261 261 )
262 262 coreconfigitem('convert', 'git.skipsubmodules',
263 263 default=False,
264 264 )
265 265 coreconfigitem('convert', 'hg.clonebranches',
266 266 default=False,
267 267 )
268 268 coreconfigitem('convert', 'hg.ignoreerrors',
269 269 default=False,
270 270 )
271 271 coreconfigitem('convert', 'hg.revs',
272 272 default=None,
273 273 )
274 274 coreconfigitem('convert', 'hg.saverev',
275 275 default=False,
276 276 )
277 277 coreconfigitem('convert', 'hg.sourcename',
278 278 default=None,
279 279 )
280 280 coreconfigitem('convert', 'hg.startrev',
281 281 default=None,
282 282 )
283 283 coreconfigitem('convert', 'hg.tagsbranch',
284 284 default='default',
285 285 )
286 286 coreconfigitem('convert', 'hg.usebranchnames',
287 287 default=True,
288 288 )
289 289 coreconfigitem('convert', 'ignoreancestorcheck',
290 290 default=False,
291 291 )
292 292 coreconfigitem('convert', 'localtimezone',
293 293 default=False,
294 294 )
295 295 coreconfigitem('convert', 'p4.encoding',
296 296 default=dynamicdefault,
297 297 )
298 298 coreconfigitem('convert', 'p4.startrev',
299 299 default=0,
300 300 )
301 301 coreconfigitem('convert', 'skiptags',
302 302 default=False,
303 303 )
304 304 coreconfigitem('convert', 'svn.debugsvnlog',
305 305 default=True,
306 306 )
307 307 coreconfigitem('convert', 'svn.trunk',
308 308 default=None,
309 309 )
310 310 coreconfigitem('convert', 'svn.tags',
311 311 default=None,
312 312 )
313 313 coreconfigitem('convert', 'svn.branches',
314 314 default=None,
315 315 )
316 316 coreconfigitem('convert', 'svn.startrev',
317 317 default=0,
318 318 )
319 319 coreconfigitem('debug', 'dirstate.delaywrite',
320 320 default=0,
321 321 )
322 322 coreconfigitem('defaults', '.*',
323 323 default=None,
324 324 generic=True,
325 325 )
326 326 coreconfigitem('devel', 'all-warnings',
327 327 default=False,
328 328 )
329 329 coreconfigitem('devel', 'bundle2.debug',
330 330 default=False,
331 331 )
332 332 coreconfigitem('devel', 'cache-vfs',
333 333 default=None,
334 334 )
335 335 coreconfigitem('devel', 'check-locks',
336 336 default=False,
337 337 )
338 338 coreconfigitem('devel', 'check-relroot',
339 339 default=False,
340 340 )
341 341 coreconfigitem('devel', 'default-date',
342 342 default=None,
343 343 )
344 344 coreconfigitem('devel', 'deprec-warn',
345 345 default=False,
346 346 )
347 347 coreconfigitem('devel', 'disableloaddefaultcerts',
348 348 default=False,
349 349 )
350 350 coreconfigitem('devel', 'warn-empty-changegroup',
351 351 default=False,
352 352 )
353 353 coreconfigitem('devel', 'legacy.exchange',
354 354 default=list,
355 355 )
356 356 coreconfigitem('devel', 'servercafile',
357 357 default='',
358 358 )
359 359 coreconfigitem('devel', 'serverexactprotocol',
360 360 default='',
361 361 )
362 362 coreconfigitem('devel', 'serverrequirecert',
363 363 default=False,
364 364 )
365 365 coreconfigitem('devel', 'strip-obsmarkers',
366 366 default=True,
367 367 )
368 368 coreconfigitem('devel', 'warn-config',
369 369 default=None,
370 370 )
371 371 coreconfigitem('devel', 'warn-config-default',
372 372 default=None,
373 373 )
374 374 coreconfigitem('devel', 'user.obsmarker',
375 375 default=None,
376 376 )
377 377 coreconfigitem('devel', 'warn-config-unknown',
378 378 default=None,
379 379 )
380 380 coreconfigitem('devel', 'debug.copies',
381 381 default=False,
382 382 )
383 383 coreconfigitem('devel', 'debug.extensions',
384 384 default=False,
385 385 )
386 386 coreconfigitem('devel', 'debug.peer-request',
387 387 default=False,
388 388 )
389 389 coreconfigitem('diff', 'nodates',
390 390 default=False,
391 391 )
392 392 coreconfigitem('diff', 'showfunc',
393 393 default=False,
394 394 )
395 395 coreconfigitem('diff', 'unified',
396 396 default=None,
397 397 )
398 398 coreconfigitem('diff', 'git',
399 399 default=False,
400 400 )
401 401 coreconfigitem('diff', 'ignorews',
402 402 default=False,
403 403 )
404 404 coreconfigitem('diff', 'ignorewsamount',
405 405 default=False,
406 406 )
407 407 coreconfigitem('diff', 'ignoreblanklines',
408 408 default=False,
409 409 )
410 410 coreconfigitem('diff', 'ignorewseol',
411 411 default=False,
412 412 )
413 413 coreconfigitem('diff', 'nobinary',
414 414 default=False,
415 415 )
416 416 coreconfigitem('diff', 'noprefix',
417 417 default=False,
418 418 )
419 419 coreconfigitem('diff', 'word-diff',
420 420 default=False,
421 421 )
422 422 coreconfigitem('email', 'bcc',
423 423 default=None,
424 424 )
425 425 coreconfigitem('email', 'cc',
426 426 default=None,
427 427 )
428 428 coreconfigitem('email', 'charsets',
429 429 default=list,
430 430 )
431 431 coreconfigitem('email', 'from',
432 432 default=None,
433 433 )
434 434 coreconfigitem('email', 'method',
435 435 default='smtp',
436 436 )
437 437 coreconfigitem('email', 'reply-to',
438 438 default=None,
439 439 )
440 440 coreconfigitem('email', 'to',
441 441 default=None,
442 442 )
443 443 coreconfigitem('experimental', 'archivemetatemplate',
444 444 default=dynamicdefault,
445 445 )
446 446 coreconfigitem('experimental', 'bundle-phases',
447 447 default=False,
448 448 )
449 449 coreconfigitem('experimental', 'bundle2-advertise',
450 450 default=True,
451 451 )
452 452 coreconfigitem('experimental', 'bundle2-output-capture',
453 453 default=False,
454 454 )
455 455 coreconfigitem('experimental', 'bundle2.pushback',
456 456 default=False,
457 457 )
458 458 coreconfigitem('experimental', 'bundle2lazylocking',
459 459 default=False,
460 460 )
461 461 coreconfigitem('experimental', 'bundlecomplevel',
462 462 default=None,
463 463 )
464 464 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
465 465 default=None,
466 466 )
467 467 coreconfigitem('experimental', 'bundlecomplevel.gzip',
468 468 default=None,
469 469 )
470 470 coreconfigitem('experimental', 'bundlecomplevel.none',
471 471 default=None,
472 472 )
473 473 coreconfigitem('experimental', 'bundlecomplevel.zstd',
474 474 default=None,
475 475 )
476 476 coreconfigitem('experimental', 'changegroup3',
477 477 default=False,
478 478 )
479 479 coreconfigitem('experimental', 'clientcompressionengines',
480 480 default=list,
481 481 )
482 482 coreconfigitem('experimental', 'copytrace',
483 483 default='on',
484 484 )
485 485 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
486 486 default=100,
487 487 )
488 488 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
489 489 default=100,
490 490 )
491 491 coreconfigitem('experimental', 'crecordtest',
492 492 default=None,
493 493 )
494 494 coreconfigitem('experimental', 'directaccess',
495 495 default=False,
496 496 )
497 497 coreconfigitem('experimental', 'directaccess.revnums',
498 498 default=False,
499 499 )
500 500 coreconfigitem('experimental', 'editortmpinhg',
501 501 default=False,
502 502 )
503 503 coreconfigitem('experimental', 'evolution',
504 504 default=list,
505 505 )
506 506 coreconfigitem('experimental', 'evolution.allowdivergence',
507 507 default=False,
508 508 alias=[('experimental', 'allowdivergence')]
509 509 )
510 510 coreconfigitem('experimental', 'evolution.allowunstable',
511 511 default=None,
512 512 )
513 513 coreconfigitem('experimental', 'evolution.createmarkers',
514 514 default=None,
515 515 )
516 516 coreconfigitem('experimental', 'evolution.effect-flags',
517 517 default=True,
518 518 alias=[('experimental', 'effect-flags')]
519 519 )
520 520 coreconfigitem('experimental', 'evolution.exchange',
521 521 default=None,
522 522 )
523 523 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
524 524 default=False,
525 525 )
526 526 coreconfigitem('experimental', 'evolution.report-instabilities',
527 527 default=True,
528 528 )
529 529 coreconfigitem('experimental', 'evolution.track-operation',
530 530 default=True,
531 531 )
532 532 coreconfigitem('experimental', 'maxdeltachainspan',
533 533 default=-1,
534 534 )
535 535 coreconfigitem('experimental', 'mergetempdirprefix',
536 536 default=None,
537 537 )
538 538 coreconfigitem('experimental', 'mmapindexthreshold',
539 539 default=None,
540 540 )
541 541 coreconfigitem('experimental', 'narrow',
542 542 default=False,
543 543 )
544 544 coreconfigitem('experimental', 'nonnormalparanoidcheck',
545 545 default=False,
546 546 )
547 547 coreconfigitem('experimental', 'exportableenviron',
548 548 default=list,
549 549 )
550 550 coreconfigitem('experimental', 'extendedheader.index',
551 551 default=None,
552 552 )
553 553 coreconfigitem('experimental', 'extendedheader.similarity',
554 554 default=False,
555 555 )
556 556 coreconfigitem('experimental', 'format.compression',
557 557 default='zlib',
558 558 )
559 559 coreconfigitem('experimental', 'graphshorten',
560 560 default=False,
561 561 )
562 562 coreconfigitem('experimental', 'graphstyle.parent',
563 563 default=dynamicdefault,
564 564 )
565 565 coreconfigitem('experimental', 'graphstyle.missing',
566 566 default=dynamicdefault,
567 567 )
568 568 coreconfigitem('experimental', 'graphstyle.grandparent',
569 569 default=dynamicdefault,
570 570 )
571 571 coreconfigitem('experimental', 'hook-track-tags',
572 572 default=False,
573 573 )
574 574 coreconfigitem('experimental', 'httppeer.advertise-v2',
575 575 default=False,
576 576 )
577 577 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
578 578 default=None,
579 579 )
580 580 coreconfigitem('experimental', 'httppostargs',
581 581 default=False,
582 582 )
583 583 coreconfigitem('experimental', 'mergedriver',
584 584 default=None,
585 585 )
586 586 coreconfigitem('experimental', 'nointerrupt', default=False)
587 587 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
588 588
589 589 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
590 590 default=False,
591 591 )
592 592 coreconfigitem('experimental', 'remotenames',
593 593 default=False,
594 594 )
595 595 coreconfigitem('experimental', 'removeemptydirs',
596 596 default=True,
597 597 )
598 598 coreconfigitem('experimental', 'revisions.prefixhexnode',
599 599 default=False,
600 600 )
601 601 coreconfigitem('experimental', 'revlogv2',
602 602 default=None,
603 603 )
604 604 coreconfigitem('experimental', 'revisions.disambiguatewithin',
605 605 default=None,
606 606 )
607 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
608 default=50000,
609 )
607 610 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
608 611 default=100000,
609 612 )
610 613 coreconfigitem('experimental', 'single-head-per-branch',
611 614 default=False,
612 615 )
613 616 coreconfigitem('experimental', 'sshserver.support-v2',
614 617 default=False,
615 618 )
616 619 coreconfigitem('experimental', 'spacemovesdown',
617 620 default=False,
618 621 )
619 622 coreconfigitem('experimental', 'sparse-read',
620 623 default=False,
621 624 )
622 625 coreconfigitem('experimental', 'sparse-read.density-threshold',
623 626 default=0.50,
624 627 )
625 628 coreconfigitem('experimental', 'sparse-read.min-gap-size',
626 629 default='65K',
627 630 )
628 631 coreconfigitem('experimental', 'treemanifest',
629 632 default=False,
630 633 )
631 634 coreconfigitem('experimental', 'update.atomic-file',
632 635 default=False,
633 636 )
634 637 coreconfigitem('experimental', 'sshpeer.advertise-v2',
635 638 default=False,
636 639 )
637 640 coreconfigitem('experimental', 'web.apiserver',
638 641 default=False,
639 642 )
640 643 coreconfigitem('experimental', 'web.api.http-v2',
641 644 default=False,
642 645 )
643 646 coreconfigitem('experimental', 'web.api.debugreflect',
644 647 default=False,
645 648 )
646 649 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
647 650 default=False,
648 651 )
649 652 coreconfigitem('experimental', 'xdiff',
650 653 default=False,
651 654 )
652 655 coreconfigitem('extensions', '.*',
653 656 default=None,
654 657 generic=True,
655 658 )
656 659 coreconfigitem('extdata', '.*',
657 660 default=None,
658 661 generic=True,
659 662 )
660 663 coreconfigitem('format', 'chunkcachesize',
661 664 default=None,
662 665 )
663 666 coreconfigitem('format', 'dotencode',
664 667 default=True,
665 668 )
666 669 coreconfigitem('format', 'generaldelta',
667 670 default=False,
668 671 )
669 672 coreconfigitem('format', 'manifestcachesize',
670 673 default=None,
671 674 )
672 675 coreconfigitem('format', 'maxchainlen',
673 676 default=dynamicdefault,
674 677 )
675 678 coreconfigitem('format', 'obsstore-version',
676 679 default=None,
677 680 )
678 681 coreconfigitem('format', 'sparse-revlog',
679 682 default=False,
680 683 )
681 684 coreconfigitem('format', 'usefncache',
682 685 default=True,
683 686 )
684 687 coreconfigitem('format', 'usegeneraldelta',
685 688 default=True,
686 689 )
687 690 coreconfigitem('format', 'usestore',
688 691 default=True,
689 692 )
690 693 coreconfigitem('format', 'internal-phase',
691 694 default=False,
692 695 )
693 696 coreconfigitem('fsmonitor', 'warn_when_unused',
694 697 default=True,
695 698 )
696 699 coreconfigitem('fsmonitor', 'warn_update_file_count',
697 700 default=50000,
698 701 )
699 702 coreconfigitem('hooks', '.*',
700 703 default=dynamicdefault,
701 704 generic=True,
702 705 )
703 706 coreconfigitem('hgweb-paths', '.*',
704 707 default=list,
705 708 generic=True,
706 709 )
707 710 coreconfigitem('hostfingerprints', '.*',
708 711 default=list,
709 712 generic=True,
710 713 )
711 714 coreconfigitem('hostsecurity', 'ciphers',
712 715 default=None,
713 716 )
714 717 coreconfigitem('hostsecurity', 'disabletls10warning',
715 718 default=False,
716 719 )
717 720 coreconfigitem('hostsecurity', 'minimumprotocol',
718 721 default=dynamicdefault,
719 722 )
720 723 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
721 724 default=dynamicdefault,
722 725 generic=True,
723 726 )
724 727 coreconfigitem('hostsecurity', '.*:ciphers$',
725 728 default=dynamicdefault,
726 729 generic=True,
727 730 )
728 731 coreconfigitem('hostsecurity', '.*:fingerprints$',
729 732 default=list,
730 733 generic=True,
731 734 )
732 735 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
733 736 default=None,
734 737 generic=True,
735 738 )
736 739
737 740 coreconfigitem('http_proxy', 'always',
738 741 default=False,
739 742 )
740 743 coreconfigitem('http_proxy', 'host',
741 744 default=None,
742 745 )
743 746 coreconfigitem('http_proxy', 'no',
744 747 default=list,
745 748 )
746 749 coreconfigitem('http_proxy', 'passwd',
747 750 default=None,
748 751 )
749 752 coreconfigitem('http_proxy', 'user',
750 753 default=None,
751 754 )
752 755
753 756 coreconfigitem('http', 'timeout',
754 757 default=None,
755 758 )
756 759
757 760 coreconfigitem('logtoprocess', 'commandexception',
758 761 default=None,
759 762 )
760 763 coreconfigitem('logtoprocess', 'commandfinish',
761 764 default=None,
762 765 )
763 766 coreconfigitem('logtoprocess', 'command',
764 767 default=None,
765 768 )
766 769 coreconfigitem('logtoprocess', 'develwarn',
767 770 default=None,
768 771 )
769 772 coreconfigitem('logtoprocess', 'uiblocked',
770 773 default=None,
771 774 )
772 775 coreconfigitem('merge', 'checkunknown',
773 776 default='abort',
774 777 )
775 778 coreconfigitem('merge', 'checkignored',
776 779 default='abort',
777 780 )
778 781 coreconfigitem('experimental', 'merge.checkpathconflicts',
779 782 default=False,
780 783 )
781 784 coreconfigitem('merge', 'followcopies',
782 785 default=True,
783 786 )
784 787 coreconfigitem('merge', 'on-failure',
785 788 default='continue',
786 789 )
787 790 coreconfigitem('merge', 'preferancestor',
788 791 default=lambda: ['*'],
789 792 )
790 793 coreconfigitem('merge', 'strict-capability-check',
791 794 default=False,
792 795 )
793 796 coreconfigitem('merge-tools', '.*',
794 797 default=None,
795 798 generic=True,
796 799 )
797 800 coreconfigitem('merge-tools', br'.*\.args$',
798 801 default="$local $base $other",
799 802 generic=True,
800 803 priority=-1,
801 804 )
802 805 coreconfigitem('merge-tools', br'.*\.binary$',
803 806 default=False,
804 807 generic=True,
805 808 priority=-1,
806 809 )
807 810 coreconfigitem('merge-tools', br'.*\.check$',
808 811 default=list,
809 812 generic=True,
810 813 priority=-1,
811 814 )
812 815 coreconfigitem('merge-tools', br'.*\.checkchanged$',
813 816 default=False,
814 817 generic=True,
815 818 priority=-1,
816 819 )
817 820 coreconfigitem('merge-tools', br'.*\.executable$',
818 821 default=dynamicdefault,
819 822 generic=True,
820 823 priority=-1,
821 824 )
822 825 coreconfigitem('merge-tools', br'.*\.fixeol$',
823 826 default=False,
824 827 generic=True,
825 828 priority=-1,
826 829 )
827 830 coreconfigitem('merge-tools', br'.*\.gui$',
828 831 default=False,
829 832 generic=True,
830 833 priority=-1,
831 834 )
832 835 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
833 836 default='basic',
834 837 generic=True,
835 838 priority=-1,
836 839 )
837 840 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
838 841 default=dynamicdefault, # take from ui.mergemarkertemplate
839 842 generic=True,
840 843 priority=-1,
841 844 )
842 845 coreconfigitem('merge-tools', br'.*\.priority$',
843 846 default=0,
844 847 generic=True,
845 848 priority=-1,
846 849 )
847 850 coreconfigitem('merge-tools', br'.*\.premerge$',
848 851 default=dynamicdefault,
849 852 generic=True,
850 853 priority=-1,
851 854 )
852 855 coreconfigitem('merge-tools', br'.*\.symlink$',
853 856 default=False,
854 857 generic=True,
855 858 priority=-1,
856 859 )
857 860 coreconfigitem('pager', 'attend-.*',
858 861 default=dynamicdefault,
859 862 generic=True,
860 863 )
861 864 coreconfigitem('pager', 'ignore',
862 865 default=list,
863 866 )
864 867 coreconfigitem('pager', 'pager',
865 868 default=dynamicdefault,
866 869 )
867 870 coreconfigitem('patch', 'eol',
868 871 default='strict',
869 872 )
870 873 coreconfigitem('patch', 'fuzz',
871 874 default=2,
872 875 )
873 876 coreconfigitem('paths', 'default',
874 877 default=None,
875 878 )
876 879 coreconfigitem('paths', 'default-push',
877 880 default=None,
878 881 )
879 882 coreconfigitem('paths', '.*',
880 883 default=None,
881 884 generic=True,
882 885 )
883 886 coreconfigitem('phases', 'checksubrepos',
884 887 default='follow',
885 888 )
886 889 coreconfigitem('phases', 'new-commit',
887 890 default='draft',
888 891 )
889 892 coreconfigitem('phases', 'publish',
890 893 default=True,
891 894 )
892 895 coreconfigitem('profiling', 'enabled',
893 896 default=False,
894 897 )
895 898 coreconfigitem('profiling', 'format',
896 899 default='text',
897 900 )
898 901 coreconfigitem('profiling', 'freq',
899 902 default=1000,
900 903 )
901 904 coreconfigitem('profiling', 'limit',
902 905 default=30,
903 906 )
904 907 coreconfigitem('profiling', 'nested',
905 908 default=0,
906 909 )
907 910 coreconfigitem('profiling', 'output',
908 911 default=None,
909 912 )
910 913 coreconfigitem('profiling', 'showmax',
911 914 default=0.999,
912 915 )
913 916 coreconfigitem('profiling', 'showmin',
914 917 default=dynamicdefault,
915 918 )
916 919 coreconfigitem('profiling', 'sort',
917 920 default='inlinetime',
918 921 )
919 922 coreconfigitem('profiling', 'statformat',
920 923 default='hotpath',
921 924 )
922 925 coreconfigitem('profiling', 'time-track',
923 926 default='cpu',
924 927 )
925 928 coreconfigitem('profiling', 'type',
926 929 default='stat',
927 930 )
928 931 coreconfigitem('progress', 'assume-tty',
929 932 default=False,
930 933 )
931 934 coreconfigitem('progress', 'changedelay',
932 935 default=1,
933 936 )
934 937 coreconfigitem('progress', 'clear-complete',
935 938 default=True,
936 939 )
937 940 coreconfigitem('progress', 'debug',
938 941 default=False,
939 942 )
940 943 coreconfigitem('progress', 'delay',
941 944 default=3,
942 945 )
943 946 coreconfigitem('progress', 'disable',
944 947 default=False,
945 948 )
946 949 coreconfigitem('progress', 'estimateinterval',
947 950 default=60.0,
948 951 )
949 952 coreconfigitem('progress', 'format',
950 953 default=lambda: ['topic', 'bar', 'number', 'estimate'],
951 954 )
952 955 coreconfigitem('progress', 'refresh',
953 956 default=0.1,
954 957 )
955 958 coreconfigitem('progress', 'width',
956 959 default=dynamicdefault,
957 960 )
958 961 coreconfigitem('push', 'pushvars.server',
959 962 default=False,
960 963 )
961 964 coreconfigitem('storage', 'new-repo-backend',
962 965 default='revlogv1',
963 966 )
964 967 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
965 968 default=True,
966 969 alias=[('format', 'aggressivemergedeltas')],
967 970 )
968 971 coreconfigitem('server', 'bookmarks-pushkey-compat',
969 972 default=True,
970 973 )
971 974 coreconfigitem('server', 'bundle1',
972 975 default=True,
973 976 )
974 977 coreconfigitem('server', 'bundle1gd',
975 978 default=None,
976 979 )
977 980 coreconfigitem('server', 'bundle1.pull',
978 981 default=None,
979 982 )
980 983 coreconfigitem('server', 'bundle1gd.pull',
981 984 default=None,
982 985 )
983 986 coreconfigitem('server', 'bundle1.push',
984 987 default=None,
985 988 )
986 989 coreconfigitem('server', 'bundle1gd.push',
987 990 default=None,
988 991 )
989 992 coreconfigitem('server', 'bundle2.stream',
990 993 default=True,
991 994 alias=[('experimental', 'bundle2.stream')]
992 995 )
993 996 coreconfigitem('server', 'compressionengines',
994 997 default=list,
995 998 )
996 999 coreconfigitem('server', 'concurrent-push-mode',
997 1000 default='strict',
998 1001 )
999 1002 coreconfigitem('server', 'disablefullbundle',
1000 1003 default=False,
1001 1004 )
1002 1005 coreconfigitem('server', 'maxhttpheaderlen',
1003 1006 default=1024,
1004 1007 )
1005 1008 coreconfigitem('server', 'pullbundle',
1006 1009 default=False,
1007 1010 )
1008 1011 coreconfigitem('server', 'preferuncompressed',
1009 1012 default=False,
1010 1013 )
1011 1014 coreconfigitem('server', 'streamunbundle',
1012 1015 default=False,
1013 1016 )
1014 1017 coreconfigitem('server', 'uncompressed',
1015 1018 default=True,
1016 1019 )
1017 1020 coreconfigitem('server', 'uncompressedallowsecret',
1018 1021 default=False,
1019 1022 )
1020 1023 coreconfigitem('server', 'validate',
1021 1024 default=False,
1022 1025 )
1023 1026 coreconfigitem('server', 'zliblevel',
1024 1027 default=-1,
1025 1028 )
1026 1029 coreconfigitem('server', 'zstdlevel',
1027 1030 default=3,
1028 1031 )
1029 1032 coreconfigitem('share', 'pool',
1030 1033 default=None,
1031 1034 )
1032 1035 coreconfigitem('share', 'poolnaming',
1033 1036 default='identity',
1034 1037 )
1035 1038 coreconfigitem('smtp', 'host',
1036 1039 default=None,
1037 1040 )
1038 1041 coreconfigitem('smtp', 'local_hostname',
1039 1042 default=None,
1040 1043 )
1041 1044 coreconfigitem('smtp', 'password',
1042 1045 default=None,
1043 1046 )
1044 1047 coreconfigitem('smtp', 'port',
1045 1048 default=dynamicdefault,
1046 1049 )
1047 1050 coreconfigitem('smtp', 'tls',
1048 1051 default='none',
1049 1052 )
1050 1053 coreconfigitem('smtp', 'username',
1051 1054 default=None,
1052 1055 )
1053 1056 coreconfigitem('sparse', 'missingwarning',
1054 1057 default=True,
1055 1058 )
1056 1059 coreconfigitem('subrepos', 'allowed',
1057 1060 default=dynamicdefault, # to make backporting simpler
1058 1061 )
1059 1062 coreconfigitem('subrepos', 'hg:allowed',
1060 1063 default=dynamicdefault,
1061 1064 )
1062 1065 coreconfigitem('subrepos', 'git:allowed',
1063 1066 default=dynamicdefault,
1064 1067 )
1065 1068 coreconfigitem('subrepos', 'svn:allowed',
1066 1069 default=dynamicdefault,
1067 1070 )
1068 1071 coreconfigitem('templates', '.*',
1069 1072 default=None,
1070 1073 generic=True,
1071 1074 )
1072 1075 coreconfigitem('trusted', 'groups',
1073 1076 default=list,
1074 1077 )
1075 1078 coreconfigitem('trusted', 'users',
1076 1079 default=list,
1077 1080 )
1078 1081 coreconfigitem('ui', '_usedassubrepo',
1079 1082 default=False,
1080 1083 )
1081 1084 coreconfigitem('ui', 'allowemptycommit',
1082 1085 default=False,
1083 1086 )
1084 1087 coreconfigitem('ui', 'archivemeta',
1085 1088 default=True,
1086 1089 )
1087 1090 coreconfigitem('ui', 'askusername',
1088 1091 default=False,
1089 1092 )
1090 1093 coreconfigitem('ui', 'clonebundlefallback',
1091 1094 default=False,
1092 1095 )
1093 1096 coreconfigitem('ui', 'clonebundleprefers',
1094 1097 default=list,
1095 1098 )
1096 1099 coreconfigitem('ui', 'clonebundles',
1097 1100 default=True,
1098 1101 )
1099 1102 coreconfigitem('ui', 'color',
1100 1103 default='auto',
1101 1104 )
1102 1105 coreconfigitem('ui', 'commitsubrepos',
1103 1106 default=False,
1104 1107 )
1105 1108 coreconfigitem('ui', 'debug',
1106 1109 default=False,
1107 1110 )
1108 1111 coreconfigitem('ui', 'debugger',
1109 1112 default=None,
1110 1113 )
1111 1114 coreconfigitem('ui', 'editor',
1112 1115 default=dynamicdefault,
1113 1116 )
1114 1117 coreconfigitem('ui', 'fallbackencoding',
1115 1118 default=None,
1116 1119 )
1117 1120 coreconfigitem('ui', 'forcecwd',
1118 1121 default=None,
1119 1122 )
1120 1123 coreconfigitem('ui', 'forcemerge',
1121 1124 default=None,
1122 1125 )
1123 1126 coreconfigitem('ui', 'formatdebug',
1124 1127 default=False,
1125 1128 )
1126 1129 coreconfigitem('ui', 'formatjson',
1127 1130 default=False,
1128 1131 )
1129 1132 coreconfigitem('ui', 'formatted',
1130 1133 default=None,
1131 1134 )
1132 1135 coreconfigitem('ui', 'graphnodetemplate',
1133 1136 default=None,
1134 1137 )
1135 1138 coreconfigitem('ui', 'history-editing-backup',
1136 1139 default=True,
1137 1140 )
1138 1141 coreconfigitem('ui', 'interactive',
1139 1142 default=None,
1140 1143 )
1141 1144 coreconfigitem('ui', 'interface',
1142 1145 default=None,
1143 1146 )
1144 1147 coreconfigitem('ui', 'interface.chunkselector',
1145 1148 default=None,
1146 1149 )
1147 1150 coreconfigitem('ui', 'large-file-limit',
1148 1151 default=10000000,
1149 1152 )
1150 1153 coreconfigitem('ui', 'logblockedtimes',
1151 1154 default=False,
1152 1155 )
1153 1156 coreconfigitem('ui', 'logtemplate',
1154 1157 default=None,
1155 1158 )
1156 1159 coreconfigitem('ui', 'merge',
1157 1160 default=None,
1158 1161 )
1159 1162 coreconfigitem('ui', 'mergemarkers',
1160 1163 default='basic',
1161 1164 )
1162 1165 coreconfigitem('ui', 'mergemarkertemplate',
1163 1166 default=('{node|short} '
1164 1167 '{ifeq(tags, "tip", "", '
1165 1168 'ifeq(tags, "", "", "{tags} "))}'
1166 1169 '{if(bookmarks, "{bookmarks} ")}'
1167 1170 '{ifeq(branch, "default", "", "{branch} ")}'
1168 1171 '- {author|user}: {desc|firstline}')
1169 1172 )
1170 1173 coreconfigitem('ui', 'nontty',
1171 1174 default=False,
1172 1175 )
1173 1176 coreconfigitem('ui', 'origbackuppath',
1174 1177 default=None,
1175 1178 )
1176 1179 coreconfigitem('ui', 'paginate',
1177 1180 default=True,
1178 1181 )
1179 1182 coreconfigitem('ui', 'patch',
1180 1183 default=None,
1181 1184 )
1182 1185 coreconfigitem('ui', 'portablefilenames',
1183 1186 default='warn',
1184 1187 )
1185 1188 coreconfigitem('ui', 'promptecho',
1186 1189 default=False,
1187 1190 )
1188 1191 coreconfigitem('ui', 'quiet',
1189 1192 default=False,
1190 1193 )
1191 1194 coreconfigitem('ui', 'quietbookmarkmove',
1192 1195 default=False,
1193 1196 )
1194 1197 coreconfigitem('ui', 'remotecmd',
1195 1198 default='hg',
1196 1199 )
1197 1200 coreconfigitem('ui', 'report_untrusted',
1198 1201 default=True,
1199 1202 )
1200 1203 coreconfigitem('ui', 'rollback',
1201 1204 default=True,
1202 1205 )
1203 1206 coreconfigitem('ui', 'signal-safe-lock',
1204 1207 default=True,
1205 1208 )
1206 1209 coreconfigitem('ui', 'slash',
1207 1210 default=False,
1208 1211 )
1209 1212 coreconfigitem('ui', 'ssh',
1210 1213 default='ssh',
1211 1214 )
1212 1215 coreconfigitem('ui', 'ssherrorhint',
1213 1216 default=None,
1214 1217 )
1215 1218 coreconfigitem('ui', 'statuscopies',
1216 1219 default=False,
1217 1220 )
1218 1221 coreconfigitem('ui', 'strict',
1219 1222 default=False,
1220 1223 )
1221 1224 coreconfigitem('ui', 'style',
1222 1225 default='',
1223 1226 )
1224 1227 coreconfigitem('ui', 'supportcontact',
1225 1228 default=None,
1226 1229 )
1227 1230 coreconfigitem('ui', 'textwidth',
1228 1231 default=78,
1229 1232 )
1230 1233 coreconfigitem('ui', 'timeout',
1231 1234 default='600',
1232 1235 )
1233 1236 coreconfigitem('ui', 'timeout.warn',
1234 1237 default=0,
1235 1238 )
1236 1239 coreconfigitem('ui', 'traceback',
1237 1240 default=False,
1238 1241 )
1239 1242 coreconfigitem('ui', 'tweakdefaults',
1240 1243 default=False,
1241 1244 )
1242 1245 coreconfigitem('ui', 'username',
1243 1246 alias=[('ui', 'user')]
1244 1247 )
1245 1248 coreconfigitem('ui', 'verbose',
1246 1249 default=False,
1247 1250 )
1248 1251 coreconfigitem('verify', 'skipflags',
1249 1252 default=None,
1250 1253 )
1251 1254 coreconfigitem('web', 'allowbz2',
1252 1255 default=False,
1253 1256 )
1254 1257 coreconfigitem('web', 'allowgz',
1255 1258 default=False,
1256 1259 )
1257 1260 coreconfigitem('web', 'allow-pull',
1258 1261 alias=[('web', 'allowpull')],
1259 1262 default=True,
1260 1263 )
1261 1264 coreconfigitem('web', 'allow-push',
1262 1265 alias=[('web', 'allow_push')],
1263 1266 default=list,
1264 1267 )
1265 1268 coreconfigitem('web', 'allowzip',
1266 1269 default=False,
1267 1270 )
1268 1271 coreconfigitem('web', 'archivesubrepos',
1269 1272 default=False,
1270 1273 )
1271 1274 coreconfigitem('web', 'cache',
1272 1275 default=True,
1273 1276 )
1274 1277 coreconfigitem('web', 'contact',
1275 1278 default=None,
1276 1279 )
1277 1280 coreconfigitem('web', 'deny_push',
1278 1281 default=list,
1279 1282 )
1280 1283 coreconfigitem('web', 'guessmime',
1281 1284 default=False,
1282 1285 )
1283 1286 coreconfigitem('web', 'hidden',
1284 1287 default=False,
1285 1288 )
1286 1289 coreconfigitem('web', 'labels',
1287 1290 default=list,
1288 1291 )
1289 1292 coreconfigitem('web', 'logoimg',
1290 1293 default='hglogo.png',
1291 1294 )
1292 1295 coreconfigitem('web', 'logourl',
1293 1296 default='https://mercurial-scm.org/',
1294 1297 )
1295 1298 coreconfigitem('web', 'accesslog',
1296 1299 default='-',
1297 1300 )
1298 1301 coreconfigitem('web', 'address',
1299 1302 default='',
1300 1303 )
1301 1304 coreconfigitem('web', 'allow-archive',
1302 1305 alias=[('web', 'allow_archive')],
1303 1306 default=list,
1304 1307 )
1305 1308 coreconfigitem('web', 'allow_read',
1306 1309 default=list,
1307 1310 )
1308 1311 coreconfigitem('web', 'baseurl',
1309 1312 default=None,
1310 1313 )
1311 1314 coreconfigitem('web', 'cacerts',
1312 1315 default=None,
1313 1316 )
1314 1317 coreconfigitem('web', 'certificate',
1315 1318 default=None,
1316 1319 )
1317 1320 coreconfigitem('web', 'collapse',
1318 1321 default=False,
1319 1322 )
1320 1323 coreconfigitem('web', 'csp',
1321 1324 default=None,
1322 1325 )
1323 1326 coreconfigitem('web', 'deny_read',
1324 1327 default=list,
1325 1328 )
1326 1329 coreconfigitem('web', 'descend',
1327 1330 default=True,
1328 1331 )
1329 1332 coreconfigitem('web', 'description',
1330 1333 default="",
1331 1334 )
1332 1335 coreconfigitem('web', 'encoding',
1333 1336 default=lambda: encoding.encoding,
1334 1337 )
1335 1338 coreconfigitem('web', 'errorlog',
1336 1339 default='-',
1337 1340 )
1338 1341 coreconfigitem('web', 'ipv6',
1339 1342 default=False,
1340 1343 )
1341 1344 coreconfigitem('web', 'maxchanges',
1342 1345 default=10,
1343 1346 )
1344 1347 coreconfigitem('web', 'maxfiles',
1345 1348 default=10,
1346 1349 )
1347 1350 coreconfigitem('web', 'maxshortchanges',
1348 1351 default=60,
1349 1352 )
1350 1353 coreconfigitem('web', 'motd',
1351 1354 default='',
1352 1355 )
1353 1356 coreconfigitem('web', 'name',
1354 1357 default=dynamicdefault,
1355 1358 )
1356 1359 coreconfigitem('web', 'port',
1357 1360 default=8000,
1358 1361 )
1359 1362 coreconfigitem('web', 'prefix',
1360 1363 default='',
1361 1364 )
1362 1365 coreconfigitem('web', 'push_ssl',
1363 1366 default=True,
1364 1367 )
1365 1368 coreconfigitem('web', 'refreshinterval',
1366 1369 default=20,
1367 1370 )
1368 1371 coreconfigitem('web', 'server-header',
1369 1372 default=None,
1370 1373 )
1371 1374 coreconfigitem('web', 'static',
1372 1375 default=None,
1373 1376 )
1374 1377 coreconfigitem('web', 'staticurl',
1375 1378 default=None,
1376 1379 )
1377 1380 coreconfigitem('web', 'stripes',
1378 1381 default=1,
1379 1382 )
1380 1383 coreconfigitem('web', 'style',
1381 1384 default='paper',
1382 1385 )
1383 1386 coreconfigitem('web', 'templates',
1384 1387 default=None,
1385 1388 )
1386 1389 coreconfigitem('web', 'view',
1387 1390 default='served',
1388 1391 )
1389 1392 coreconfigitem('worker', 'backgroundclose',
1390 1393 default=dynamicdefault,
1391 1394 )
1392 1395 # Windows defaults to a limit of 512 open files. A buffer of 128
1393 1396 # should give us enough headway.
1394 1397 coreconfigitem('worker', 'backgroundclosemaxqueue',
1395 1398 default=384,
1396 1399 )
1397 1400 coreconfigitem('worker', 'backgroundcloseminfilecount',
1398 1401 default=2048,
1399 1402 )
1400 1403 coreconfigitem('worker', 'backgroundclosethreadcount',
1401 1404 default=4,
1402 1405 )
1403 1406 coreconfigitem('worker', 'enabled',
1404 1407 default=True,
1405 1408 )
1406 1409 coreconfigitem('worker', 'numcpus',
1407 1410 default=None,
1408 1411 )
1409 1412
1410 1413 # Rebase related configuration moved to core because other extension are doing
1411 1414 # strange things. For example, shelve import the extensions to reuse some bit
1412 1415 # without formally loading it.
1413 1416 coreconfigitem('commands', 'rebase.requiredest',
1414 1417 default=False,
1415 1418 )
1416 1419 coreconfigitem('experimental', 'rebaseskipobsolete',
1417 1420 default=True,
1418 1421 )
1419 1422 coreconfigitem('rebase', 'singletransaction',
1420 1423 default=False,
1421 1424 )
1422 1425 coreconfigitem('rebase', 'experimental.inmemory',
1423 1426 default=False,
1424 1427 )
@@ -1,561 +1,668 b''
1 1 **Experimental and under active development**
2 2
3 3 This section documents the wire protocol commands exposed to transports
4 4 using the frame-based protocol. The set of commands exposed through
5 5 these transports is distinct from the set of commands exposed to legacy
6 6 transports.
7 7
8 8 The frame-based protocol uses CBOR to encode command execution requests.
9 9 All command arguments must be mapped to a specific or set of CBOR data
10 10 types.
11 11
12 12 The response to many commands is also CBOR. There is no common response
13 13 format: each command defines its own response format.
14 14
15 15 TODOs
16 16 =====
17 17
18 18 * Add "node namespace" support to each command. In order to support
19 19 SHA-1 hash transition, we want servers to be able to expose different
20 20 "node namespaces" for the same data. Every command operating on nodes
21 21 should specify which "node namespace" it is operating on and responses
22 22 should encode the "node namespace" accordingly.
23 23
24 24 Commands
25 25 ========
26 26
27 27 The sections below detail all commands available to wire protocol version
28 28 2.
29 29
30 30 branchmap
31 31 ---------
32 32
33 33 Obtain heads in named branches.
34 34
35 35 Receives no arguments.
36 36
37 37 The response is a map with bytestring keys defining the branch name.
38 38 Values are arrays of bytestring defining raw changeset nodes.
39 39
40 40 capabilities
41 41 ------------
42 42
43 43 Obtain the server's capabilities.
44 44
45 45 Receives no arguments.
46 46
47 47 This command is typically called only as part of the handshake during
48 48 initial connection establishment.
49 49
50 50 The response is a map with bytestring keys defining server information.
51 51
52 52 The defined keys are:
53 53
54 54 commands
55 55 A map defining available wire protocol commands on this server.
56 56
57 57 Keys in the map are the names of commands that can be invoked. Values
58 58 are maps defining information about that command. The bytestring keys
59 59 are:
60 60
61 61 args
62 62 (map) Describes arguments accepted by the command.
63 63
64 64 Keys are bytestrings denoting the argument name.
65 65
66 66 Values are maps describing the argument. The map has the following
67 67 bytestring keys:
68 68
69 69 default
70 70 (varied) The default value for this argument if not specified. Only
71 71 present if ``required`` is not true.
72 72
73 73 required
74 74 (boolean) Whether the argument must be specified. Failure to send
75 75 required arguments will result in an error executing the command.
76 76
77 77 type
78 78 (bytestring) The type of the argument. e.g. ``bytes`` or ``bool``.
79 79
80 80 validvalues
81 81 (set) Values that are recognized for this argument. Some arguments
82 82 only allow a fixed set of values to be specified. These arguments
83 83 may advertise that set in this key. If this set is advertised and
84 84 a value not in this set is specified, the command should result
85 85 in error.
86 86
87 87 permissions
88 88 An array of permissions required to execute this command.
89 89
90 90 *
91 91 (various) Individual commands may define extra keys that supplement
92 92 generic command metadata. See the command definition for more.
93 93
94 94 framingmediatypes
95 95 An array of bytestrings defining the supported framing protocol
96 96 media types. Servers will not accept media types not in this list.
97 97
98 98 pathfilterprefixes
99 99 (set of bytestring) Matcher prefixes that are recognized when performing
100 100 path filtering. Specifying a path filter whose type/prefix does not
101 101 match one in this set will likely be rejected by the server.
102 102
103 103 rawrepoformats
104 104 An array of storage formats the repository is using. This set of
105 105 requirements can be used to determine whether a client can read a
106 106 *raw* copy of file data available.
107 107
108 108 redirect
109 109 A map declaring potential *content redirects* that may be used by this
110 110 server. Contains the following bytestring keys:
111 111
112 112 targets
113 113 (array of maps) Potential redirect targets. Values are maps describing
114 114 this target in more detail. Each map has the following bytestring keys:
115 115
116 116 name
117 117 (bytestring) Identifier for this target. The identifier will be used
118 118 by clients to uniquely identify this target.
119 119
120 120 protocol
121 121 (bytestring) High-level network protocol. Values can be
122 122 ``http``, ```https``, ``ssh``, etc.
123 123
124 124 uris
125 125 (array of bytestrings) Representative URIs for this target.
126 126
127 127 snirequired (optional)
128 128 (boolean) Indicates whether Server Name Indication is required
129 129 to use this target. Defaults to False.
130 130
131 131 tlsversions (optional)
132 132 (array of bytestring) Indicates which TLS versions are supported by
133 133 this target. Values are ``1.1``, ``1.2``, ``1.3``, etc.
134 134
135 135 hashes
136 136 (array of bytestring) Indicates support for hashing algorithms that are
137 137 used to ensure content integrity. Values include ``sha1``, ``sha256``,
138 138 etc.
139 139
140 140 changesetdata
141 141 -------------
142 142
143 143 Obtain various data related to changesets.
144 144
145 145 The command accepts the following arguments:
146 146
147 147 revisions
148 148 (array of maps) Specifies revisions whose data is being requested. Each
149 149 value in the array is a map describing revisions. See the
150 150 *Revisions Specifiers* section below for the format of this map.
151 151
152 152 Data will be sent for the union of all revisions resolved by all
153 153 revision specifiers.
154 154
155 155 Only revision specifiers operating on changeset revisions are allowed.
156 156
157 157 fields
158 158 (set of bytestring) Which data associated with changelog revisions to
159 159 fetch. The following values are recognized:
160 160
161 161 bookmarks
162 162 Bookmarks associated with a revision.
163 163
164 164 parents
165 165 Parent revisions.
166 166
167 167 phase
168 168 The phase state of a revision.
169 169
170 170 revision
171 171 The raw, revision data for the changelog entry. The hash of this data
172 172 will match the revision's node value.
173 173
174 174 The response bytestream starts with a CBOR map describing the data that follows.
175 175 This map has the following bytestring keys:
176 176
177 177 totalitems
178 178 (unsigned integer) Total number of changelog revisions whose data is being
179 179 transferred. This maps to the set of revisions in the requested node
180 180 range, not the total number of records that follow (see below for why).
181 181
182 182 Following the map header is a series of 0 or more CBOR values. If values
183 183 are present, the first value will always be a map describing a single changeset
184 184 revision.
185 185
186 186 If the ``fieldsfollowing`` key is present, the map will immediately be followed
187 187 by N CBOR bytestring values, where N is the number of elements in
188 188 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
189 189 by ``fieldsfollowing``.
190 190
191 191 Following the optional bytestring field values is the next revision descriptor
192 192 map, or end of stream.
193 193
194 194 Each revision descriptor map has the following bytestring keys:
195 195
196 196 node
197 197 (bytestring) The node value for this revision. This is the SHA-1 hash of
198 198 the raw revision data.
199 199
200 200 bookmarks (optional)
201 201 (array of bytestrings) Bookmarks attached to this revision. Only present
202 202 if ``bookmarks`` data is being requested and the revision has bookmarks
203 203 attached.
204 204
205 205 fieldsfollowing (optional)
206 206 (array of 2-array) Denotes what fields immediately follow this map. Each
207 207 value is an array with 2 elements: the bytestring field name and an unsigned
208 208 integer describing the length of the data, in bytes.
209 209
210 210 If this key isn't present, no special fields will follow this map.
211 211
212 212 The following fields may be present:
213 213
214 214 revision
215 215 Raw, revision data for the changelog entry. Contains a serialized form
216 216 of the changeset data, including the author, date, commit message, set
217 217 of changed files, manifest node, and other metadata.
218 218
219 219 Only present if the ``revision`` field was requested.
220 220
221 221 parents (optional)
222 222 (array of bytestrings) The nodes representing the parent revisions of this
223 223 revision. Only present if ``parents`` data is being requested.
224 224
225 225 phase (optional)
226 226 (bytestring) The phase that a revision is in. Recognized values are
227 227 ``secret``, ``draft``, and ``public``. Only present if ``phase`` data
228 228 is being requested.
229 229
230 230 The set of changeset revisions emitted may not match the exact set of
231 231 changesets requested. Furthermore, the set of keys present on each
232 232 map may vary. This is to facilitate emitting changeset updates as well
233 233 as new revisions.
234 234
235 235 For example, if the request wants ``phase`` and ``revision`` data,
236 236 the response may contain entries for each changeset in the common nodes
237 237 set with the ``phase`` key and without the ``revision`` key in order
238 238 to reflect a phase-only update.
239 239
240 240 TODO support different revision selection mechanisms (e.g. non-public, specific
241 241 revisions)
242 242 TODO support different hash "namespaces" for revisions (e.g. sha-1 versus other)
243 243 TODO support emitting obsolescence data
244 244 TODO support filtering based on relevant paths (narrow clone)
245 245 TODO support hgtagsfnodes cache / tags data
246 246 TODO support branch heads cache
247 247 TODO consider unify query mechanism. e.g. as an array of "query descriptors"
248 248 rather than a set of top-level arguments that have semantics when combined.
249 249
250 250 filedata
251 251 --------
252 252
253 253 Obtain various data related to an individual tracked file.
254 254
255 255 The command accepts the following arguments:
256 256
257 257 fields
258 258 (set of bytestring) Which data associated with a file to fetch.
259 259 The following values are recognized:
260 260
261 261 parents
262 262 Parent nodes for the revision.
263 263
264 264 revision
265 265 The raw revision data for a file.
266 266
267 267 haveparents
268 268 (bool) Whether the client has the parent revisions of all requested
269 269 nodes. If set, the server may emit revision data as deltas against
270 270 any parent revision. If not set, the server MUST only emit deltas for
271 271 revisions previously emitted by this command.
272 272
273 273 False is assumed in the absence of any value.
274 274
275 275 nodes
276 276 (array of bytestrings) File nodes whose data to retrieve.
277 277
278 278 path
279 279 (bytestring) Path of the tracked file whose data to retrieve.
280 280
281 281 TODO allow specifying revisions via alternate means (such as from
282 282 changeset revisions or ranges)
283 283
284 284 The response bytestream starts with a CBOR map describing the data that
285 285 follows. It has the following bytestream keys:
286 286
287 287 totalitems
288 288 (unsigned integer) Total number of file revisions whose data is
289 289 being returned.
290 290
291 291 Following the map header is a series of 0 or more CBOR values. If values
292 292 are present, the first value will always be a map describing a single changeset
293 293 revision.
294 294
295 295 If the ``fieldsfollowing`` key is present, the map will immediately be followed
296 296 by N CBOR bytestring values, where N is the number of elements in
297 297 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
298 298 by ``fieldsfollowing``.
299 299
300 300 Following the optional bytestring field values is the next revision descriptor
301 301 map, or end of stream.
302 302
303 303 Each revision descriptor map has the following bytestring keys:
304 304
305 305 Each map has the following bytestring keys:
306 306
307 307 node
308 308 (bytestring) The node of the file revision whose data is represented.
309 309
310 310 deltabasenode
311 311 (bytestring) Node of the file revision the following delta is against.
312 312
313 313 Only present if the ``revision`` field is requested and delta data
314 314 follows this map.
315 315
316 316 fieldsfollowing
317 317 (array of 2-array) Denotes extra bytestring fields that following this map.
318 318 See the documentation for ``changesetdata`` for semantics.
319 319
320 320 The following named fields may be present:
321 321
322 322 ``delta``
323 323 The delta data to use to construct the fulltext revision.
324 324
325 325 Only present if the ``revision`` field is requested and a delta is
326 326 being emitted. The ``deltabasenode`` top-level key will also be
327 327 present if this field is being emitted.
328 328
329 329 ``revision``
330 330 The fulltext revision data for this manifest. Only present if the
331 331 ``revision`` field is requested and a fulltext revision is being emitted.
332 332
333 333 parents
334 334 (array of bytestring) The nodes of the parents of this file revision.
335 335
336 336 Only present if the ``parents`` field is requested.
337 337
338 338 When ``revision`` data is requested, the server chooses to emit either fulltext
339 339 revision data or a delta. What the server decides can be inferred by looking
340 340 for the presence of the ``delta`` or ``revision`` keys in the
341 341 ``fieldsfollowing`` array.
342 342
343 filesdata
344 ---------
345
346 Obtain various data related to multiple tracked files for specific changesets.
347
348 This command is similar to ``filedata`` with the main difference being that
349 individual requests operate on multiple file paths. This allows clients to
350 request data for multiple paths by issuing a single command.
351
352 The command accepts the following arguments:
353
354 fields
355 (set of bytestring) Which data associated with a file to fetch.
356 The following values are recognized:
357
358 parents
359 Parent nodes for the revision.
360
361 revision
362 The raw revision data for a file.
363
364 haveparents
365 (bool) Whether the client has the parent revisions of all requested
366 nodes.
367
368 pathfilter
369 (map) Defines a filter that determines what file paths are relevant.
370
371 See the *Path Filters* section for more.
372
373 If the argument is omitted, it is assumed that all paths are relevant.
374
375 revisions
376 (array of maps) Specifies revisions whose data is being requested. Each value
377 in the array is a map describing revisions. See the *Revisions Specifiers*
378 section below for the format of this map.
379
380 Data will be sent for the union of all revisions resolved by all revision
381 specifiers.
382
383 Only revision specifiers operating on changeset revisions are allowed.
384
385 The response bytestream starts with a CBOR map describing the data that
386 follows. This map has the following bytestring keys:
387
388 totalpaths
389 (unsigned integer) Total number of paths whose data is being transferred.
390
391 totalitems
392 (unsigned integer) Total number of file revisions whose data is being
393 transferred.
394
395 Following the map header are 0 or more sequences of CBOR values. Each sequence
396 represents data for a specific tracked path. Each sequence begins with a CBOR
397 map describing the file data that follows. Following that map is N CBOR values
398 describing file revision data. The format of this data is identical to that
399 returned by the ``filedata`` command.
400
401 Each sequence's map header has the following bytestring keys:
402
403 path
404 (bytestring) The tracked file path whose data follows.
405
406 totalitems
407 (unsigned integer) Total number of file revisions whose data is being
408 transferred.
409
410 The ``haveparents`` argument has significant implications on the data
411 transferred.
412
413 When ``haveparents`` is true, the command MAY only emit data for file
414 revisions introduced by the set of changeset revisions whose data is being
415 requested. In other words, the command may assume that all file revisions
416 for all relevant paths for ancestors of the requested changeset revisions
417 are present on the receiver.
418
419 When ``haveparents`` is false, the command MUST assume that the receiver
420 has no file revisions data. This means that all referenced file revisions
421 in the queried set of changeset revisions will be sent.
422
423 TODO we'll probably want a more complicated mechanism for the client to
424 specify which ancestor revisions are known.
425
343 426 heads
344 427 -----
345 428
346 429 Obtain DAG heads in the repository.
347 430
348 431 The command accepts the following arguments:
349 432
350 433 publiconly (optional)
351 434 (boolean) If set, operate on the DAG for public phase changesets only.
352 435 Non-public (i.e. draft) phase DAG heads will not be returned.
353 436
354 437 The response is a CBOR array of bytestrings defining changeset nodes
355 438 of DAG heads. The array can be empty if the repository is empty or no
356 439 changesets satisfied the request.
357 440
358 441 TODO consider exposing phase of heads in response
359 442
360 443 known
361 444 -----
362 445
363 446 Determine whether a series of changeset nodes is known to the server.
364 447
365 448 The command accepts the following arguments:
366 449
367 450 nodes
368 451 (array of bytestrings) List of changeset nodes whose presence to
369 452 query.
370 453
371 454 The response is a bytestring where each byte contains a 0 or 1 for the
372 455 corresponding requested node at the same index.
373 456
374 457 TODO use a bit array for even more compact response
375 458
376 459 listkeys
377 460 --------
378 461
379 462 List values in a specified ``pushkey`` namespace.
380 463
381 464 The command receives the following arguments:
382 465
383 466 namespace
384 467 (bytestring) Pushkey namespace to query.
385 468
386 469 The response is a map with bytestring keys and values.
387 470
388 471 TODO consider using binary to represent nodes in certain pushkey namespaces.
389 472
390 473 lookup
391 474 ------
392 475
393 476 Try to resolve a value to a changeset revision.
394 477
395 478 Unlike ``known`` which operates on changeset nodes, lookup operates on
396 479 node fragments and other names that a user may use.
397 480
398 481 The command receives the following arguments:
399 482
400 483 key
401 484 (bytestring) Value to try to resolve.
402 485
403 486 On success, returns a bytestring containing the resolved node.
404 487
405 488 manifestdata
406 489 ------------
407 490
408 491 Obtain various data related to manifests (which are lists of files in
409 492 a revision).
410 493
411 494 The command accepts the following arguments:
412 495
413 496 fields
414 497 (set of bytestring) Which data associated with manifests to fetch.
415 498 The following values are recognized:
416 499
417 500 parents
418 501 Parent nodes for the manifest.
419 502
420 503 revision
421 504 The raw revision data for the manifest.
422 505
423 506 haveparents
424 507 (bool) Whether the client has the parent revisions of all requested
425 508 nodes. If set, the server may emit revision data as deltas against
426 509 any parent revision. If not set, the server MUST only emit deltas for
427 510 revisions previously emitted by this command.
428 511
429 512 False is assumed in the absence of any value.
430 513
431 514 nodes
432 515 (array of bytestring) Manifest nodes whose data to retrieve.
433 516
434 517 tree
435 518 (bytestring) Path to manifest to retrieve. The empty bytestring represents
436 519 the root manifest. All other values represent directories/trees within
437 520 the repository.
438 521
439 522 TODO allow specifying revisions via alternate means (such as from changeset
440 523 revisions or ranges)
441 524 TODO consider recursive expansion of manifests (with path filtering for
442 525 narrow use cases)
443 526
444 527 The response bytestream starts with a CBOR map describing the data that
445 528 follows. It has the following bytestring keys:
446 529
447 530 totalitems
448 531 (unsigned integer) Total number of manifest revisions whose data is
449 532 being returned.
450 533
451 534 Following the map header is a series of 0 or more CBOR values. If values
452 535 are present, the first value will always be a map describing a single manifest
453 536 revision.
454 537
455 538 If the ``fieldsfollowing`` key is present, the map will immediately be followed
456 539 by N CBOR bytestring values, where N is the number of elements in
457 540 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
458 541 by ``fieldsfollowing``.
459 542
460 543 Following the optional bytestring field values is the next revision descriptor
461 544 map, or end of stream.
462 545
463 546 Each revision descriptor map has the following bytestring keys:
464 547
465 548 node
466 549 (bytestring) The node of the manifest revision whose data is represented.
467 550
468 551 deltabasenode
469 552 (bytestring) The node that the delta representation of this revision is
470 553 computed against. Only present if the ``revision`` field is requested and
471 554 a delta is being emitted.
472 555
473 556 fieldsfollowing
474 557 (array of 2-array) Denotes extra bytestring fields that following this map.
475 558 See the documentation for ``changesetdata`` for semantics.
476 559
477 560 The following named fields may be present:
478 561
479 562 ``delta``
480 563 The delta data to use to construct the fulltext revision.
481 564
482 565 Only present if the ``revision`` field is requested and a delta is
483 566 being emitted. The ``deltabasenode`` top-level key will also be
484 567 present if this field is being emitted.
485 568
486 569 ``revision``
487 570 The fulltext revision data for this manifest. Only present if the
488 571 ``revision`` field is requested and a fulltext revision is being emitted.
489 572
490 573 parents
491 574 (array of bytestring) The nodes of the parents of this manifest revision.
492 575 Only present if the ``parents`` field is requested.
493 576
494 577 When ``revision`` data is requested, the server chooses to emit either fulltext
495 578 revision data or a delta. What the server decides can be inferred by looking
496 579 for the presence of ``delta`` or ``revision`` in the ``fieldsfollowing`` array.
497 580
498 581 Servers MAY advertise the following extra fields in the capabilities
499 582 descriptor for this command:
500 583
501 584 recommendedbatchsize
502 585 (unsigned integer) Number of revisions the server recommends as a batch
503 586 query size. If defined, clients needing to issue multiple ``manifestdata``
504 587 commands to obtain needed data SHOULD construct their commands to have
505 588 this many revisions per request.
506 589
507 590 pushkey
508 591 -------
509 592
510 593 Set a value using the ``pushkey`` protocol.
511 594
512 595 The command receives the following arguments:
513 596
514 597 namespace
515 598 (bytestring) Pushkey namespace to operate on.
516 599 key
517 600 (bytestring) The pushkey key to set.
518 601 old
519 602 (bytestring) Old value for this key.
520 603 new
521 604 (bytestring) New value for this key.
522 605
523 606 TODO consider using binary to represent nodes is certain pushkey namespaces.
524 607 TODO better define response type and meaning.
525 608
526 609 Revision Specifiers
527 610 ===================
528 611
529 612 A *revision specifier* is a map that evaluates to a set of revisions.
530 613
531 614 A *revision specifier* has a ``type`` key that defines the revision
532 615 selection type to perform. Other keys in the map are used in a
533 616 type-specific manner.
534 617
535 618 The following types are defined:
536 619
537 620 changesetexplicit
538 621 An explicit set of enumerated changeset revisions.
539 622
540 623 The ``nodes`` key MUST contain an array of full binary nodes, expressed
541 624 as bytestrings.
542 625
543 626 changesetexplicitdepth
544 627 Like ``changesetexplicit``, but contains a ``depth`` key defining the
545 628 unsigned integer number of ancestor revisions to also resolve. For each
546 629 value in ``nodes``, DAG ancestors will be walked until up to N total
547 630 revisions from that ancestry walk are present in the final resolved set.
548 631
549 632 changesetdagrange
550 633 Defines revisions via a DAG range of changesets on the changelog.
551 634
552 635 The ``roots`` key MUST contain an array of full, binary node values
553 636 representing the *root* revisions.
554 637
555 638 The ``heads`` key MUST contain an array of full, binary nodes values
556 639 representing the *head* revisions.
557 640
558 641 The DAG range between ``roots`` and ``heads`` will be resolved and all
559 642 revisions between will be used. Nodes in ``roots`` are not part of the
560 643 resolved set. Nodes in ``heads`` are. The ``roots`` array may be empty.
561 644 The ``heads`` array MUST be defined.
645
646 Path Filters
647 ============
648
649 Various commands accept a *path filter* argument that defines the set of file
650 paths relevant to the request.
651
652 A *path filter* is defined as a map with the bytestring keys ``include`` and
653 ``exclude``. Each is an array of bytestring values. Each value defines a pattern
654 rule (see :hg:`help patterns`) that is used to match file paths.
655
656 A path matches the path filter if it is matched by a rule in the ``include``
657 set but doesn't match a rule in the ``exclude`` set. In other words, a path
658 matcher takes the union of all ``include`` patterns and then substracts the
659 union of all ``exclude`` patterns.
660
661 Patterns MUST be prefixed with their pattern type. Only the following pattern
662 types are allowed: ``path:``, ``rootfilesin:``.
663
664 If the ``include`` key is omitted, it is assumed that all paths are
665 relevant. The patterns from ``exclude`` will still be used, if defined.
666
667 An example value is ``path:tests/foo``, which would match a file named
668 ``tests/foo`` or a directory ``tests/foo`` and all files under it.
@@ -1,1231 +1,1371 b''
1 1 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2 2 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 3 #
4 4 # This software may be used and distributed according to the terms of the
5 5 # GNU General Public License version 2 or any later version.
6 6
7 7 from __future__ import absolute_import
8 8
9 import collections
9 10 import contextlib
10 11 import hashlib
11 12
12 13 from .i18n import _
13 14 from .node import (
14 15 hex,
15 16 nullid,
16 17 )
17 18 from . import (
18 19 discovery,
19 20 encoding,
20 21 error,
22 match as matchmod,
21 23 narrowspec,
22 24 pycompat,
23 25 wireprotoframing,
24 26 wireprototypes,
25 27 )
26 28 from .utils import (
27 29 cborutil,
28 30 interfaceutil,
29 31 stringutil,
30 32 )
31 33
32 34 FRAMINGTYPE = b'application/mercurial-exp-framing-0006'
33 35
34 36 HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
35 37
36 38 COMMANDS = wireprototypes.commanddict()
37 39
38 40 # Value inserted into cache key computation function. Change the value to
39 41 # force new cache keys for every command request. This should be done when
40 42 # there is a change to how caching works, etc.
41 43 GLOBAL_CACHE_VERSION = 1
42 44
43 45 def handlehttpv2request(rctx, req, res, checkperm, urlparts):
44 46 from .hgweb import common as hgwebcommon
45 47
46 48 # URL space looks like: <permissions>/<command>, where <permission> can
47 49 # be ``ro`` or ``rw`` to signal read-only or read-write, respectively.
48 50
49 51 # Root URL does nothing meaningful... yet.
50 52 if not urlparts:
51 53 res.status = b'200 OK'
52 54 res.headers[b'Content-Type'] = b'text/plain'
53 55 res.setbodybytes(_('HTTP version 2 API handler'))
54 56 return
55 57
56 58 if len(urlparts) == 1:
57 59 res.status = b'404 Not Found'
58 60 res.headers[b'Content-Type'] = b'text/plain'
59 61 res.setbodybytes(_('do not know how to process %s\n') %
60 62 req.dispatchpath)
61 63 return
62 64
63 65 permission, command = urlparts[0:2]
64 66
65 67 if permission not in (b'ro', b'rw'):
66 68 res.status = b'404 Not Found'
67 69 res.headers[b'Content-Type'] = b'text/plain'
68 70 res.setbodybytes(_('unknown permission: %s') % permission)
69 71 return
70 72
71 73 if req.method != 'POST':
72 74 res.status = b'405 Method Not Allowed'
73 75 res.headers[b'Allow'] = b'POST'
74 76 res.setbodybytes(_('commands require POST requests'))
75 77 return
76 78
77 79 # At some point we'll want to use our own API instead of recycling the
78 80 # behavior of version 1 of the wire protocol...
79 81 # TODO return reasonable responses - not responses that overload the
80 82 # HTTP status line message for error reporting.
81 83 try:
82 84 checkperm(rctx, req, 'pull' if permission == b'ro' else 'push')
83 85 except hgwebcommon.ErrorResponse as e:
84 86 res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e))
85 87 for k, v in e.headers:
86 88 res.headers[k] = v
87 89 res.setbodybytes('permission denied')
88 90 return
89 91
90 92 # We have a special endpoint to reflect the request back at the client.
91 93 if command == b'debugreflect':
92 94 _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
93 95 return
94 96
95 97 # Extra commands that we handle that aren't really wire protocol
96 98 # commands. Think extra hard before making this hackery available to
97 99 # extension.
98 100 extracommands = {'multirequest'}
99 101
100 102 if command not in COMMANDS and command not in extracommands:
101 103 res.status = b'404 Not Found'
102 104 res.headers[b'Content-Type'] = b'text/plain'
103 105 res.setbodybytes(_('unknown wire protocol command: %s\n') % command)
104 106 return
105 107
106 108 repo = rctx.repo
107 109 ui = repo.ui
108 110
109 111 proto = httpv2protocolhandler(req, ui)
110 112
111 113 if (not COMMANDS.commandavailable(command, proto)
112 114 and command not in extracommands):
113 115 res.status = b'404 Not Found'
114 116 res.headers[b'Content-Type'] = b'text/plain'
115 117 res.setbodybytes(_('invalid wire protocol command: %s') % command)
116 118 return
117 119
118 120 # TODO consider cases where proxies may add additional Accept headers.
119 121 if req.headers.get(b'Accept') != FRAMINGTYPE:
120 122 res.status = b'406 Not Acceptable'
121 123 res.headers[b'Content-Type'] = b'text/plain'
122 124 res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
123 125 % FRAMINGTYPE)
124 126 return
125 127
126 128 if req.headers.get(b'Content-Type') != FRAMINGTYPE:
127 129 res.status = b'415 Unsupported Media Type'
128 130 # TODO we should send a response with appropriate media type,
129 131 # since client does Accept it.
130 132 res.headers[b'Content-Type'] = b'text/plain'
131 133 res.setbodybytes(_('client MUST send Content-Type header with '
132 134 'value: %s\n') % FRAMINGTYPE)
133 135 return
134 136
135 137 _processhttpv2request(ui, repo, req, res, permission, command, proto)
136 138
137 139 def _processhttpv2reflectrequest(ui, repo, req, res):
138 140 """Reads unified frame protocol request and dumps out state to client.
139 141
140 142 This special endpoint can be used to help debug the wire protocol.
141 143
142 144 Instead of routing the request through the normal dispatch mechanism,
143 145 we instead read all frames, decode them, and feed them into our state
144 146 tracker. We then dump the log of all that activity back out to the
145 147 client.
146 148 """
147 149 import json
148 150
149 151 # Reflection APIs have a history of being abused, accidentally disclosing
150 152 # sensitive data, etc. So we have a config knob.
151 153 if not ui.configbool('experimental', 'web.api.debugreflect'):
152 154 res.status = b'404 Not Found'
153 155 res.headers[b'Content-Type'] = b'text/plain'
154 156 res.setbodybytes(_('debugreflect service not available'))
155 157 return
156 158
157 159 # We assume we have a unified framing protocol request body.
158 160
159 161 reactor = wireprotoframing.serverreactor(ui)
160 162 states = []
161 163
162 164 while True:
163 165 frame = wireprotoframing.readframe(req.bodyfh)
164 166
165 167 if not frame:
166 168 states.append(b'received: <no frame>')
167 169 break
168 170
169 171 states.append(b'received: %d %d %d %s' % (frame.typeid, frame.flags,
170 172 frame.requestid,
171 173 frame.payload))
172 174
173 175 action, meta = reactor.onframerecv(frame)
174 176 states.append(json.dumps((action, meta), sort_keys=True,
175 177 separators=(', ', ': ')))
176 178
177 179 action, meta = reactor.oninputeof()
178 180 meta['action'] = action
179 181 states.append(json.dumps(meta, sort_keys=True, separators=(', ',': ')))
180 182
181 183 res.status = b'200 OK'
182 184 res.headers[b'Content-Type'] = b'text/plain'
183 185 res.setbodybytes(b'\n'.join(states))
184 186
185 187 def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
186 188 """Post-validation handler for HTTPv2 requests.
187 189
188 190 Called when the HTTP request contains unified frame-based protocol
189 191 frames for evaluation.
190 192 """
191 193 # TODO Some HTTP clients are full duplex and can receive data before
192 194 # the entire request is transmitted. Figure out a way to indicate support
193 195 # for that so we can opt into full duplex mode.
194 196 reactor = wireprotoframing.serverreactor(ui, deferoutput=True)
195 197 seencommand = False
196 198
197 199 outstream = None
198 200
199 201 while True:
200 202 frame = wireprotoframing.readframe(req.bodyfh)
201 203 if not frame:
202 204 break
203 205
204 206 action, meta = reactor.onframerecv(frame)
205 207
206 208 if action == 'wantframe':
207 209 # Need more data before we can do anything.
208 210 continue
209 211 elif action == 'runcommand':
210 212 # Defer creating output stream because we need to wait for
211 213 # protocol settings frames so proper encoding can be applied.
212 214 if not outstream:
213 215 outstream = reactor.makeoutputstream()
214 216
215 217 sentoutput = _httpv2runcommand(ui, repo, req, res, authedperm,
216 218 reqcommand, reactor, outstream,
217 219 meta, issubsequent=seencommand)
218 220
219 221 if sentoutput:
220 222 return
221 223
222 224 seencommand = True
223 225
224 226 elif action == 'error':
225 227 # TODO define proper error mechanism.
226 228 res.status = b'200 OK'
227 229 res.headers[b'Content-Type'] = b'text/plain'
228 230 res.setbodybytes(meta['message'] + b'\n')
229 231 return
230 232 else:
231 233 raise error.ProgrammingError(
232 234 'unhandled action from frame processor: %s' % action)
233 235
234 236 action, meta = reactor.oninputeof()
235 237 if action == 'sendframes':
236 238 # We assume we haven't started sending the response yet. If we're
237 239 # wrong, the response type will raise an exception.
238 240 res.status = b'200 OK'
239 241 res.headers[b'Content-Type'] = FRAMINGTYPE
240 242 res.setbodygen(meta['framegen'])
241 243 elif action == 'noop':
242 244 pass
243 245 else:
244 246 raise error.ProgrammingError('unhandled action from frame processor: %s'
245 247 % action)
246 248
247 249 def _httpv2runcommand(ui, repo, req, res, authedperm, reqcommand, reactor,
248 250 outstream, command, issubsequent):
249 251 """Dispatch a wire protocol command made from HTTPv2 requests.
250 252
251 253 The authenticated permission (``authedperm``) along with the original
252 254 command from the URL (``reqcommand``) are passed in.
253 255 """
254 256 # We already validated that the session has permissions to perform the
255 257 # actions in ``authedperm``. In the unified frame protocol, the canonical
256 258 # command to run is expressed in a frame. However, the URL also requested
257 259 # to run a specific command. We need to be careful that the command we
258 260 # run doesn't have permissions requirements greater than what was granted
259 261 # by ``authedperm``.
260 262 #
261 263 # Our rule for this is we only allow one command per HTTP request and
262 264 # that command must match the command in the URL. However, we make
263 265 # an exception for the ``multirequest`` URL. This URL is allowed to
264 266 # execute multiple commands. We double check permissions of each command
265 267 # as it is invoked to ensure there is no privilege escalation.
266 268 # TODO consider allowing multiple commands to regular command URLs
267 269 # iff each command is the same.
268 270
269 271 proto = httpv2protocolhandler(req, ui, args=command['args'])
270 272
271 273 if reqcommand == b'multirequest':
272 274 if not COMMANDS.commandavailable(command['command'], proto):
273 275 # TODO proper error mechanism
274 276 res.status = b'200 OK'
275 277 res.headers[b'Content-Type'] = b'text/plain'
276 278 res.setbodybytes(_('wire protocol command not available: %s') %
277 279 command['command'])
278 280 return True
279 281
280 282 # TODO don't use assert here, since it may be elided by -O.
281 283 assert authedperm in (b'ro', b'rw')
282 284 wirecommand = COMMANDS[command['command']]
283 285 assert wirecommand.permission in ('push', 'pull')
284 286
285 287 if authedperm == b'ro' and wirecommand.permission != 'pull':
286 288 # TODO proper error mechanism
287 289 res.status = b'403 Forbidden'
288 290 res.headers[b'Content-Type'] = b'text/plain'
289 291 res.setbodybytes(_('insufficient permissions to execute '
290 292 'command: %s') % command['command'])
291 293 return True
292 294
293 295 # TODO should we also call checkperm() here? Maybe not if we're going
294 296 # to overhaul that API. The granted scope from the URL check should
295 297 # be good enough.
296 298
297 299 else:
298 300 # Don't allow multiple commands outside of ``multirequest`` URL.
299 301 if issubsequent:
300 302 # TODO proper error mechanism
301 303 res.status = b'200 OK'
302 304 res.headers[b'Content-Type'] = b'text/plain'
303 305 res.setbodybytes(_('multiple commands cannot be issued to this '
304 306 'URL'))
305 307 return True
306 308
307 309 if reqcommand != command['command']:
308 310 # TODO define proper error mechanism
309 311 res.status = b'200 OK'
310 312 res.headers[b'Content-Type'] = b'text/plain'
311 313 res.setbodybytes(_('command in frame must match command in URL'))
312 314 return True
313 315
314 316 res.status = b'200 OK'
315 317 res.headers[b'Content-Type'] = FRAMINGTYPE
316 318
317 319 try:
318 320 objs = dispatch(repo, proto, command['command'], command['redirect'])
319 321
320 322 action, meta = reactor.oncommandresponsereadyobjects(
321 323 outstream, command['requestid'], objs)
322 324
323 325 except error.WireprotoCommandError as e:
324 326 action, meta = reactor.oncommanderror(
325 327 outstream, command['requestid'], e.message, e.messageargs)
326 328
327 329 except Exception as e:
328 330 action, meta = reactor.onservererror(
329 331 outstream, command['requestid'],
330 332 _('exception when invoking command: %s') %
331 333 stringutil.forcebytestr(e))
332 334
333 335 if action == 'sendframes':
334 336 res.setbodygen(meta['framegen'])
335 337 return True
336 338 elif action == 'noop':
337 339 return False
338 340 else:
339 341 raise error.ProgrammingError('unhandled event from reactor: %s' %
340 342 action)
341 343
342 344 def getdispatchrepo(repo, proto, command):
343 345 return repo.filtered('served')
344 346
345 347 def dispatch(repo, proto, command, redirect):
346 348 """Run a wire protocol command.
347 349
348 350 Returns an iterable of objects that will be sent to the client.
349 351 """
350 352 repo = getdispatchrepo(repo, proto, command)
351 353
352 354 entry = COMMANDS[command]
353 355 func = entry.func
354 356 spec = entry.args
355 357
356 358 args = proto.getargs(spec)
357 359
358 360 # There is some duplicate boilerplate code here for calling the command and
359 361 # emitting objects. It is either that or a lot of indented code that looks
360 362 # like a pyramid (since there are a lot of code paths that result in not
361 363 # using the cacher).
362 364 callcommand = lambda: func(repo, proto, **pycompat.strkwargs(args))
363 365
364 366 # Request is not cacheable. Don't bother instantiating a cacher.
365 367 if not entry.cachekeyfn:
366 368 for o in callcommand():
367 369 yield o
368 370 return
369 371
370 372 if redirect:
371 373 redirecttargets = redirect[b'targets']
372 374 redirecthashes = redirect[b'hashes']
373 375 else:
374 376 redirecttargets = []
375 377 redirecthashes = []
376 378
377 379 cacher = makeresponsecacher(repo, proto, command, args,
378 380 cborutil.streamencode,
379 381 redirecttargets=redirecttargets,
380 382 redirecthashes=redirecthashes)
381 383
382 384 # But we have no cacher. Do default handling.
383 385 if not cacher:
384 386 for o in callcommand():
385 387 yield o
386 388 return
387 389
388 390 with cacher:
389 391 cachekey = entry.cachekeyfn(repo, proto, cacher, **args)
390 392
391 393 # No cache key or the cacher doesn't like it. Do default handling.
392 394 if cachekey is None or not cacher.setcachekey(cachekey):
393 395 for o in callcommand():
394 396 yield o
395 397 return
396 398
397 399 # Serve it from the cache, if possible.
398 400 cached = cacher.lookup()
399 401
400 402 if cached:
401 403 for o in cached['objs']:
402 404 yield o
403 405 return
404 406
405 407 # Else call the command and feed its output into the cacher, allowing
406 408 # the cacher to buffer/mutate objects as it desires.
407 409 for o in callcommand():
408 410 for o in cacher.onobject(o):
409 411 yield o
410 412
411 413 for o in cacher.onfinished():
412 414 yield o
413 415
414 416 @interfaceutil.implementer(wireprototypes.baseprotocolhandler)
415 417 class httpv2protocolhandler(object):
416 418 def __init__(self, req, ui, args=None):
417 419 self._req = req
418 420 self._ui = ui
419 421 self._args = args
420 422
421 423 @property
422 424 def name(self):
423 425 return HTTP_WIREPROTO_V2
424 426
425 427 def getargs(self, args):
426 428 # First look for args that were passed but aren't registered on this
427 429 # command.
428 430 extra = set(self._args) - set(args)
429 431 if extra:
430 432 raise error.WireprotoCommandError(
431 433 'unsupported argument to command: %s' %
432 434 ', '.join(sorted(extra)))
433 435
434 436 # And look for required arguments that are missing.
435 437 missing = {a for a in args if args[a]['required']} - set(self._args)
436 438
437 439 if missing:
438 440 raise error.WireprotoCommandError(
439 441 'missing required arguments: %s' % ', '.join(sorted(missing)))
440 442
441 443 # Now derive the arguments to pass to the command, taking into
442 444 # account the arguments specified by the client.
443 445 data = {}
444 446 for k, meta in sorted(args.items()):
445 447 # This argument wasn't passed by the client.
446 448 if k not in self._args:
447 449 data[k] = meta['default']()
448 450 continue
449 451
450 452 v = self._args[k]
451 453
452 454 # Sets may be expressed as lists. Silently normalize.
453 455 if meta['type'] == 'set' and isinstance(v, list):
454 456 v = set(v)
455 457
456 458 # TODO consider more/stronger type validation.
457 459
458 460 data[k] = v
459 461
460 462 return data
461 463
462 464 def getprotocaps(self):
463 465 # Protocol capabilities are currently not implemented for HTTP V2.
464 466 return set()
465 467
466 468 def getpayload(self):
467 469 raise NotImplementedError
468 470
469 471 @contextlib.contextmanager
470 472 def mayberedirectstdio(self):
471 473 raise NotImplementedError
472 474
473 475 def client(self):
474 476 raise NotImplementedError
475 477
476 478 def addcapabilities(self, repo, caps):
477 479 return caps
478 480
479 481 def checkperm(self, perm):
480 482 raise NotImplementedError
481 483
482 484 def httpv2apidescriptor(req, repo):
483 485 proto = httpv2protocolhandler(req, repo.ui)
484 486
485 487 return _capabilitiesv2(repo, proto)
486 488
487 489 def _capabilitiesv2(repo, proto):
488 490 """Obtain the set of capabilities for version 2 transports.
489 491
490 492 These capabilities are distinct from the capabilities for version 1
491 493 transports.
492 494 """
493 495 caps = {
494 496 'commands': {},
495 497 'framingmediatypes': [FRAMINGTYPE],
496 498 'pathfilterprefixes': set(narrowspec.VALID_PREFIXES),
497 499 }
498 500
499 501 for command, entry in COMMANDS.items():
500 502 args = {}
501 503
502 504 for arg, meta in entry.args.items():
503 505 args[arg] = {
504 506 # TODO should this be a normalized type using CBOR's
505 507 # terminology?
506 508 b'type': meta['type'],
507 509 b'required': meta['required'],
508 510 }
509 511
510 512 if not meta['required']:
511 513 args[arg][b'default'] = meta['default']()
512 514
513 515 if meta['validvalues']:
514 516 args[arg][b'validvalues'] = meta['validvalues']
515 517
516 518 caps['commands'][command] = {
517 519 'args': args,
518 520 'permissions': [entry.permission],
519 521 }
520 522
521 523 if entry.extracapabilitiesfn:
522 524 extracaps = entry.extracapabilitiesfn(repo, proto)
523 525 caps['commands'][command].update(extracaps)
524 526
525 527 caps['rawrepoformats'] = sorted(repo.requirements &
526 528 repo.supportedformats)
527 529
528 530 targets = getadvertisedredirecttargets(repo, proto)
529 531 if targets:
530 532 caps[b'redirect'] = {
531 533 b'targets': [],
532 534 b'hashes': [b'sha256', b'sha1'],
533 535 }
534 536
535 537 for target in targets:
536 538 entry = {
537 539 b'name': target['name'],
538 540 b'protocol': target['protocol'],
539 541 b'uris': target['uris'],
540 542 }
541 543
542 544 for key in ('snirequired', 'tlsversions'):
543 545 if key in target:
544 546 entry[key] = target[key]
545 547
546 548 caps[b'redirect'][b'targets'].append(entry)
547 549
548 550 return proto.addcapabilities(repo, caps)
549 551
550 552 def getadvertisedredirecttargets(repo, proto):
551 553 """Obtain a list of content redirect targets.
552 554
553 555 Returns a list containing potential redirect targets that will be
554 556 advertised in capabilities data. Each dict MUST have the following
555 557 keys:
556 558
557 559 name
558 560 The name of this redirect target. This is the identifier clients use
559 561 to refer to a target. It is transferred as part of every command
560 562 request.
561 563
562 564 protocol
563 565 Network protocol used by this target. Typically this is the string
564 566 in front of the ``://`` in a URL. e.g. ``https``.
565 567
566 568 uris
567 569 List of representative URIs for this target. Clients can use the
568 570 URIs to test parsing for compatibility or for ordering preference
569 571 for which target to use.
570 572
571 573 The following optional keys are recognized:
572 574
573 575 snirequired
574 576 Bool indicating if Server Name Indication (SNI) is required to
575 577 connect to this target.
576 578
577 579 tlsversions
578 580 List of bytes indicating which TLS versions are supported by this
579 581 target.
580 582
581 583 By default, clients reflect the target order advertised by servers
582 584 and servers will use the first client-advertised target when picking
583 585 a redirect target. So targets should be advertised in the order the
584 586 server prefers they be used.
585 587 """
586 588 return []
587 589
588 590 def wireprotocommand(name, args=None, permission='push', cachekeyfn=None,
589 591 extracapabilitiesfn=None):
590 592 """Decorator to declare a wire protocol command.
591 593
592 594 ``name`` is the name of the wire protocol command being provided.
593 595
594 596 ``args`` is a dict defining arguments accepted by the command. Keys are
595 597 the argument name. Values are dicts with the following keys:
596 598
597 599 ``type``
598 600 The argument data type. Must be one of the following string
599 601 literals: ``bytes``, ``int``, ``list``, ``dict``, ``set``,
600 602 or ``bool``.
601 603
602 604 ``default``
603 605 A callable returning the default value for this argument. If not
604 606 specified, ``None`` will be the default value.
605 607
606 608 ``example``
607 609 An example value for this argument.
608 610
609 611 ``validvalues``
610 612 Set of recognized values for this argument.
611 613
612 614 ``permission`` defines the permission type needed to run this command.
613 615 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
614 616 respectively. Default is to assume command requires ``push`` permissions
615 617 because otherwise commands not declaring their permissions could modify
616 618 a repository that is supposed to be read-only.
617 619
618 620 ``cachekeyfn`` defines an optional callable that can derive the
619 621 cache key for this request.
620 622
621 623 ``extracapabilitiesfn`` defines an optional callable that defines extra
622 624 command capabilities/parameters that are advertised next to the command
623 625 in the capabilities data structure describing the server. The callable
624 626 receives as arguments the repository and protocol objects. It returns
625 627 a dict of extra fields to add to the command descriptor.
626 628
627 629 Wire protocol commands are generators of objects to be serialized and
628 630 sent to the client.
629 631
630 632 If a command raises an uncaught exception, this will be translated into
631 633 a command error.
632 634
633 635 All commands can opt in to being cacheable by defining a function
634 636 (``cachekeyfn``) that is called to derive a cache key. This function
635 637 receives the same arguments as the command itself plus a ``cacher``
636 638 argument containing the active cacher for the request and returns a bytes
637 639 containing the key in a cache the response to this command may be cached
638 640 under.
639 641 """
640 642 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
641 643 if v['version'] == 2}
642 644
643 645 if permission not in ('push', 'pull'):
644 646 raise error.ProgrammingError('invalid wire protocol permission; '
645 647 'got %s; expected "push" or "pull"' %
646 648 permission)
647 649
648 650 if args is None:
649 651 args = {}
650 652
651 653 if not isinstance(args, dict):
652 654 raise error.ProgrammingError('arguments for version 2 commands '
653 655 'must be declared as dicts')
654 656
655 657 for arg, meta in args.items():
656 658 if arg == '*':
657 659 raise error.ProgrammingError('* argument name not allowed on '
658 660 'version 2 commands')
659 661
660 662 if not isinstance(meta, dict):
661 663 raise error.ProgrammingError('arguments for version 2 commands '
662 664 'must declare metadata as a dict')
663 665
664 666 if 'type' not in meta:
665 667 raise error.ProgrammingError('%s argument for command %s does not '
666 668 'declare type field' % (arg, name))
667 669
668 670 if meta['type'] not in ('bytes', 'int', 'list', 'dict', 'set', 'bool'):
669 671 raise error.ProgrammingError('%s argument for command %s has '
670 672 'illegal type: %s' % (arg, name,
671 673 meta['type']))
672 674
673 675 if 'example' not in meta:
674 676 raise error.ProgrammingError('%s argument for command %s does not '
675 677 'declare example field' % (arg, name))
676 678
677 679 meta['required'] = 'default' not in meta
678 680
679 681 meta.setdefault('default', lambda: None)
680 682 meta.setdefault('validvalues', None)
681 683
682 684 def register(func):
683 685 if name in COMMANDS:
684 686 raise error.ProgrammingError('%s command already registered '
685 687 'for version 2' % name)
686 688
687 689 COMMANDS[name] = wireprototypes.commandentry(
688 690 func, args=args, transports=transports, permission=permission,
689 691 cachekeyfn=cachekeyfn, extracapabilitiesfn=extracapabilitiesfn)
690 692
691 693 return func
692 694
693 695 return register
694 696
695 697 def makecommandcachekeyfn(command, localversion=None, allargs=False):
696 698 """Construct a cache key derivation function with common features.
697 699
698 700 By default, the cache key is a hash of:
699 701
700 702 * The command name.
701 703 * A global cache version number.
702 704 * A local cache version number (passed via ``localversion``).
703 705 * All the arguments passed to the command.
704 706 * The media type used.
705 707 * Wire protocol version string.
706 708 * The repository path.
707 709 """
708 710 if not allargs:
709 711 raise error.ProgrammingError('only allargs=True is currently supported')
710 712
711 713 if localversion is None:
712 714 raise error.ProgrammingError('must set localversion argument value')
713 715
714 716 def cachekeyfn(repo, proto, cacher, **args):
715 717 spec = COMMANDS[command]
716 718
717 719 # Commands that mutate the repo can not be cached.
718 720 if spec.permission == 'push':
719 721 return None
720 722
721 723 # TODO config option to disable caching.
722 724
723 725 # Our key derivation strategy is to construct a data structure
724 726 # holding everything that could influence cacheability and to hash
725 727 # the CBOR representation of that. Using CBOR seems like it might
726 728 # be overkill. However, simpler hashing mechanisms are prone to
727 729 # duplicate input issues. e.g. if you just concatenate two values,
728 730 # "foo"+"bar" is identical to "fo"+"obar". Using CBOR provides
729 731 # "padding" between values and prevents these problems.
730 732
731 733 # Seed the hash with various data.
732 734 state = {
733 735 # To invalidate all cache keys.
734 736 b'globalversion': GLOBAL_CACHE_VERSION,
735 737 # More granular cache key invalidation.
736 738 b'localversion': localversion,
737 739 # Cache keys are segmented by command.
738 740 b'command': pycompat.sysbytes(command),
739 741 # Throw in the media type and API version strings so changes
740 742 # to exchange semantics invalid cache.
741 743 b'mediatype': FRAMINGTYPE,
742 744 b'version': HTTP_WIREPROTO_V2,
743 745 # So same requests for different repos don't share cache keys.
744 746 b'repo': repo.root,
745 747 }
746 748
747 749 # The arguments passed to us will have already been normalized.
748 750 # Default values will be set, etc. This is important because it
749 751 # means that it doesn't matter if clients send an explicit argument
750 752 # or rely on the default value: it will all normalize to the same
751 753 # set of arguments on the server and therefore the same cache key.
752 754 #
753 755 # Arguments by their very nature must support being encoded to CBOR.
754 756 # And the CBOR encoder is deterministic. So we hash the arguments
755 757 # by feeding the CBOR of their representation into the hasher.
756 758 if allargs:
757 759 state[b'args'] = pycompat.byteskwargs(args)
758 760
759 761 cacher.adjustcachekeystate(state)
760 762
761 763 hasher = hashlib.sha1()
762 764 for chunk in cborutil.streamencode(state):
763 765 hasher.update(chunk)
764 766
765 767 return pycompat.sysbytes(hasher.hexdigest())
766 768
767 769 return cachekeyfn
768 770
769 771 def makeresponsecacher(repo, proto, command, args, objencoderfn,
770 772 redirecttargets, redirecthashes):
771 773 """Construct a cacher for a cacheable command.
772 774
773 775 Returns an ``iwireprotocolcommandcacher`` instance.
774 776
775 777 Extensions can monkeypatch this function to provide custom caching
776 778 backends.
777 779 """
778 780 return None
779 781
780 782 def resolvenodes(repo, revisions):
781 783 """Resolve nodes from a revisions specifier data structure."""
782 784 cl = repo.changelog
783 785 clhasnode = cl.hasnode
784 786
785 787 seen = set()
786 788 nodes = []
787 789
788 790 if not isinstance(revisions, list):
789 791 raise error.WireprotoCommandError('revisions must be defined as an '
790 792 'array')
791 793
792 794 for spec in revisions:
793 795 if b'type' not in spec:
794 796 raise error.WireprotoCommandError(
795 797 'type key not present in revision specifier')
796 798
797 799 typ = spec[b'type']
798 800
799 801 if typ == b'changesetexplicit':
800 802 if b'nodes' not in spec:
801 803 raise error.WireprotoCommandError(
802 804 'nodes key not present in changesetexplicit revision '
803 805 'specifier')
804 806
805 807 for node in spec[b'nodes']:
806 808 if node not in seen:
807 809 nodes.append(node)
808 810 seen.add(node)
809 811
810 812 elif typ == b'changesetexplicitdepth':
811 813 for key in (b'nodes', b'depth'):
812 814 if key not in spec:
813 815 raise error.WireprotoCommandError(
814 816 '%s key not present in changesetexplicitdepth revision '
815 817 'specifier', (key,))
816 818
817 819 for rev in repo.revs(b'ancestors(%ln, %d)', spec[b'nodes'],
818 820 spec[b'depth'] - 1):
819 821 node = cl.node(rev)
820 822
821 823 if node not in seen:
822 824 nodes.append(node)
823 825 seen.add(node)
824 826
825 827 elif typ == b'changesetdagrange':
826 828 for key in (b'roots', b'heads'):
827 829 if key not in spec:
828 830 raise error.WireprotoCommandError(
829 831 '%s key not present in changesetdagrange revision '
830 832 'specifier', (key,))
831 833
832 834 if not spec[b'heads']:
833 835 raise error.WireprotoCommandError(
834 836 'heads key in changesetdagrange cannot be empty')
835 837
836 838 if spec[b'roots']:
837 839 common = [n for n in spec[b'roots'] if clhasnode(n)]
838 840 else:
839 841 common = [nullid]
840 842
841 843 for n in discovery.outgoing(repo, common, spec[b'heads']).missing:
842 844 if n not in seen:
843 845 nodes.append(n)
844 846 seen.add(n)
845 847
846 848 else:
847 849 raise error.WireprotoCommandError(
848 850 'unknown revision specifier type: %s', (typ,))
849 851
850 852 return nodes
851 853
852 854 @wireprotocommand('branchmap', permission='pull')
853 855 def branchmapv2(repo, proto):
854 856 yield {encoding.fromlocal(k): v
855 857 for k, v in repo.branchmap().iteritems()}
856 858
857 859 @wireprotocommand('capabilities', permission='pull')
858 860 def capabilitiesv2(repo, proto):
859 861 yield _capabilitiesv2(repo, proto)
860 862
861 863 @wireprotocommand(
862 864 'changesetdata',
863 865 args={
864 866 'revisions': {
865 867 'type': 'list',
866 868 'example': [{
867 869 b'type': b'changesetexplicit',
868 870 b'nodes': [b'abcdef...'],
869 871 }],
870 872 },
871 873 'fields': {
872 874 'type': 'set',
873 875 'default': set,
874 876 'example': {b'parents', b'revision'},
875 877 'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
876 878 },
877 879 },
878 880 permission='pull')
879 881 def changesetdata(repo, proto, revisions, fields):
880 882 # TODO look for unknown fields and abort when they can't be serviced.
881 883 # This could probably be validated by dispatcher using validvalues.
882 884
883 885 cl = repo.changelog
884 886 outgoing = resolvenodes(repo, revisions)
885 887 publishing = repo.publishing()
886 888
887 889 if outgoing:
888 890 repo.hook('preoutgoing', throw=True, source='serve')
889 891
890 892 yield {
891 893 b'totalitems': len(outgoing),
892 894 }
893 895
894 896 # The phases of nodes already transferred to the client may have changed
895 897 # since the client last requested data. We send phase-only records
896 898 # for these revisions, if requested.
897 899 # TODO actually do this. We'll probably want to emit phase heads
898 900 # in the ancestry set of the outgoing revisions. This will ensure
899 901 # that phase updates within that set are seen.
900 902 if b'phase' in fields:
901 903 pass
902 904
903 905 nodebookmarks = {}
904 906 for mark, node in repo._bookmarks.items():
905 907 nodebookmarks.setdefault(node, set()).add(mark)
906 908
907 909 # It is already topologically sorted by revision number.
908 910 for node in outgoing:
909 911 d = {
910 912 b'node': node,
911 913 }
912 914
913 915 if b'parents' in fields:
914 916 d[b'parents'] = cl.parents(node)
915 917
916 918 if b'phase' in fields:
917 919 if publishing:
918 920 d[b'phase'] = b'public'
919 921 else:
920 922 ctx = repo[node]
921 923 d[b'phase'] = ctx.phasestr()
922 924
923 925 if b'bookmarks' in fields and node in nodebookmarks:
924 926 d[b'bookmarks'] = sorted(nodebookmarks[node])
925 927 del nodebookmarks[node]
926 928
927 929 followingmeta = []
928 930 followingdata = []
929 931
930 932 if b'revision' in fields:
931 933 revisiondata = cl.revision(node, raw=True)
932 934 followingmeta.append((b'revision', len(revisiondata)))
933 935 followingdata.append(revisiondata)
934 936
935 937 # TODO make it possible for extensions to wrap a function or register
936 938 # a handler to service custom fields.
937 939
938 940 if followingmeta:
939 941 d[b'fieldsfollowing'] = followingmeta
940 942
941 943 yield d
942 944
943 945 for extra in followingdata:
944 946 yield extra
945 947
946 948 # If requested, send bookmarks from nodes that didn't have revision
947 949 # data sent so receiver is aware of any bookmark updates.
948 950 if b'bookmarks' in fields:
949 951 for node, marks in sorted(nodebookmarks.iteritems()):
950 952 yield {
951 953 b'node': node,
952 954 b'bookmarks': sorted(marks),
953 955 }
954 956
955 957 class FileAccessError(Exception):
956 958 """Represents an error accessing a specific file."""
957 959
958 960 def __init__(self, path, msg, args):
959 961 self.path = path
960 962 self.msg = msg
961 963 self.args = args
962 964
963 965 def getfilestore(repo, proto, path):
964 966 """Obtain a file storage object for use with wire protocol.
965 967
966 968 Exists as a standalone function so extensions can monkeypatch to add
967 969 access control.
968 970 """
969 971 # This seems to work even if the file doesn't exist. So catch
970 972 # "empty" files and return an error.
971 973 fl = repo.file(path)
972 974
973 975 if not len(fl):
974 976 raise FileAccessError(path, 'unknown file: %s', (path,))
975 977
976 978 return fl
977 979
978 980 def emitfilerevisions(revisions, fields):
979 981 for revision in revisions:
980 982 d = {
981 983 b'node': revision.node,
982 984 }
983 985
984 986 if b'parents' in fields:
985 987 d[b'parents'] = [revision.p1node, revision.p2node]
986 988
987 989 followingmeta = []
988 990 followingdata = []
989 991
990 992 if b'revision' in fields:
991 993 if revision.revision is not None:
992 994 followingmeta.append((b'revision', len(revision.revision)))
993 995 followingdata.append(revision.revision)
994 996 else:
995 997 d[b'deltabasenode'] = revision.basenode
996 998 followingmeta.append((b'delta', len(revision.delta)))
997 999 followingdata.append(revision.delta)
998 1000
999 1001 if followingmeta:
1000 1002 d[b'fieldsfollowing'] = followingmeta
1001 1003
1002 1004 yield d
1003 1005
1004 1006 for extra in followingdata:
1005 1007 yield extra
1006 1008
1009 def makefilematcher(repo, pathfilter):
1010 """Construct a matcher from a path filter dict."""
1011
1012 # Validate values.
1013 if pathfilter:
1014 for key in (b'include', b'exclude'):
1015 for pattern in pathfilter.get(key, []):
1016 if not pattern.startswith((b'path:', b'rootfilesin:')):
1017 raise error.WireprotoCommandError(
1018 '%s pattern must begin with `path:` or `rootfilesin:`; '
1019 'got %s', (key, pattern))
1020
1021 if pathfilter:
1022 matcher = matchmod.match(repo.root, b'',
1023 include=pathfilter.get(b'include', []),
1024 exclude=pathfilter.get(b'exclude', []))
1025 else:
1026 matcher = matchmod.match(repo.root, b'')
1027
1028 # Requested patterns could include files not in the local store. So
1029 # filter those out.
1030 return matchmod.intersectmatchers(repo.narrowmatch(), matcher)
1031
1007 1032 @wireprotocommand(
1008 1033 'filedata',
1009 1034 args={
1010 1035 'haveparents': {
1011 1036 'type': 'bool',
1012 1037 'default': lambda: False,
1013 1038 'example': True,
1014 1039 },
1015 1040 'nodes': {
1016 1041 'type': 'list',
1017 1042 'example': [b'0123456...'],
1018 1043 },
1019 1044 'fields': {
1020 1045 'type': 'set',
1021 1046 'default': set,
1022 1047 'example': {b'parents', b'revision'},
1023 1048 'validvalues': {b'parents', b'revision'},
1024 1049 },
1025 1050 'path': {
1026 1051 'type': 'bytes',
1027 1052 'example': b'foo.txt',
1028 1053 }
1029 1054 },
1030 1055 permission='pull',
1031 1056 # TODO censoring a file revision won't invalidate the cache.
1032 1057 # Figure out a way to take censoring into account when deriving
1033 1058 # the cache key.
1034 1059 cachekeyfn=makecommandcachekeyfn('filedata', 1, allargs=True))
1035 1060 def filedata(repo, proto, haveparents, nodes, fields, path):
1061 # TODO this API allows access to file revisions that are attached to
1062 # secret changesets. filesdata does not have this problem. Maybe this
1063 # API should be deleted?
1064
1036 1065 try:
1037 1066 # Extensions may wish to access the protocol handler.
1038 1067 store = getfilestore(repo, proto, path)
1039 1068 except FileAccessError as e:
1040 1069 raise error.WireprotoCommandError(e.msg, e.args)
1041 1070
1042 1071 # Validate requested nodes.
1043 1072 for node in nodes:
1044 1073 try:
1045 1074 store.rev(node)
1046 1075 except error.LookupError:
1047 1076 raise error.WireprotoCommandError('unknown file node: %s',
1048 1077 (hex(node),))
1049 1078
1050 1079 revisions = store.emitrevisions(nodes,
1051 1080 revisiondata=b'revision' in fields,
1052 1081 assumehaveparentrevisions=haveparents)
1053 1082
1054 1083 yield {
1055 1084 b'totalitems': len(nodes),
1056 1085 }
1057 1086
1058 1087 for o in emitfilerevisions(revisions, fields):
1059 1088 yield o
1060 1089
1090 def filesdatacapabilities(repo, proto):
1091 batchsize = repo.ui.configint(
1092 b'experimental', b'server.filesdata.recommended-batch-size')
1093 return {
1094 b'recommendedbatchsize': batchsize,
1095 }
1096
1097 @wireprotocommand(
1098 'filesdata',
1099 args={
1100 'haveparents': {
1101 'type': 'bool',
1102 'default': lambda: False,
1103 'example': True,
1104 },
1105 'fields': {
1106 'type': 'set',
1107 'default': set,
1108 'example': {b'parents', b'revision'},
1109 'validvalues': {b'firstchangeset', b'parents', b'revision'},
1110 },
1111 'pathfilter': {
1112 'type': 'dict',
1113 'default': lambda: None,
1114 'example': {b'include': [b'path:tests']},
1115 },
1116 'revisions': {
1117 'type': 'list',
1118 'example': [{
1119 b'type': b'changesetexplicit',
1120 b'nodes': [b'abcdef...'],
1121 }],
1122 },
1123 },
1124 permission='pull',
1125 # TODO censoring a file revision won't invalidate the cache.
1126 # Figure out a way to take censoring into account when deriving
1127 # the cache key.
1128 cachekeyfn=makecommandcachekeyfn('filesdata', 1, allargs=True),
1129 extracapabilitiesfn=filesdatacapabilities)
1130 def filesdata(repo, proto, haveparents, fields, pathfilter, revisions):
1131 # TODO This should operate on a repo that exposes obsolete changesets. There
1132 # is a race between a client making a push that obsoletes a changeset and
1133 # another client fetching files data for that changeset. If a client has a
1134 # changeset, it should probably be allowed to access files data for that
1135 # changeset.
1136
1137 cl = repo.changelog
1138 outgoing = resolvenodes(repo, revisions)
1139 filematcher = makefilematcher(repo, pathfilter)
1140
1141 # Figure out what needs to be emitted.
1142 changedpaths = set()
1143 fnodes = collections.defaultdict(set)
1144
1145 for node in outgoing:
1146 ctx = repo[node]
1147 changedpaths.update(ctx.files())
1148
1149 changedpaths = sorted(p for p in changedpaths if filematcher(p))
1150
1151 # If ancestors are known, we send file revisions having a linkrev in the
1152 # outgoing set of changeset revisions.
1153 if haveparents:
1154 outgoingclrevs = set(cl.rev(n) for n in outgoing)
1155
1156 for path in changedpaths:
1157 try:
1158 store = getfilestore(repo, proto, path)
1159 except FileAccessError as e:
1160 raise error.WireprotoCommandError(e.msg, e.args)
1161
1162 for rev in store:
1163 linkrev = store.linkrev(rev)
1164
1165 if linkrev in outgoingclrevs:
1166 fnodes[path].add(store.node(rev))
1167
1168 # If ancestors aren't known, we walk the manifests and send all
1169 # encountered file revisions.
1170 else:
1171 for node in outgoing:
1172 mctx = repo[node].manifestctx()
1173
1174 for path, fnode in mctx.read().items():
1175 if filematcher(path):
1176 fnodes[path].add(fnode)
1177
1178 yield {
1179 b'totalpaths': len(fnodes),
1180 b'totalitems': sum(len(v) for v in fnodes.values())
1181 }
1182
1183 for path, filenodes in sorted(fnodes.items()):
1184 try:
1185 store = getfilestore(repo, proto, path)
1186 except FileAccessError as e:
1187 raise error.WireprotoCommandError(e.msg, e.args)
1188
1189 yield {
1190 b'path': path,
1191 b'totalitems': len(filenodes),
1192 }
1193
1194 revisions = store.emitrevisions(filenodes,
1195 revisiondata=b'revision' in fields,
1196 assumehaveparentrevisions=haveparents)
1197
1198 for o in emitfilerevisions(revisions, fields):
1199 yield o
1200
1061 1201 @wireprotocommand(
1062 1202 'heads',
1063 1203 args={
1064 1204 'publiconly': {
1065 1205 'type': 'bool',
1066 1206 'default': lambda: False,
1067 1207 'example': False,
1068 1208 },
1069 1209 },
1070 1210 permission='pull')
1071 1211 def headsv2(repo, proto, publiconly):
1072 1212 if publiconly:
1073 1213 repo = repo.filtered('immutable')
1074 1214
1075 1215 yield repo.heads()
1076 1216
1077 1217 @wireprotocommand(
1078 1218 'known',
1079 1219 args={
1080 1220 'nodes': {
1081 1221 'type': 'list',
1082 1222 'default': list,
1083 1223 'example': [b'deadbeef'],
1084 1224 },
1085 1225 },
1086 1226 permission='pull')
1087 1227 def knownv2(repo, proto, nodes):
1088 1228 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
1089 1229 yield result
1090 1230
1091 1231 @wireprotocommand(
1092 1232 'listkeys',
1093 1233 args={
1094 1234 'namespace': {
1095 1235 'type': 'bytes',
1096 1236 'example': b'ns',
1097 1237 },
1098 1238 },
1099 1239 permission='pull')
1100 1240 def listkeysv2(repo, proto, namespace):
1101 1241 keys = repo.listkeys(encoding.tolocal(namespace))
1102 1242 keys = {encoding.fromlocal(k): encoding.fromlocal(v)
1103 1243 for k, v in keys.iteritems()}
1104 1244
1105 1245 yield keys
1106 1246
1107 1247 @wireprotocommand(
1108 1248 'lookup',
1109 1249 args={
1110 1250 'key': {
1111 1251 'type': 'bytes',
1112 1252 'example': b'foo',
1113 1253 },
1114 1254 },
1115 1255 permission='pull')
1116 1256 def lookupv2(repo, proto, key):
1117 1257 key = encoding.tolocal(key)
1118 1258
1119 1259 # TODO handle exception.
1120 1260 node = repo.lookup(key)
1121 1261
1122 1262 yield node
1123 1263
1124 1264 def manifestdatacapabilities(repo, proto):
1125 1265 batchsize = repo.ui.configint(
1126 1266 b'experimental', b'server.manifestdata.recommended-batch-size')
1127 1267
1128 1268 return {
1129 1269 b'recommendedbatchsize': batchsize,
1130 1270 }
1131 1271
1132 1272 @wireprotocommand(
1133 1273 'manifestdata',
1134 1274 args={
1135 1275 'nodes': {
1136 1276 'type': 'list',
1137 1277 'example': [b'0123456...'],
1138 1278 },
1139 1279 'haveparents': {
1140 1280 'type': 'bool',
1141 1281 'default': lambda: False,
1142 1282 'example': True,
1143 1283 },
1144 1284 'fields': {
1145 1285 'type': 'set',
1146 1286 'default': set,
1147 1287 'example': {b'parents', b'revision'},
1148 1288 'validvalues': {b'parents', b'revision'},
1149 1289 },
1150 1290 'tree': {
1151 1291 'type': 'bytes',
1152 1292 'example': b'',
1153 1293 },
1154 1294 },
1155 1295 permission='pull',
1156 1296 cachekeyfn=makecommandcachekeyfn('manifestdata', 1, allargs=True),
1157 1297 extracapabilitiesfn=manifestdatacapabilities)
1158 1298 def manifestdata(repo, proto, haveparents, nodes, fields, tree):
1159 1299 store = repo.manifestlog.getstorage(tree)
1160 1300
1161 1301 # Validate the node is known and abort on unknown revisions.
1162 1302 for node in nodes:
1163 1303 try:
1164 1304 store.rev(node)
1165 1305 except error.LookupError:
1166 1306 raise error.WireprotoCommandError(
1167 1307 'unknown node: %s', (node,))
1168 1308
1169 1309 revisions = store.emitrevisions(nodes,
1170 1310 revisiondata=b'revision' in fields,
1171 1311 assumehaveparentrevisions=haveparents)
1172 1312
1173 1313 yield {
1174 1314 b'totalitems': len(nodes),
1175 1315 }
1176 1316
1177 1317 for revision in revisions:
1178 1318 d = {
1179 1319 b'node': revision.node,
1180 1320 }
1181 1321
1182 1322 if b'parents' in fields:
1183 1323 d[b'parents'] = [revision.p1node, revision.p2node]
1184 1324
1185 1325 followingmeta = []
1186 1326 followingdata = []
1187 1327
1188 1328 if b'revision' in fields:
1189 1329 if revision.revision is not None:
1190 1330 followingmeta.append((b'revision', len(revision.revision)))
1191 1331 followingdata.append(revision.revision)
1192 1332 else:
1193 1333 d[b'deltabasenode'] = revision.basenode
1194 1334 followingmeta.append((b'delta', len(revision.delta)))
1195 1335 followingdata.append(revision.delta)
1196 1336
1197 1337 if followingmeta:
1198 1338 d[b'fieldsfollowing'] = followingmeta
1199 1339
1200 1340 yield d
1201 1341
1202 1342 for extra in followingdata:
1203 1343 yield extra
1204 1344
1205 1345 @wireprotocommand(
1206 1346 'pushkey',
1207 1347 args={
1208 1348 'namespace': {
1209 1349 'type': 'bytes',
1210 1350 'example': b'ns',
1211 1351 },
1212 1352 'key': {
1213 1353 'type': 'bytes',
1214 1354 'example': b'key',
1215 1355 },
1216 1356 'old': {
1217 1357 'type': 'bytes',
1218 1358 'example': b'old',
1219 1359 },
1220 1360 'new': {
1221 1361 'type': 'bytes',
1222 1362 'example': 'new',
1223 1363 },
1224 1364 },
1225 1365 permission='push')
1226 1366 def pushkeyv2(repo, proto, namespace, key, old, new):
1227 1367 # TODO handle ui output redirection
1228 1368 yield repo.pushkey(encoding.tolocal(namespace),
1229 1369 encoding.tolocal(key),
1230 1370 encoding.tolocal(old),
1231 1371 encoding.tolocal(new))
@@ -1,759 +1,759 b''
1 1 #require no-chg
2 2
3 3 $ . $TESTDIR/wireprotohelpers.sh
4 4
5 5 $ cat >> $HGRCPATH << EOF
6 6 > [web]
7 7 > push_ssl = false
8 8 > allow_push = *
9 9 > EOF
10 10
11 11 $ hg init server
12 12 $ cd server
13 13 $ touch a
14 14 $ hg -q commit -A -m initial
15 15 $ cd ..
16 16
17 17 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
18 18 $ cat hg.pid >> $DAEMON_PIDS
19 19
20 20 compression formats are advertised in compression capability
21 21
22 22 #if zstd
23 23 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zstd,zlib$' > /dev/null
24 24 #else
25 25 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zlib$' > /dev/null
26 26 #endif
27 27
28 28 $ killdaemons.py
29 29
30 30 server.compressionengines can replace engines list wholesale
31 31
32 32 $ hg serve --config server.compressionengines=none -R server -p $HGPORT -d --pid-file hg.pid
33 33 $ cat hg.pid > $DAEMON_PIDS
34 34 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none$' > /dev/null
35 35
36 36 $ killdaemons.py
37 37
38 38 Order of engines can also change
39 39
40 40 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
41 41 $ cat hg.pid > $DAEMON_PIDS
42 42 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none,zlib$' > /dev/null
43 43
44 44 $ killdaemons.py
45 45
46 46 Start a default server again
47 47
48 48 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
49 49 $ cat hg.pid > $DAEMON_PIDS
50 50
51 51 Server should send application/mercurial-0.1 to clients if no Accept is used
52 52
53 53 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
54 54 200 Script output follows
55 55 content-type: application/mercurial-0.1
56 56 date: $HTTP_DATE$
57 57 server: testing stub value
58 58 transfer-encoding: chunked
59 59
60 60 Server should send application/mercurial-0.1 when client says it wants it
61 61
62 62 $ get-with-headers.py --hgproto '0.1' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
63 63 200 Script output follows
64 64 content-type: application/mercurial-0.1
65 65 date: $HTTP_DATE$
66 66 server: testing stub value
67 67 transfer-encoding: chunked
68 68
69 69 Server should send application/mercurial-0.2 when client says it wants it
70 70
71 71 $ get-with-headers.py --hgproto '0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
72 72 200 Script output follows
73 73 content-type: application/mercurial-0.2
74 74 date: $HTTP_DATE$
75 75 server: testing stub value
76 76 transfer-encoding: chunked
77 77
78 78 $ get-with-headers.py --hgproto '0.1 0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
79 79 200 Script output follows
80 80 content-type: application/mercurial-0.2
81 81 date: $HTTP_DATE$
82 82 server: testing stub value
83 83 transfer-encoding: chunked
84 84
85 85 Requesting a compression format that server doesn't support results will fall back to 0.1
86 86
87 87 $ get-with-headers.py --hgproto '0.2 comp=aa' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
88 88 200 Script output follows
89 89 content-type: application/mercurial-0.1
90 90 date: $HTTP_DATE$
91 91 server: testing stub value
92 92 transfer-encoding: chunked
93 93
94 94 #if zstd
95 95 zstd is used if available
96 96
97 97 $ get-with-headers.py --hgproto '0.2 comp=zstd' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
98 98 $ f --size --hexdump --bytes 36 --sha1 resp
99 99 resp: size=248, sha1=4d8d8f87fb82bd542ce52881fdc94f850748
100 100 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
101 101 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 73 74 64 |t follows...zstd|
102 102 0020: 28 b5 2f fd |(./.|
103 103
104 104 #endif
105 105
106 106 application/mercurial-0.2 is not yet used on non-streaming responses
107 107
108 108 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=heads' -
109 109 200 Script output follows
110 110 content-length: 41
111 111 content-type: application/mercurial-0.1
112 112 date: $HTTP_DATE$
113 113 server: testing stub value
114 114
115 115 e93700bd72895c5addab234c56d4024b487a362f
116 116
117 117 Now test protocol preference usage
118 118
119 119 $ killdaemons.py
120 120 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
121 121 $ cat hg.pid > $DAEMON_PIDS
122 122
123 123 No Accept will send 0.1+zlib, even though "none" is preferred b/c "none" isn't supported on 0.1
124 124
125 125 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' Content-Type
126 126 200 Script output follows
127 127 content-type: application/mercurial-0.1
128 128
129 129 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
130 130 $ f --size --hexdump --bytes 28 --sha1 resp
131 131 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
132 132 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
133 133 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
134 134
135 135 Explicit 0.1 will send zlib because "none" isn't supported on 0.1
136 136
137 137 $ get-with-headers.py --hgproto '0.1' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
138 138 $ f --size --hexdump --bytes 28 --sha1 resp
139 139 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
140 140 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
141 141 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
142 142
143 143 0.2 with no compression will get "none" because that is server's preference
144 144 (spec says ZL and UN are implicitly supported)
145 145
146 146 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
147 147 $ f --size --hexdump --bytes 32 --sha1 resp
148 148 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
149 149 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
150 150 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
151 151
152 152 Client receives server preference even if local order doesn't match
153 153
154 154 $ get-with-headers.py --hgproto '0.2 comp=zlib,none' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
155 155 $ f --size --hexdump --bytes 32 --sha1 resp
156 156 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
157 157 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
158 158 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
159 159
160 160 Client receives only supported format even if not server preferred format
161 161
162 162 $ get-with-headers.py --hgproto '0.2 comp=zlib' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
163 163 $ f --size --hexdump --bytes 33 --sha1 resp
164 164 resp: size=232, sha1=a1c727f0c9693ca15742a75c30419bc36
165 165 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
166 166 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib|
167 167 0020: 78 |x|
168 168
169 169 $ killdaemons.py
170 170 $ cd ..
171 171
172 172 Test listkeys for listing namespaces
173 173
174 174 $ hg init empty
175 175 $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
176 176 $ cat hg.pid > $DAEMON_PIDS
177 177
178 178 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
179 179 > command listkeys
180 180 > namespace namespaces
181 181 > EOF
182 182 s> GET /?cmd=capabilities HTTP/1.1\r\n
183 183 s> Accept-Encoding: identity\r\n
184 184 s> accept: application/mercurial-0.1\r\n
185 185 s> host: $LOCALIP:$HGPORT\r\n (glob)
186 186 s> user-agent: Mercurial debugwireproto\r\n
187 187 s> \r\n
188 188 s> makefile('rb', None)
189 189 s> HTTP/1.1 200 Script output follows\r\n
190 190 s> Server: testing stub value\r\n
191 191 s> Date: $HTTP_DATE$\r\n
192 192 s> Content-Type: application/mercurial-0.1\r\n
193 193 s> Content-Length: *\r\n (glob)
194 194 s> \r\n
195 195 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
196 196 sending listkeys command
197 197 s> GET /?cmd=listkeys HTTP/1.1\r\n
198 198 s> Accept-Encoding: identity\r\n
199 199 s> vary: X-HgArg-1,X-HgProto-1\r\n
200 200 s> x-hgarg-1: namespace=namespaces\r\n
201 201 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
202 202 s> accept: application/mercurial-0.1\r\n
203 203 s> host: $LOCALIP:$HGPORT\r\n (glob)
204 204 s> user-agent: Mercurial debugwireproto\r\n
205 205 s> \r\n
206 206 s> makefile('rb', None)
207 207 s> HTTP/1.1 200 Script output follows\r\n
208 208 s> Server: testing stub value\r\n
209 209 s> Date: $HTTP_DATE$\r\n
210 210 s> Content-Type: application/mercurial-0.1\r\n
211 211 s> Content-Length: 30\r\n
212 212 s> \r\n
213 213 s> bookmarks\t\n
214 214 s> namespaces\t\n
215 215 s> phases\t
216 216 response: {
217 217 b'bookmarks': b'',
218 218 b'namespaces': b'',
219 219 b'phases': b''
220 220 }
221 221 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
222 222
223 223 Same thing, but with "httprequest" command
224 224
225 225 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
226 226 > httprequest GET ?cmd=listkeys
227 227 > user-agent: test
228 228 > x-hgarg-1: namespace=namespaces
229 229 > EOF
230 230 using raw connection to peer
231 231 s> GET /?cmd=listkeys HTTP/1.1\r\n
232 232 s> Accept-Encoding: identity\r\n
233 233 s> user-agent: test\r\n
234 234 s> x-hgarg-1: namespace=namespaces\r\n
235 235 s> host: $LOCALIP:$HGPORT\r\n (glob)
236 236 s> \r\n
237 237 s> makefile('rb', None)
238 238 s> HTTP/1.1 200 Script output follows\r\n
239 239 s> Server: testing stub value\r\n
240 240 s> Date: $HTTP_DATE$\r\n
241 241 s> Content-Type: application/mercurial-0.1\r\n
242 242 s> Content-Length: 30\r\n
243 243 s> \r\n
244 244 s> bookmarks\t\n
245 245 s> namespaces\t\n
246 246 s> phases\t
247 247
248 248 Client with HTTPv2 enabled advertises that and gets old capabilities response from old server
249 249
250 250 $ hg --config experimental.httppeer.advertise-v2=true --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
251 251 > command heads
252 252 > EOF
253 253 s> GET /?cmd=capabilities HTTP/1.1\r\n
254 254 s> Accept-Encoding: identity\r\n
255 255 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
256 256 s> x-hgproto-1: cbor\r\n
257 257 s> x-hgupgrade-1: exp-http-v2-0003\r\n
258 258 s> accept: application/mercurial-0.1\r\n
259 259 s> host: $LOCALIP:$HGPORT\r\n (glob)
260 260 s> user-agent: Mercurial debugwireproto\r\n
261 261 s> \r\n
262 262 s> makefile('rb', None)
263 263 s> HTTP/1.1 200 Script output follows\r\n
264 264 s> Server: testing stub value\r\n
265 265 s> Date: $HTTP_DATE$\r\n
266 266 s> Content-Type: application/mercurial-0.1\r\n
267 267 s> Content-Length: *\r\n (glob)
268 268 s> \r\n
269 269 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
270 270 sending heads command
271 271 s> GET /?cmd=heads HTTP/1.1\r\n
272 272 s> Accept-Encoding: identity\r\n
273 273 s> vary: X-HgProto-1\r\n
274 274 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
275 275 s> accept: application/mercurial-0.1\r\n
276 276 s> host: $LOCALIP:$HGPORT\r\n (glob)
277 277 s> user-agent: Mercurial debugwireproto\r\n
278 278 s> \r\n
279 279 s> makefile('rb', None)
280 280 s> HTTP/1.1 200 Script output follows\r\n
281 281 s> Server: testing stub value\r\n
282 282 s> Date: $HTTP_DATE$\r\n
283 283 s> Content-Type: application/mercurial-0.1\r\n
284 284 s> Content-Length: 41\r\n
285 285 s> \r\n
286 286 s> 0000000000000000000000000000000000000000\n
287 287 response: [
288 288 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
289 289 ]
290 290 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
291 291
292 292 $ killdaemons.py
293 293 $ enablehttpv2 empty
294 294 $ hg --config server.compressionengines=zlib -R empty serve -p $HGPORT -d --pid-file hg.pid
295 295 $ cat hg.pid > $DAEMON_PIDS
296 296
297 297 Client with HTTPv2 enabled automatically upgrades if the server supports it
298 298
299 299 $ hg --config experimental.httppeer.advertise-v2=true --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
300 300 > command heads
301 301 > EOF
302 302 s> GET /?cmd=capabilities HTTP/1.1\r\n
303 303 s> Accept-Encoding: identity\r\n
304 304 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
305 305 s> x-hgproto-1: cbor\r\n
306 306 s> x-hgupgrade-1: exp-http-v2-0003\r\n
307 307 s> accept: application/mercurial-0.1\r\n
308 308 s> host: $LOCALIP:$HGPORT\r\n (glob)
309 309 s> user-agent: Mercurial debugwireproto\r\n
310 310 s> \r\n
311 311 s> makefile('rb', None)
312 312 s> HTTP/1.1 200 OK\r\n
313 313 s> Server: testing stub value\r\n
314 314 s> Date: $HTTP_DATE$\r\n
315 315 s> Content-Type: application/mercurial-cbor\r\n
316 316 s> Content-Length: *\r\n (glob)
317 317 s> \r\n
318 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
318 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
319 319 sending heads command
320 320 s> POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n
321 321 s> Accept-Encoding: identity\r\n
322 322 s> accept: application/mercurial-exp-framing-0006\r\n
323 323 s> content-type: application/mercurial-exp-framing-0006\r\n
324 324 s> content-length: 56\r\n
325 325 s> host: $LOCALIP:$HGPORT\r\n (glob)
326 326 s> user-agent: Mercurial debugwireproto\r\n
327 327 s> \r\n
328 328 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads
329 329 s> makefile('rb', None)
330 330 s> HTTP/1.1 200 OK\r\n
331 331 s> Server: testing stub value\r\n
332 332 s> Date: $HTTP_DATE$\r\n
333 333 s> Content-Type: application/mercurial-exp-framing-0006\r\n
334 334 s> Transfer-Encoding: chunked\r\n
335 335 s> \r\n
336 336 s> 11\r\n
337 337 s> \t\x00\x00\x01\x00\x02\x01\x92
338 338 s> Hidentity
339 339 s> \r\n
340 340 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
341 341 s> 13\r\n
342 342 s> \x0b\x00\x00\x01\x00\x02\x041
343 343 s> \xa1FstatusBok
344 344 s> \r\n
345 345 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
346 346 s> 1e\r\n
347 347 s> \x16\x00\x00\x01\x00\x02\x041
348 348 s> \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
349 349 s> \r\n
350 350 received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
351 351 s> 8\r\n
352 352 s> \x00\x00\x00\x01\x00\x02\x002
353 353 s> \r\n
354 354 s> 0\r\n
355 355 s> \r\n
356 356 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
357 357 response: [
358 358 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
359 359 ]
360 360 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
361 361
362 362 $ killdaemons.py
363 363
364 364 HTTP client follows HTTP redirect on handshake to new repo
365 365
366 366 $ cd $TESTTMP
367 367
368 368 $ hg init redirector
369 369 $ hg init redirected
370 370 $ cd redirected
371 371 $ touch foo
372 372 $ hg -q commit -A -m initial
373 373 $ cd ..
374 374
375 375 $ cat > paths.conf << EOF
376 376 > [paths]
377 377 > / = $TESTTMP/*
378 378 > EOF
379 379
380 380 $ cat > redirectext.py << EOF
381 381 > from mercurial import extensions, wireprotoserver
382 382 > def wrappedcallhttp(orig, repo, req, res, proto, cmd):
383 383 > path = req.advertisedurl[len(req.advertisedbaseurl):]
384 384 > if not path.startswith(b'/redirector'):
385 385 > return orig(repo, req, res, proto, cmd)
386 386 > relpath = path[len(b'/redirector'):]
387 387 > res.status = b'301 Redirect'
388 388 > newurl = b'%s/redirected%s' % (req.baseurl, relpath)
389 389 > if not repo.ui.configbool('testing', 'redirectqs', True) and b'?' in newurl:
390 390 > newurl = newurl[0:newurl.index(b'?')]
391 391 > res.headers[b'Location'] = newurl
392 392 > res.headers[b'Content-Type'] = b'text/plain'
393 393 > res.setbodybytes(b'redirected')
394 394 > return True
395 395 >
396 396 > extensions.wrapfunction(wireprotoserver, '_callhttp', wrappedcallhttp)
397 397 > EOF
398 398
399 399 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
400 400 > --config server.compressionengines=zlib \
401 401 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
402 402 $ cat hg.pid > $DAEMON_PIDS
403 403
404 404 Verify our HTTP 301 is served properly
405 405
406 406 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
407 407 > httprequest GET /redirector?cmd=capabilities
408 408 > user-agent: test
409 409 > EOF
410 410 using raw connection to peer
411 411 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
412 412 s> Accept-Encoding: identity\r\n
413 413 s> user-agent: test\r\n
414 414 s> host: $LOCALIP:$HGPORT\r\n (glob)
415 415 s> \r\n
416 416 s> makefile('rb', None)
417 417 s> HTTP/1.1 301 Redirect\r\n
418 418 s> Server: testing stub value\r\n
419 419 s> Date: $HTTP_DATE$\r\n
420 420 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
421 421 s> Content-Type: text/plain\r\n
422 422 s> Content-Length: 10\r\n
423 423 s> \r\n
424 424 s> redirected
425 425 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
426 426 s> Accept-Encoding: identity\r\n
427 427 s> user-agent: test\r\n
428 428 s> host: $LOCALIP:$HGPORT\r\n (glob)
429 429 s> \r\n
430 430 s> makefile('rb', None)
431 431 s> HTTP/1.1 200 Script output follows\r\n
432 432 s> Server: testing stub value\r\n
433 433 s> Date: $HTTP_DATE$\r\n
434 434 s> Content-Type: application/mercurial-0.1\r\n
435 435 s> Content-Length: 467\r\n
436 436 s> \r\n
437 437 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
438 438
439 439 Test with the HTTP peer
440 440
441 441 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
442 442 > command heads
443 443 > EOF
444 444 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
445 445 s> Accept-Encoding: identity\r\n
446 446 s> accept: application/mercurial-0.1\r\n
447 447 s> host: $LOCALIP:$HGPORT\r\n (glob)
448 448 s> user-agent: Mercurial debugwireproto\r\n
449 449 s> \r\n
450 450 s> makefile('rb', None)
451 451 s> HTTP/1.1 301 Redirect\r\n
452 452 s> Server: testing stub value\r\n
453 453 s> Date: $HTTP_DATE$\r\n
454 454 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
455 455 s> Content-Type: text/plain\r\n
456 456 s> Content-Length: 10\r\n
457 457 s> \r\n
458 458 s> redirected
459 459 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
460 460 s> Accept-Encoding: identity\r\n
461 461 s> accept: application/mercurial-0.1\r\n
462 462 s> host: $LOCALIP:$HGPORT\r\n (glob)
463 463 s> user-agent: Mercurial debugwireproto\r\n
464 464 s> \r\n
465 465 s> makefile('rb', None)
466 466 s> HTTP/1.1 200 Script output follows\r\n
467 467 s> Server: testing stub value\r\n
468 468 s> Date: $HTTP_DATE$\r\n
469 469 s> Content-Type: application/mercurial-0.1\r\n
470 470 s> Content-Length: 467\r\n
471 471 s> \r\n
472 472 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
473 473 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
474 474 sending heads command
475 475 s> GET /redirected?cmd=heads HTTP/1.1\r\n
476 476 s> Accept-Encoding: identity\r\n
477 477 s> vary: X-HgProto-1\r\n
478 478 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
479 479 s> accept: application/mercurial-0.1\r\n
480 480 s> host: $LOCALIP:$HGPORT\r\n (glob)
481 481 s> user-agent: Mercurial debugwireproto\r\n
482 482 s> \r\n
483 483 s> makefile('rb', None)
484 484 s> HTTP/1.1 200 Script output follows\r\n
485 485 s> Server: testing stub value\r\n
486 486 s> Date: $HTTP_DATE$\r\n
487 487 s> Content-Type: application/mercurial-0.1\r\n
488 488 s> Content-Length: 41\r\n
489 489 s> \r\n
490 490 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
491 491 response: [
492 492 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
493 493 ]
494 494 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
495 495
496 496 $ killdaemons.py
497 497
498 498 Now test a variation where we strip the query string from the redirect URL.
499 499 (SCM Manager apparently did this and clients would recover from it)
500 500
501 501 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
502 502 > --config server.compressionengines=zlib \
503 503 > --config testing.redirectqs=false \
504 504 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
505 505 $ cat hg.pid > $DAEMON_PIDS
506 506
507 507 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
508 508 > httprequest GET /redirector?cmd=capabilities
509 509 > user-agent: test
510 510 > EOF
511 511 using raw connection to peer
512 512 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
513 513 s> Accept-Encoding: identity\r\n
514 514 s> user-agent: test\r\n
515 515 s> host: $LOCALIP:$HGPORT\r\n (glob)
516 516 s> \r\n
517 517 s> makefile('rb', None)
518 518 s> HTTP/1.1 301 Redirect\r\n
519 519 s> Server: testing stub value\r\n
520 520 s> Date: $HTTP_DATE$\r\n
521 521 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
522 522 s> Content-Type: text/plain\r\n
523 523 s> Content-Length: 10\r\n
524 524 s> \r\n
525 525 s> redirected
526 526 s> GET /redirected HTTP/1.1\r\n
527 527 s> Accept-Encoding: identity\r\n
528 528 s> user-agent: test\r\n
529 529 s> host: $LOCALIP:$HGPORT\r\n (glob)
530 530 s> \r\n
531 531 s> makefile('rb', None)
532 532 s> HTTP/1.1 200 Script output follows\r\n
533 533 s> Server: testing stub value\r\n
534 534 s> Date: $HTTP_DATE$\r\n
535 535 s> ETag: W/"*"\r\n (glob)
536 536 s> Content-Type: text/html; charset=ascii\r\n
537 537 s> Transfer-Encoding: chunked\r\n
538 538 s> \r\n
539 539 s> 414\r\n
540 540 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
541 541 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
542 542 s> <head>\n
543 543 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
544 544 s> <meta name="robots" content="index, nofollow" />\n
545 545 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
546 546 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
547 547 s> \n
548 548 s> <title>redirected: log</title>\n
549 549 s> <link rel="alternate" type="application/atom+xml"\n
550 550 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
551 551 s> <link rel="alternate" type="application/rss+xml"\n
552 552 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
553 553 s> </head>\n
554 554 s> <body>\n
555 555 s> \n
556 556 s> <div class="container">\n
557 557 s> <div class="menu">\n
558 558 s> <div class="logo">\n
559 559 s> <a href="https://mercurial-scm.org/">\n
560 560 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
561 561 s> </div>\n
562 562 s> <ul>\n
563 563 s> <li class="active">log</li>\n
564 564 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
565 565 s> <li><a href="/redirected/tags">tags</a></li>\n
566 566 s> <li><a href="
567 567 s> \r\n
568 568 s> 810\r\n
569 569 s> /redirected/bookmarks">bookmarks</a></li>\n
570 570 s> <li><a href="/redirected/branches">branches</a></li>\n
571 571 s> </ul>\n
572 572 s> <ul>\n
573 573 s> <li><a href="/redirected/rev/tip">changeset</a></li>\n
574 574 s> <li><a href="/redirected/file/tip">browse</a></li>\n
575 575 s> </ul>\n
576 576 s> <ul>\n
577 577 s> \n
578 578 s> </ul>\n
579 579 s> <ul>\n
580 580 s> <li><a href="/redirected/help">help</a></li>\n
581 581 s> </ul>\n
582 582 s> <div class="atom-logo">\n
583 583 s> <a href="/redirected/atom-log" title="subscribe to atom feed">\n
584 584 s> <img class="atom-logo" src="/redirected/static/feed-icon-14x14.png" alt="atom feed" />\n
585 585 s> </a>\n
586 586 s> </div>\n
587 587 s> </div>\n
588 588 s> \n
589 589 s> <div class="main">\n
590 590 s> <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/redirected">redirected</a> </h2>\n
591 591 s> <h3>log</h3>\n
592 592 s> \n
593 593 s> \n
594 594 s> <form class="search" action="/redirected/log">\n
595 595 s> \n
596 596 s> <p><input name="rev" id="search1" type="text" size="30" value="" /></p>\n
597 597 s> <div id="hint">Find changesets by keywords (author, files, the commit message), revision\n
598 598 s> number or hash, or <a href="/redirected/help/revsets">revset expression</a>.</div>\n
599 599 s> </form>\n
600 600 s> \n
601 601 s> <div class="navigate">\n
602 602 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
603 603 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
604 604 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
605 605 s> </div>\n
606 606 s> \n
607 607 s> <table class="bigtable">\n
608 608 s> <thead>\n
609 609 s> <tr>\n
610 610 s> <th class="age">age</th>\n
611 611 s> <th class="author">author</th>\n
612 612 s> <th class="description">description</th>\n
613 613 s> </tr>\n
614 614 s> </thead>\n
615 615 s> <tbody class="stripes2">\n
616 616 s> <tr>\n
617 617 s> <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>\n
618 618 s> <td class="author">test</td>\n
619 619 s> <td class="description">\n
620 620 s> <a href="/redirected/rev/96ee1d7354c4">initial</a>\n
621 621 s> <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span> \n
622 622 s> </td>\n
623 623 s> </tr>\n
624 624 s> \n
625 625 s> </tbody>\n
626 626 s> </table>\n
627 627 s> \n
628 628 s> <div class="navigate">\n
629 629 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
630 630 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
631 631 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
632 632 s> </div>\n
633 633 s> \n
634 634 s> <script type="text/javascript">\n
635 635 s> ajaxScrollInit(\n
636 636 s> \'/redirected/shortlog/%next%\',\n
637 637 s> \'\', <!-- NEXTHASH\n
638 638 s> function (htmlText) {
639 639 s> \r\n
640 640 s> 14a\r\n
641 641 s> \n
642 642 s> var m = htmlText.match(/\'(\\w+)\', <!-- NEXTHASH/);\n
643 643 s> return m ? m[1] : null;\n
644 644 s> },\n
645 645 s> \'.bigtable > tbody\',\n
646 646 s> \'<tr class="%class%">\\\n
647 647 s> <td colspan="3" style="text-align: center;">%text%</td>\\\n
648 648 s> </tr>\'\n
649 649 s> );\n
650 650 s> </script>\n
651 651 s> \n
652 652 s> </div>\n
653 653 s> </div>\n
654 654 s> \n
655 655 s> \n
656 656 s> \n
657 657 s> </body>\n
658 658 s> </html>\n
659 659 s> \n
660 660 s> \r\n
661 661 s> 0\r\n
662 662 s> \r\n
663 663
664 664 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
665 665 > command heads
666 666 > EOF
667 667 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
668 668 s> Accept-Encoding: identity\r\n
669 669 s> accept: application/mercurial-0.1\r\n
670 670 s> host: $LOCALIP:$HGPORT\r\n (glob)
671 671 s> user-agent: Mercurial debugwireproto\r\n
672 672 s> \r\n
673 673 s> makefile('rb', None)
674 674 s> HTTP/1.1 301 Redirect\r\n
675 675 s> Server: testing stub value\r\n
676 676 s> Date: $HTTP_DATE$\r\n
677 677 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
678 678 s> Content-Type: text/plain\r\n
679 679 s> Content-Length: 10\r\n
680 680 s> \r\n
681 681 s> redirected
682 682 s> GET /redirected HTTP/1.1\r\n
683 683 s> Accept-Encoding: identity\r\n
684 684 s> accept: application/mercurial-0.1\r\n
685 685 s> host: $LOCALIP:$HGPORT\r\n (glob)
686 686 s> user-agent: Mercurial debugwireproto\r\n
687 687 s> \r\n
688 688 s> makefile('rb', None)
689 689 s> HTTP/1.1 200 Script output follows\r\n
690 690 s> Server: testing stub value\r\n
691 691 s> Date: $HTTP_DATE$\r\n
692 692 s> ETag: W/"*"\r\n (glob)
693 693 s> Content-Type: text/html; charset=ascii\r\n
694 694 s> Transfer-Encoding: chunked\r\n
695 695 s> \r\n
696 696 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
697 697 s> 414\r\n
698 698 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
699 699 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
700 700 s> <head>\n
701 701 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
702 702 s> <meta name="robots" content="index, nofollow" />\n
703 703 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
704 704 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
705 705 s> \n
706 706 s> <title>redirected: log</title>\n
707 707 s> <link rel="alternate" type="application/atom+xml"\n
708 708 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
709 709 s> <link rel="alternate" type="application/rss+xml"\n
710 710 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
711 711 s> </head>\n
712 712 s> <body>\n
713 713 s> \n
714 714 s> <div class="container">\n
715 715 s> <div class="menu">\n
716 716 s> <div class="logo">\n
717 717 s> <a href="https://mercurial-scm.org/">\n
718 718 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
719 719 s> </div>\n
720 720 s> <ul>\n
721 721 s> <li class="active">log</li>\n
722 722 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
723 723 s> <li><a href="/redirected/tags">tags</a
724 724 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
725 725 s> Accept-Encoding: identity\r\n
726 726 s> accept: application/mercurial-0.1\r\n
727 727 s> host: $LOCALIP:$HGPORT\r\n (glob)
728 728 s> user-agent: Mercurial debugwireproto\r\n
729 729 s> \r\n
730 730 s> makefile('rb', None)
731 731 s> HTTP/1.1 200 Script output follows\r\n
732 732 s> Server: testing stub value\r\n
733 733 s> Date: $HTTP_DATE$\r\n
734 734 s> Content-Type: application/mercurial-0.1\r\n
735 735 s> Content-Length: 467\r\n
736 736 s> \r\n
737 737 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
738 738 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
739 739 sending heads command
740 740 s> GET /redirected?cmd=heads HTTP/1.1\r\n
741 741 s> Accept-Encoding: identity\r\n
742 742 s> vary: X-HgProto-1\r\n
743 743 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
744 744 s> accept: application/mercurial-0.1\r\n
745 745 s> host: $LOCALIP:$HGPORT\r\n (glob)
746 746 s> user-agent: Mercurial debugwireproto\r\n
747 747 s> \r\n
748 748 s> makefile('rb', None)
749 749 s> HTTP/1.1 200 Script output follows\r\n
750 750 s> Server: testing stub value\r\n
751 751 s> Date: $HTTP_DATE$\r\n
752 752 s> Content-Type: application/mercurial-0.1\r\n
753 753 s> Content-Length: 41\r\n
754 754 s> \r\n
755 755 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
756 756 response: [
757 757 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
758 758 ]
759 759 (sent 4 HTTP requests and * bytes; received * bytes in responses) (glob)
@@ -1,412 +1,444 b''
1 1 $ . $TESTDIR/wireprotohelpers.sh
2 2 $ cat >> $HGRCPATH << EOF
3 3 > [extensions]
4 4 > blackbox =
5 5 > [blackbox]
6 6 > track = simplecache
7 7 > EOF
8 8 $ hg init server
9 9 $ enablehttpv2 server
10 10 $ cd server
11 11 $ cat >> .hg/hgrc << EOF
12 12 > [extensions]
13 13 > simplecache = $TESTDIR/wireprotosimplecache.py
14 14 > EOF
15 15
16 16 $ echo a0 > a
17 17 $ echo b0 > b
18 18 $ hg -q commit -A -m 'commit 0'
19 19 $ echo a1 > a
20 20 $ hg commit -m 'commit 1'
21 21 $ echo b1 > b
22 22 $ hg commit -m 'commit 2'
23 23 $ echo a2 > a
24 24 $ echo b2 > b
25 25 $ hg commit -m 'commit 3'
26 26
27 27 $ hg log -G -T '{rev}:{node} {desc}'
28 28 @ 3:50590a86f3ff5d1e9a1624a7a6957884565cc8e8 commit 3
29 29 |
30 30 o 2:4d01eda50c6ac5f7e89cbe1880143a32f559c302 commit 2
31 31 |
32 32 o 1:4432d83626e8a98655f062ec1f2a43b07f7fbbb0 commit 1
33 33 |
34 34 o 0:3390ef850073fbc2f0dfff2244342c8e9229013a commit 0
35 35
36 36
37 37 $ hg --debug debugindex -m
38 38 rev linkrev nodeid p1 p2
39 39 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
40 40 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
41 41 2 2 a8853dafacfca6fc807055a660d8b835141a3bb4 a988fb43583e871d1ed5750ee074c6d840bbbfc8 0000000000000000000000000000000000000000
42 42 3 3 3fe11dfbb13645782b0addafbe75a87c210ffddc a8853dafacfca6fc807055a660d8b835141a3bb4 0000000000000000000000000000000000000000
43 43
44 44 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
45 45 $ cat hg.pid > $DAEMON_PIDS
46 46
47 47 Performing the same request should result in same result, with 2nd response
48 48 coming from cache.
49 49
50 50 $ sendhttpv2peer << EOF
51 51 > command manifestdata
52 52 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
53 53 > tree eval:b''
54 54 > fields eval:[b'parents']
55 55 > EOF
56 56 creating http peer for wire protocol version 2
57 57 sending manifestdata command
58 58 response: gen[
59 59 {
60 60 b'totalitems': 1
61 61 },
62 62 {
63 63 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
64 64 b'parents': [
65 65 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
66 66 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
67 67 ]
68 68 }
69 69 ]
70 70
71 71 $ sendhttpv2peer << EOF
72 72 > command manifestdata
73 73 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
74 74 > tree eval:b''
75 75 > fields eval:[b'parents']
76 76 > EOF
77 77 creating http peer for wire protocol version 2
78 78 sending manifestdata command
79 79 response: gen[
80 80 {
81 81 b'totalitems': 1
82 82 },
83 83 {
84 84 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
85 85 b'parents': [
86 86 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
87 87 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
88 88 ]
89 89 }
90 90 ]
91 91
92 92 Sending different request doesn't yield cache hit.
93 93
94 94 $ sendhttpv2peer << EOF
95 95 > command manifestdata
96 96 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41', b'\xa9\x88\xfb\x43\x58\x3e\x87\x1d\x1e\xd5\x75\x0e\xe0\x74\xc6\xd8\x40\xbb\xbf\xc8']
97 97 > tree eval:b''
98 98 > fields eval:[b'parents']
99 99 > EOF
100 100 creating http peer for wire protocol version 2
101 101 sending manifestdata command
102 102 response: gen[
103 103 {
104 104 b'totalitems': 2
105 105 },
106 106 {
107 107 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
108 108 b'parents': [
109 109 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
110 110 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
111 111 ]
112 112 },
113 113 {
114 114 b'node': b'\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8',
115 115 b'parents': [
116 116 b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
117 117 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
118 118 ]
119 119 }
120 120 ]
121 121
122 122 $ cat .hg/blackbox.log
123 123 *> cacher constructed for manifestdata (glob)
124 124 *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
125 125 *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
126 126 *> cacher constructed for manifestdata (glob)
127 127 *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
128 128 *> cacher constructed for manifestdata (glob)
129 129 *> cache miss for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob)
130 130 *> storing cache entry for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob)
131 131
132 132 $ cat error.log
133 133
134 134 $ killdaemons.py
135 135 $ rm .hg/blackbox.log
136 136
137 137 Try with object caching mode
138 138
139 139 $ cat >> .hg/hgrc << EOF
140 140 > [simplecache]
141 141 > cacheobjects = true
142 142 > EOF
143 143
144 144 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
145 145 $ cat hg.pid > $DAEMON_PIDS
146 146
147 147 $ sendhttpv2peer << EOF
148 148 > command manifestdata
149 149 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
150 150 > tree eval:b''
151 151 > fields eval:[b'parents']
152 152 > EOF
153 153 creating http peer for wire protocol version 2
154 154 sending manifestdata command
155 155 response: gen[
156 156 {
157 157 b'totalitems': 1
158 158 },
159 159 {
160 160 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
161 161 b'parents': [
162 162 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
163 163 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
164 164 ]
165 165 }
166 166 ]
167 167
168 168 $ sendhttpv2peer << EOF
169 169 > command manifestdata
170 170 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
171 171 > tree eval:b''
172 172 > fields eval:[b'parents']
173 173 > EOF
174 174 creating http peer for wire protocol version 2
175 175 sending manifestdata command
176 176 response: gen[
177 177 {
178 178 b'totalitems': 1
179 179 },
180 180 {
181 181 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
182 182 b'parents': [
183 183 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
184 184 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
185 185 ]
186 186 }
187 187 ]
188 188
189 189 $ cat .hg/blackbox.log
190 190 *> cacher constructed for manifestdata (glob)
191 191 *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
192 192 *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
193 193 *> cacher constructed for manifestdata (glob)
194 194 *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
195 195
196 196 $ cat error.log
197 197
198 198 $ killdaemons.py
199 199 $ rm .hg/blackbox.log
200 200
201 201 A non-cacheable command does not instantiate cacher
202 202
203 203 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
204 204 $ cat hg.pid > $DAEMON_PIDS
205 205 $ sendhttpv2peer << EOF
206 206 > command capabilities
207 207 > EOF
208 208 creating http peer for wire protocol version 2
209 209 sending capabilities command
210 210 response: gen[
211 211 {
212 212 b'commands': {
213 213 b'branchmap': {
214 214 b'args': {},
215 215 b'permissions': [
216 216 b'pull'
217 217 ]
218 218 },
219 219 b'capabilities': {
220 220 b'args': {},
221 221 b'permissions': [
222 222 b'pull'
223 223 ]
224 224 },
225 225 b'changesetdata': {
226 226 b'args': {
227 227 b'fields': {
228 228 b'default': set([]),
229 229 b'required': False,
230 230 b'type': b'set',
231 231 b'validvalues': set([
232 232 b'bookmarks',
233 233 b'parents',
234 234 b'phase',
235 235 b'revision'
236 236 ])
237 237 },
238 238 b'revisions': {
239 239 b'required': True,
240 240 b'type': b'list'
241 241 }
242 242 },
243 243 b'permissions': [
244 244 b'pull'
245 245 ]
246 246 },
247 247 b'filedata': {
248 248 b'args': {
249 249 b'fields': {
250 250 b'default': set([]),
251 251 b'required': False,
252 252 b'type': b'set',
253 253 b'validvalues': set([
254 254 b'parents',
255 255 b'revision'
256 256 ])
257 257 },
258 258 b'haveparents': {
259 259 b'default': False,
260 260 b'required': False,
261 261 b'type': b'bool'
262 262 },
263 263 b'nodes': {
264 264 b'required': True,
265 265 b'type': b'list'
266 266 },
267 267 b'path': {
268 268 b'required': True,
269 269 b'type': b'bytes'
270 270 }
271 271 },
272 272 b'permissions': [
273 273 b'pull'
274 274 ]
275 275 },
276 b'filesdata': {
277 b'args': {
278 b'fields': {
279 b'default': set([]),
280 b'required': False,
281 b'type': b'set',
282 b'validvalues': set([
283 b'firstchangeset',
284 b'parents',
285 b'revision'
286 ])
287 },
288 b'haveparents': {
289 b'default': False,
290 b'required': False,
291 b'type': b'bool'
292 },
293 b'pathfilter': {
294 b'default': None,
295 b'required': False,
296 b'type': b'dict'
297 },
298 b'revisions': {
299 b'required': True,
300 b'type': b'list'
301 }
302 },
303 b'permissions': [
304 b'pull'
305 ],
306 b'recommendedbatchsize': 50000
307 },
276 308 b'heads': {
277 309 b'args': {
278 310 b'publiconly': {
279 311 b'default': False,
280 312 b'required': False,
281 313 b'type': b'bool'
282 314 }
283 315 },
284 316 b'permissions': [
285 317 b'pull'
286 318 ]
287 319 },
288 320 b'known': {
289 321 b'args': {
290 322 b'nodes': {
291 323 b'default': [],
292 324 b'required': False,
293 325 b'type': b'list'
294 326 }
295 327 },
296 328 b'permissions': [
297 329 b'pull'
298 330 ]
299 331 },
300 332 b'listkeys': {
301 333 b'args': {
302 334 b'namespace': {
303 335 b'required': True,
304 336 b'type': b'bytes'
305 337 }
306 338 },
307 339 b'permissions': [
308 340 b'pull'
309 341 ]
310 342 },
311 343 b'lookup': {
312 344 b'args': {
313 345 b'key': {
314 346 b'required': True,
315 347 b'type': b'bytes'
316 348 }
317 349 },
318 350 b'permissions': [
319 351 b'pull'
320 352 ]
321 353 },
322 354 b'manifestdata': {
323 355 b'args': {
324 356 b'fields': {
325 357 b'default': set([]),
326 358 b'required': False,
327 359 b'type': b'set',
328 360 b'validvalues': set([
329 361 b'parents',
330 362 b'revision'
331 363 ])
332 364 },
333 365 b'haveparents': {
334 366 b'default': False,
335 367 b'required': False,
336 368 b'type': b'bool'
337 369 },
338 370 b'nodes': {
339 371 b'required': True,
340 372 b'type': b'list'
341 373 },
342 374 b'tree': {
343 375 b'required': True,
344 376 b'type': b'bytes'
345 377 }
346 378 },
347 379 b'permissions': [
348 380 b'pull'
349 381 ],
350 382 b'recommendedbatchsize': 100000
351 383 },
352 384 b'pushkey': {
353 385 b'args': {
354 386 b'key': {
355 387 b'required': True,
356 388 b'type': b'bytes'
357 389 },
358 390 b'namespace': {
359 391 b'required': True,
360 392 b'type': b'bytes'
361 393 },
362 394 b'new': {
363 395 b'required': True,
364 396 b'type': b'bytes'
365 397 },
366 398 b'old': {
367 399 b'required': True,
368 400 b'type': b'bytes'
369 401 }
370 402 },
371 403 b'permissions': [
372 404 b'push'
373 405 ]
374 406 }
375 407 },
376 408 b'framingmediatypes': [
377 409 b'application/mercurial-exp-framing-0006'
378 410 ],
379 411 b'pathfilterprefixes': set([
380 412 b'path:',
381 413 b'rootfilesin:'
382 414 ]),
383 415 b'rawrepoformats': [
384 416 b'generaldelta',
385 417 b'revlogv1'
386 418 ]
387 419 }
388 420 ]
389 421
390 422 $ test -f .hg/blackbox.log
391 423 [1]
392 424
393 425 An error is not cached
394 426
395 427 $ sendhttpv2peer << EOF
396 428 > command manifestdata
397 429 > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
398 430 > tree eval:b''
399 431 > fields eval:[b'parents']
400 432 > EOF
401 433 creating http peer for wire protocol version 2
402 434 sending manifestdata command
403 435 abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa! (esc)
404 436 [255]
405 437
406 438 $ cat .hg/blackbox.log
407 439 *> cacher constructed for manifestdata (glob)
408 440 *> cache miss for 2cba2a7d0d1575fea2fe68f597e97a7c2ac2f705 (glob)
409 441 *> cacher exiting due to error (glob)
410 442
411 443 $ killdaemons.py
412 444 $ rm .hg/blackbox.log
@@ -1,648 +1,712 b''
1 1 #require no-chg
2 2
3 3 $ . $TESTDIR/wireprotohelpers.sh
4 4
5 5 $ hg init server
6 6
7 7 zstd isn't present in plain builds. Make tests easier by removing
8 8 zstd from the equation.
9 9
10 10 $ cat >> server/.hg/hgrc << EOF
11 11 > [server]
12 12 > compressionengines = zlib
13 13 > EOF
14 14
15 15 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
16 16 $ cat hg.pid > $DAEMON_PIDS
17 17
18 18 A normal capabilities request is serviced for version 1
19 19
20 20 $ sendhttpraw << EOF
21 21 > httprequest GET ?cmd=capabilities
22 22 > user-agent: test
23 23 > EOF
24 24 using raw connection to peer
25 25 s> GET /?cmd=capabilities HTTP/1.1\r\n
26 26 s> Accept-Encoding: identity\r\n
27 27 s> user-agent: test\r\n
28 28 s> host: $LOCALIP:$HGPORT\r\n (glob)
29 29 s> \r\n
30 30 s> makefile('rb', None)
31 31 s> HTTP/1.1 200 Script output follows\r\n
32 32 s> Server: testing stub value\r\n
33 33 s> Date: $HTTP_DATE$\r\n
34 34 s> Content-Type: application/mercurial-0.1\r\n
35 35 s> Content-Length: *\r\n (glob)
36 36 s> \r\n
37 37 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
38 38
39 39 A proper request without the API server enabled returns the legacy response
40 40
41 41 $ sendhttpraw << EOF
42 42 > httprequest GET ?cmd=capabilities
43 43 > user-agent: test
44 44 > x-hgupgrade-1: foo
45 45 > x-hgproto-1: cbor
46 46 > EOF
47 47 using raw connection to peer
48 48 s> GET /?cmd=capabilities HTTP/1.1\r\n
49 49 s> Accept-Encoding: identity\r\n
50 50 s> user-agent: test\r\n
51 51 s> x-hgproto-1: cbor\r\n
52 52 s> x-hgupgrade-1: foo\r\n
53 53 s> host: $LOCALIP:$HGPORT\r\n (glob)
54 54 s> \r\n
55 55 s> makefile('rb', None)
56 56 s> HTTP/1.1 200 Script output follows\r\n
57 57 s> Server: testing stub value\r\n
58 58 s> Date: $HTTP_DATE$\r\n
59 59 s> Content-Type: application/mercurial-0.1\r\n
60 60 s> Content-Length: *\r\n (glob)
61 61 s> \r\n
62 62 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
63 63
64 64 Restart with just API server enabled. This enables serving the new format.
65 65
66 66 $ killdaemons.py
67 67 $ cat error.log
68 68
69 69 $ cat >> server/.hg/hgrc << EOF
70 70 > [experimental]
71 71 > web.apiserver = true
72 72 > EOF
73 73
74 74 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
75 75 $ cat hg.pid > $DAEMON_PIDS
76 76
77 77 X-HgUpgrade-<N> without CBOR advertisement uses legacy response
78 78
79 79 $ sendhttpraw << EOF
80 80 > httprequest GET ?cmd=capabilities
81 81 > user-agent: test
82 82 > x-hgupgrade-1: foo bar
83 83 > EOF
84 84 using raw connection to peer
85 85 s> GET /?cmd=capabilities HTTP/1.1\r\n
86 86 s> Accept-Encoding: identity\r\n
87 87 s> user-agent: test\r\n
88 88 s> x-hgupgrade-1: foo bar\r\n
89 89 s> host: $LOCALIP:$HGPORT\r\n (glob)
90 90 s> \r\n
91 91 s> makefile('rb', None)
92 92 s> HTTP/1.1 200 Script output follows\r\n
93 93 s> Server: testing stub value\r\n
94 94 s> Date: $HTTP_DATE$\r\n
95 95 s> Content-Type: application/mercurial-0.1\r\n
96 96 s> Content-Length: *\r\n (glob)
97 97 s> \r\n
98 98 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
99 99
100 100 X-HgUpgrade-<N> without known serialization in X-HgProto-<N> uses legacy response
101 101
102 102 $ sendhttpraw << EOF
103 103 > httprequest GET ?cmd=capabilities
104 104 > user-agent: test
105 105 > x-hgupgrade-1: foo bar
106 106 > x-hgproto-1: some value
107 107 > EOF
108 108 using raw connection to peer
109 109 s> GET /?cmd=capabilities HTTP/1.1\r\n
110 110 s> Accept-Encoding: identity\r\n
111 111 s> user-agent: test\r\n
112 112 s> x-hgproto-1: some value\r\n
113 113 s> x-hgupgrade-1: foo bar\r\n
114 114 s> host: $LOCALIP:$HGPORT\r\n (glob)
115 115 s> \r\n
116 116 s> makefile('rb', None)
117 117 s> HTTP/1.1 200 Script output follows\r\n
118 118 s> Server: testing stub value\r\n
119 119 s> Date: $HTTP_DATE$\r\n
120 120 s> Content-Type: application/mercurial-0.1\r\n
121 121 s> Content-Length: *\r\n (glob)
122 122 s> \r\n
123 123 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
124 124
125 125 X-HgUpgrade-<N> + X-HgProto-<N> headers trigger new response format
126 126
127 127 $ sendhttpraw << EOF
128 128 > httprequest GET ?cmd=capabilities
129 129 > user-agent: test
130 130 > x-hgupgrade-1: foo bar
131 131 > x-hgproto-1: cbor
132 132 > EOF
133 133 using raw connection to peer
134 134 s> GET /?cmd=capabilities HTTP/1.1\r\n
135 135 s> Accept-Encoding: identity\r\n
136 136 s> user-agent: test\r\n
137 137 s> x-hgproto-1: cbor\r\n
138 138 s> x-hgupgrade-1: foo bar\r\n
139 139 s> host: $LOCALIP:$HGPORT\r\n (glob)
140 140 s> \r\n
141 141 s> makefile('rb', None)
142 142 s> HTTP/1.1 200 OK\r\n
143 143 s> Server: testing stub value\r\n
144 144 s> Date: $HTTP_DATE$\r\n
145 145 s> Content-Type: application/mercurial-cbor\r\n
146 146 s> Content-Length: *\r\n (glob)
147 147 s> \r\n
148 148 s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
149 149 cbor> [
150 150 {
151 151 b'apibase': b'api/',
152 152 b'apis': {},
153 153 b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
154 154 }
155 155 ]
156 156
157 157 Restart server to enable HTTPv2
158 158
159 159 $ killdaemons.py
160 160 $ enablehttpv2 server
161 161 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
162 162 $ cat hg.pid > $DAEMON_PIDS
163 163
164 164 Only requested API services are returned
165 165
166 166 $ sendhttpraw << EOF
167 167 > httprequest GET ?cmd=capabilities
168 168 > user-agent: test
169 169 > x-hgupgrade-1: foo bar
170 170 > x-hgproto-1: cbor
171 171 > EOF
172 172 using raw connection to peer
173 173 s> GET /?cmd=capabilities HTTP/1.1\r\n
174 174 s> Accept-Encoding: identity\r\n
175 175 s> user-agent: test\r\n
176 176 s> x-hgproto-1: cbor\r\n
177 177 s> x-hgupgrade-1: foo bar\r\n
178 178 s> host: $LOCALIP:$HGPORT\r\n (glob)
179 179 s> \r\n
180 180 s> makefile('rb', None)
181 181 s> HTTP/1.1 200 OK\r\n
182 182 s> Server: testing stub value\r\n
183 183 s> Date: $HTTP_DATE$\r\n
184 184 s> Content-Type: application/mercurial-cbor\r\n
185 185 s> Content-Length: *\r\n (glob)
186 186 s> \r\n
187 187 s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
188 188 cbor> [
189 189 {
190 190 b'apibase': b'api/',
191 191 b'apis': {},
192 192 b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
193 193 }
194 194 ]
195 195
196 196 Request for HTTPv2 service returns information about it
197 197
198 198 $ sendhttpraw << EOF
199 199 > httprequest GET ?cmd=capabilities
200 200 > user-agent: test
201 201 > x-hgupgrade-1: exp-http-v2-0003 foo bar
202 202 > x-hgproto-1: cbor
203 203 > EOF
204 204 using raw connection to peer
205 205 s> GET /?cmd=capabilities HTTP/1.1\r\n
206 206 s> Accept-Encoding: identity\r\n
207 207 s> user-agent: test\r\n
208 208 s> x-hgproto-1: cbor\r\n
209 209 s> x-hgupgrade-1: exp-http-v2-0003 foo bar\r\n
210 210 s> host: $LOCALIP:$HGPORT\r\n (glob)
211 211 s> \r\n
212 212 s> makefile('rb', None)
213 213 s> HTTP/1.1 200 OK\r\n
214 214 s> Server: testing stub value\r\n
215 215 s> Date: $HTTP_DATE$\r\n
216 216 s> Content-Type: application/mercurial-cbor\r\n
217 217 s> Content-Length: *\r\n (glob)
218 218 s> \r\n
219 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
219 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
220 220 cbor> [
221 221 {
222 222 b'apibase': b'api/',
223 223 b'apis': {
224 224 b'exp-http-v2-0003': {
225 225 b'commands': {
226 226 b'branchmap': {
227 227 b'args': {},
228 228 b'permissions': [
229 229 b'pull'
230 230 ]
231 231 },
232 232 b'capabilities': {
233 233 b'args': {},
234 234 b'permissions': [
235 235 b'pull'
236 236 ]
237 237 },
238 238 b'changesetdata': {
239 239 b'args': {
240 240 b'fields': {
241 241 b'default': set([]),
242 242 b'required': False,
243 243 b'type': b'set',
244 244 b'validvalues': set([
245 245 b'bookmarks',
246 246 b'parents',
247 247 b'phase',
248 248 b'revision'
249 249 ])
250 250 },
251 251 b'revisions': {
252 252 b'required': True,
253 253 b'type': b'list'
254 254 }
255 255 },
256 256 b'permissions': [
257 257 b'pull'
258 258 ]
259 259 },
260 260 b'filedata': {
261 261 b'args': {
262 262 b'fields': {
263 263 b'default': set([]),
264 264 b'required': False,
265 265 b'type': b'set',
266 266 b'validvalues': set([
267 267 b'parents',
268 268 b'revision'
269 269 ])
270 270 },
271 271 b'haveparents': {
272 272 b'default': False,
273 273 b'required': False,
274 274 b'type': b'bool'
275 275 },
276 276 b'nodes': {
277 277 b'required': True,
278 278 b'type': b'list'
279 279 },
280 280 b'path': {
281 281 b'required': True,
282 282 b'type': b'bytes'
283 283 }
284 284 },
285 285 b'permissions': [
286 286 b'pull'
287 287 ]
288 288 },
289 b'filesdata': {
290 b'args': {
291 b'fields': {
292 b'default': set([]),
293 b'required': False,
294 b'type': b'set',
295 b'validvalues': set([
296 b'firstchangeset',
297 b'parents',
298 b'revision'
299 ])
300 },
301 b'haveparents': {
302 b'default': False,
303 b'required': False,
304 b'type': b'bool'
305 },
306 b'pathfilter': {
307 b'default': None,
308 b'required': False,
309 b'type': b'dict'
310 },
311 b'revisions': {
312 b'required': True,
313 b'type': b'list'
314 }
315 },
316 b'permissions': [
317 b'pull'
318 ],
319 b'recommendedbatchsize': 50000
320 },
289 321 b'heads': {
290 322 b'args': {
291 323 b'publiconly': {
292 324 b'default': False,
293 325 b'required': False,
294 326 b'type': b'bool'
295 327 }
296 328 },
297 329 b'permissions': [
298 330 b'pull'
299 331 ]
300 332 },
301 333 b'known': {
302 334 b'args': {
303 335 b'nodes': {
304 336 b'default': [],
305 337 b'required': False,
306 338 b'type': b'list'
307 339 }
308 340 },
309 341 b'permissions': [
310 342 b'pull'
311 343 ]
312 344 },
313 345 b'listkeys': {
314 346 b'args': {
315 347 b'namespace': {
316 348 b'required': True,
317 349 b'type': b'bytes'
318 350 }
319 351 },
320 352 b'permissions': [
321 353 b'pull'
322 354 ]
323 355 },
324 356 b'lookup': {
325 357 b'args': {
326 358 b'key': {
327 359 b'required': True,
328 360 b'type': b'bytes'
329 361 }
330 362 },
331 363 b'permissions': [
332 364 b'pull'
333 365 ]
334 366 },
335 367 b'manifestdata': {
336 368 b'args': {
337 369 b'fields': {
338 370 b'default': set([]),
339 371 b'required': False,
340 372 b'type': b'set',
341 373 b'validvalues': set([
342 374 b'parents',
343 375 b'revision'
344 376 ])
345 377 },
346 378 b'haveparents': {
347 379 b'default': False,
348 380 b'required': False,
349 381 b'type': b'bool'
350 382 },
351 383 b'nodes': {
352 384 b'required': True,
353 385 b'type': b'list'
354 386 },
355 387 b'tree': {
356 388 b'required': True,
357 389 b'type': b'bytes'
358 390 }
359 391 },
360 392 b'permissions': [
361 393 b'pull'
362 394 ],
363 395 b'recommendedbatchsize': 100000
364 396 },
365 397 b'pushkey': {
366 398 b'args': {
367 399 b'key': {
368 400 b'required': True,
369 401 b'type': b'bytes'
370 402 },
371 403 b'namespace': {
372 404 b'required': True,
373 405 b'type': b'bytes'
374 406 },
375 407 b'new': {
376 408 b'required': True,
377 409 b'type': b'bytes'
378 410 },
379 411 b'old': {
380 412 b'required': True,
381 413 b'type': b'bytes'
382 414 }
383 415 },
384 416 b'permissions': [
385 417 b'push'
386 418 ]
387 419 }
388 420 },
389 421 b'framingmediatypes': [
390 422 b'application/mercurial-exp-framing-0006'
391 423 ],
392 424 b'pathfilterprefixes': set([
393 425 b'path:',
394 426 b'rootfilesin:'
395 427 ]),
396 428 b'rawrepoformats': [
397 429 b'generaldelta',
398 430 b'revlogv1'
399 431 ]
400 432 }
401 433 },
402 434 b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
403 435 }
404 436 ]
405 437
406 438 capabilities command returns expected info
407 439
408 440 $ sendhttpv2peerhandshake << EOF
409 441 > command capabilities
410 442 > EOF
411 443 creating http peer for wire protocol version 2
412 444 s> GET /?cmd=capabilities HTTP/1.1\r\n
413 445 s> Accept-Encoding: identity\r\n
414 446 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
415 447 s> x-hgproto-1: cbor\r\n
416 448 s> x-hgupgrade-1: exp-http-v2-0003\r\n
417 449 s> accept: application/mercurial-0.1\r\n
418 450 s> host: $LOCALIP:$HGPORT\r\n (glob)
419 451 s> user-agent: Mercurial debugwireproto\r\n
420 452 s> \r\n
421 453 s> makefile('rb', None)
422 454 s> HTTP/1.1 200 OK\r\n
423 455 s> Server: testing stub value\r\n
424 456 s> Date: $HTTP_DATE$\r\n
425 457 s> Content-Type: application/mercurial-cbor\r\n
426 458 s> Content-Length: *\r\n (glob)
427 459 s> \r\n
428 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
460 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
429 461 sending capabilities command
430 462 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
431 463 s> Accept-Encoding: identity\r\n
432 464 s> accept: application/mercurial-exp-framing-0006\r\n
433 465 s> content-type: application/mercurial-exp-framing-0006\r\n
434 466 s> content-length: 63\r\n
435 467 s> host: $LOCALIP:$HGPORT\r\n (glob)
436 468 s> user-agent: Mercurial debugwireproto\r\n
437 469 s> \r\n
438 470 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x13\x00\x00\x01\x00\x01\x00\x11\xa1DnameLcapabilities
439 471 s> makefile('rb', None)
440 472 s> HTTP/1.1 200 OK\r\n
441 473 s> Server: testing stub value\r\n
442 474 s> Date: $HTTP_DATE$\r\n
443 475 s> Content-Type: application/mercurial-exp-framing-0006\r\n
444 476 s> Transfer-Encoding: chunked\r\n
445 477 s> \r\n
446 478 s> 11\r\n
447 479 s> \t\x00\x00\x01\x00\x02\x01\x92
448 480 s> Hidentity
449 481 s> \r\n
450 482 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
451 483 s> 13\r\n
452 484 s> \x0b\x00\x00\x01\x00\x02\x041
453 485 s> \xa1FstatusBok
454 486 s> \r\n
455 487 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
456 s> 4cd\r\n
457 s> \xc5\x04\x00\x01\x00\x02\x041
458 s> \xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1
488 s> 5d1\r\n
489 s> \xc9\x05\x00\x01\x00\x02\x041
490 s> \xa4Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1
459 491 s> \r\n
460 received frame(size=1221; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
492 received frame(size=1481; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
461 493 s> 8\r\n
462 494 s> \x00\x00\x00\x01\x00\x02\x002
463 495 s> \r\n
464 496 s> 0\r\n
465 497 s> \r\n
466 498 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
467 499 response: gen[
468 500 {
469 501 b'commands': {
470 502 b'branchmap': {
471 503 b'args': {},
472 504 b'permissions': [
473 505 b'pull'
474 506 ]
475 507 },
476 508 b'capabilities': {
477 509 b'args': {},
478 510 b'permissions': [
479 511 b'pull'
480 512 ]
481 513 },
482 514 b'changesetdata': {
483 515 b'args': {
484 516 b'fields': {
485 517 b'default': set([]),
486 518 b'required': False,
487 519 b'type': b'set',
488 520 b'validvalues': set([
489 521 b'bookmarks',
490 522 b'parents',
491 523 b'phase',
492 524 b'revision'
493 525 ])
494 526 },
495 527 b'revisions': {
496 528 b'required': True,
497 529 b'type': b'list'
498 530 }
499 531 },
500 532 b'permissions': [
501 533 b'pull'
502 534 ]
503 535 },
504 536 b'filedata': {
505 537 b'args': {
506 538 b'fields': {
507 539 b'default': set([]),
508 540 b'required': False,
509 541 b'type': b'set',
510 542 b'validvalues': set([
511 543 b'parents',
512 544 b'revision'
513 545 ])
514 546 },
515 547 b'haveparents': {
516 548 b'default': False,
517 549 b'required': False,
518 550 b'type': b'bool'
519 551 },
520 552 b'nodes': {
521 553 b'required': True,
522 554 b'type': b'list'
523 555 },
524 556 b'path': {
525 557 b'required': True,
526 558 b'type': b'bytes'
527 559 }
528 560 },
529 561 b'permissions': [
530 562 b'pull'
531 563 ]
532 564 },
565 b'filesdata': {
566 b'args': {
567 b'fields': {
568 b'default': set([]),
569 b'required': False,
570 b'type': b'set',
571 b'validvalues': set([
572 b'firstchangeset',
573 b'parents',
574 b'revision'
575 ])
576 },
577 b'haveparents': {
578 b'default': False,
579 b'required': False,
580 b'type': b'bool'
581 },
582 b'pathfilter': {
583 b'default': None,
584 b'required': False,
585 b'type': b'dict'
586 },
587 b'revisions': {
588 b'required': True,
589 b'type': b'list'
590 }
591 },
592 b'permissions': [
593 b'pull'
594 ],
595 b'recommendedbatchsize': 50000
596 },
533 597 b'heads': {
534 598 b'args': {
535 599 b'publiconly': {
536 600 b'default': False,
537 601 b'required': False,
538 602 b'type': b'bool'
539 603 }
540 604 },
541 605 b'permissions': [
542 606 b'pull'
543 607 ]
544 608 },
545 609 b'known': {
546 610 b'args': {
547 611 b'nodes': {
548 612 b'default': [],
549 613 b'required': False,
550 614 b'type': b'list'
551 615 }
552 616 },
553 617 b'permissions': [
554 618 b'pull'
555 619 ]
556 620 },
557 621 b'listkeys': {
558 622 b'args': {
559 623 b'namespace': {
560 624 b'required': True,
561 625 b'type': b'bytes'
562 626 }
563 627 },
564 628 b'permissions': [
565 629 b'pull'
566 630 ]
567 631 },
568 632 b'lookup': {
569 633 b'args': {
570 634 b'key': {
571 635 b'required': True,
572 636 b'type': b'bytes'
573 637 }
574 638 },
575 639 b'permissions': [
576 640 b'pull'
577 641 ]
578 642 },
579 643 b'manifestdata': {
580 644 b'args': {
581 645 b'fields': {
582 646 b'default': set([]),
583 647 b'required': False,
584 648 b'type': b'set',
585 649 b'validvalues': set([
586 650 b'parents',
587 651 b'revision'
588 652 ])
589 653 },
590 654 b'haveparents': {
591 655 b'default': False,
592 656 b'required': False,
593 657 b'type': b'bool'
594 658 },
595 659 b'nodes': {
596 660 b'required': True,
597 661 b'type': b'list'
598 662 },
599 663 b'tree': {
600 664 b'required': True,
601 665 b'type': b'bytes'
602 666 }
603 667 },
604 668 b'permissions': [
605 669 b'pull'
606 670 ],
607 671 b'recommendedbatchsize': 100000
608 672 },
609 673 b'pushkey': {
610 674 b'args': {
611 675 b'key': {
612 676 b'required': True,
613 677 b'type': b'bytes'
614 678 },
615 679 b'namespace': {
616 680 b'required': True,
617 681 b'type': b'bytes'
618 682 },
619 683 b'new': {
620 684 b'required': True,
621 685 b'type': b'bytes'
622 686 },
623 687 b'old': {
624 688 b'required': True,
625 689 b'type': b'bytes'
626 690 }
627 691 },
628 692 b'permissions': [
629 693 b'push'
630 694 ]
631 695 }
632 696 },
633 697 b'framingmediatypes': [
634 698 b'application/mercurial-exp-framing-0006'
635 699 ],
636 700 b'pathfilterprefixes': set([
637 701 b'path:',
638 702 b'rootfilesin:'
639 703 ]),
640 704 b'rawrepoformats': [
641 705 b'generaldelta',
642 706 b'revlogv1'
643 707 ]
644 708 }
645 709 ]
646 710 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
647 711
648 712 $ cat error.log
@@ -1,1270 +1,1398 b''
1 1 $ . $TESTDIR/wireprotohelpers.sh
2 2
3 3 $ cat >> $HGRCPATH << EOF
4 4 > [extensions]
5 5 > blackbox =
6 6 > [blackbox]
7 7 > track = simplecache
8 8 > EOF
9 9
10 10 $ hg init server
11 11 $ enablehttpv2 server
12 12 $ cd server
13 13 $ cat >> .hg/hgrc << EOF
14 14 > [server]
15 15 > compressionengines = zlib
16 16 > [extensions]
17 17 > simplecache = $TESTDIR/wireprotosimplecache.py
18 18 > [simplecache]
19 19 > cacheapi = true
20 20 > EOF
21 21
22 22 $ echo a0 > a
23 23 $ echo b0 > b
24 24 $ hg -q commit -A -m 'commit 0'
25 25 $ echo a1 > a
26 26 $ hg commit -m 'commit 1'
27 27
28 28 $ hg --debug debugindex -m
29 29 rev linkrev nodeid p1 p2
30 30 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
31 31 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
32 32
33 33 $ hg --config simplecache.redirectsfile=redirects.py serve -p $HGPORT -d --pid-file hg.pid -E error.log
34 34 $ cat hg.pid > $DAEMON_PIDS
35 35
36 36 $ cat > redirects.py << EOF
37 37 > [
38 38 > {
39 39 > b'name': b'target-a',
40 40 > b'protocol': b'http',
41 41 > b'snirequired': False,
42 42 > b'tlsversions': [b'1.2', b'1.3'],
43 43 > b'uris': [b'http://example.com/'],
44 44 > },
45 45 > ]
46 46 > EOF
47 47
48 48 Redirect targets advertised when configured
49 49
50 50 $ sendhttpv2peerhandshake << EOF
51 51 > command capabilities
52 52 > EOF
53 53 creating http peer for wire protocol version 2
54 54 s> GET /?cmd=capabilities HTTP/1.1\r\n
55 55 s> Accept-Encoding: identity\r\n
56 56 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
57 57 s> x-hgproto-1: cbor\r\n
58 58 s> x-hgupgrade-1: exp-http-v2-0003\r\n
59 59 s> accept: application/mercurial-0.1\r\n
60 60 s> host: $LOCALIP:$HGPORT\r\n (glob)
61 61 s> user-agent: Mercurial debugwireproto\r\n
62 62 s> \r\n
63 63 s> makefile('rb', None)
64 64 s> HTTP/1.1 200 OK\r\n
65 65 s> Server: testing stub value\r\n
66 66 s> Date: $HTTP_DATE$\r\n
67 67 s> Content-Type: application/mercurial-cbor\r\n
68 s> Content-Length: 1871\r\n
68 s> Content-Length: 2131\r\n
69 69 s> \r\n
70 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
70 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
71 71 (remote redirect target target-a is compatible)
72 72 sending capabilities command
73 73 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
74 74 s> Accept-Encoding: identity\r\n
75 75 s> accept: application/mercurial-exp-framing-0006\r\n
76 76 s> content-type: application/mercurial-exp-framing-0006\r\n
77 77 s> content-length: 111\r\n
78 78 s> host: $LOCALIP:$HGPORT\r\n (glob)
79 79 s> user-agent: Mercurial debugwireproto\r\n
80 80 s> \r\n
81 81 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
82 82 s> makefile('rb', None)
83 83 s> HTTP/1.1 200 OK\r\n
84 84 s> Server: testing stub value\r\n
85 85 s> Date: $HTTP_DATE$\r\n
86 86 s> Content-Type: application/mercurial-exp-framing-0006\r\n
87 87 s> Transfer-Encoding: chunked\r\n
88 88 s> \r\n
89 89 s> 11\r\n
90 90 s> \t\x00\x00\x01\x00\x02\x01\x92
91 91 s> Hidentity
92 92 s> \r\n
93 93 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
94 94 s> 13\r\n
95 95 s> \x0b\x00\x00\x01\x00\x02\x041
96 96 s> \xa1FstatusBok
97 97 s> \r\n
98 98 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
99 s> 54d\r\n
100 s> E\x05\x00\x01\x00\x02\x041
101 s> \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/
99 s> 651\r\n
100 s> I\x06\x00\x01\x00\x02\x041
101 s> \xa5Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/
102 102 s> \r\n
103 received frame(size=1349; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
103 received frame(size=1609; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
104 104 s> 8\r\n
105 105 s> \x00\x00\x00\x01\x00\x02\x002
106 106 s> \r\n
107 107 s> 0\r\n
108 108 s> \r\n
109 109 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
110 110 response: gen[
111 111 {
112 112 b'commands': {
113 113 b'branchmap': {
114 114 b'args': {},
115 115 b'permissions': [
116 116 b'pull'
117 117 ]
118 118 },
119 119 b'capabilities': {
120 120 b'args': {},
121 121 b'permissions': [
122 122 b'pull'
123 123 ]
124 124 },
125 125 b'changesetdata': {
126 126 b'args': {
127 127 b'fields': {
128 128 b'default': set([]),
129 129 b'required': False,
130 130 b'type': b'set',
131 131 b'validvalues': set([
132 132 b'bookmarks',
133 133 b'parents',
134 134 b'phase',
135 135 b'revision'
136 136 ])
137 137 },
138 138 b'revisions': {
139 139 b'required': True,
140 140 b'type': b'list'
141 141 }
142 142 },
143 143 b'permissions': [
144 144 b'pull'
145 145 ]
146 146 },
147 147 b'filedata': {
148 148 b'args': {
149 149 b'fields': {
150 150 b'default': set([]),
151 151 b'required': False,
152 152 b'type': b'set',
153 153 b'validvalues': set([
154 154 b'parents',
155 155 b'revision'
156 156 ])
157 157 },
158 158 b'haveparents': {
159 159 b'default': False,
160 160 b'required': False,
161 161 b'type': b'bool'
162 162 },
163 163 b'nodes': {
164 164 b'required': True,
165 165 b'type': b'list'
166 166 },
167 167 b'path': {
168 168 b'required': True,
169 169 b'type': b'bytes'
170 170 }
171 171 },
172 172 b'permissions': [
173 173 b'pull'
174 174 ]
175 175 },
176 b'filesdata': {
177 b'args': {
178 b'fields': {
179 b'default': set([]),
180 b'required': False,
181 b'type': b'set',
182 b'validvalues': set([
183 b'firstchangeset',
184 b'parents',
185 b'revision'
186 ])
187 },
188 b'haveparents': {
189 b'default': False,
190 b'required': False,
191 b'type': b'bool'
192 },
193 b'pathfilter': {
194 b'default': None,
195 b'required': False,
196 b'type': b'dict'
197 },
198 b'revisions': {
199 b'required': True,
200 b'type': b'list'
201 }
202 },
203 b'permissions': [
204 b'pull'
205 ],
206 b'recommendedbatchsize': 50000
207 },
176 208 b'heads': {
177 209 b'args': {
178 210 b'publiconly': {
179 211 b'default': False,
180 212 b'required': False,
181 213 b'type': b'bool'
182 214 }
183 215 },
184 216 b'permissions': [
185 217 b'pull'
186 218 ]
187 219 },
188 220 b'known': {
189 221 b'args': {
190 222 b'nodes': {
191 223 b'default': [],
192 224 b'required': False,
193 225 b'type': b'list'
194 226 }
195 227 },
196 228 b'permissions': [
197 229 b'pull'
198 230 ]
199 231 },
200 232 b'listkeys': {
201 233 b'args': {
202 234 b'namespace': {
203 235 b'required': True,
204 236 b'type': b'bytes'
205 237 }
206 238 },
207 239 b'permissions': [
208 240 b'pull'
209 241 ]
210 242 },
211 243 b'lookup': {
212 244 b'args': {
213 245 b'key': {
214 246 b'required': True,
215 247 b'type': b'bytes'
216 248 }
217 249 },
218 250 b'permissions': [
219 251 b'pull'
220 252 ]
221 253 },
222 254 b'manifestdata': {
223 255 b'args': {
224 256 b'fields': {
225 257 b'default': set([]),
226 258 b'required': False,
227 259 b'type': b'set',
228 260 b'validvalues': set([
229 261 b'parents',
230 262 b'revision'
231 263 ])
232 264 },
233 265 b'haveparents': {
234 266 b'default': False,
235 267 b'required': False,
236 268 b'type': b'bool'
237 269 },
238 270 b'nodes': {
239 271 b'required': True,
240 272 b'type': b'list'
241 273 },
242 274 b'tree': {
243 275 b'required': True,
244 276 b'type': b'bytes'
245 277 }
246 278 },
247 279 b'permissions': [
248 280 b'pull'
249 281 ],
250 282 b'recommendedbatchsize': 100000
251 283 },
252 284 b'pushkey': {
253 285 b'args': {
254 286 b'key': {
255 287 b'required': True,
256 288 b'type': b'bytes'
257 289 },
258 290 b'namespace': {
259 291 b'required': True,
260 292 b'type': b'bytes'
261 293 },
262 294 b'new': {
263 295 b'required': True,
264 296 b'type': b'bytes'
265 297 },
266 298 b'old': {
267 299 b'required': True,
268 300 b'type': b'bytes'
269 301 }
270 302 },
271 303 b'permissions': [
272 304 b'push'
273 305 ]
274 306 }
275 307 },
276 308 b'framingmediatypes': [
277 309 b'application/mercurial-exp-framing-0006'
278 310 ],
279 311 b'pathfilterprefixes': set([
280 312 b'path:',
281 313 b'rootfilesin:'
282 314 ]),
283 315 b'rawrepoformats': [
284 316 b'generaldelta',
285 317 b'revlogv1'
286 318 ],
287 319 b'redirect': {
288 320 b'hashes': [
289 321 b'sha256',
290 322 b'sha1'
291 323 ],
292 324 b'targets': [
293 325 {
294 326 b'name': b'target-a',
295 327 b'protocol': b'http',
296 328 b'snirequired': False,
297 329 b'tlsversions': [
298 330 b'1.2',
299 331 b'1.3'
300 332 ],
301 333 b'uris': [
302 334 b'http://example.com/'
303 335 ]
304 336 }
305 337 ]
306 338 }
307 339 }
308 340 ]
309 341 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
310 342
311 343 Unknown protocol is filtered from compatible targets
312 344
313 345 $ cat > redirects.py << EOF
314 346 > [
315 347 > {
316 348 > b'name': b'target-a',
317 349 > b'protocol': b'http',
318 350 > b'uris': [b'http://example.com/'],
319 351 > },
320 352 > {
321 353 > b'name': b'target-b',
322 354 > b'protocol': b'unknown',
323 355 > b'uris': [b'unknown://example.com/'],
324 356 > },
325 357 > ]
326 358 > EOF
327 359
328 360 $ sendhttpv2peerhandshake << EOF
329 361 > command capabilities
330 362 > EOF
331 363 creating http peer for wire protocol version 2
332 364 s> GET /?cmd=capabilities HTTP/1.1\r\n
333 365 s> Accept-Encoding: identity\r\n
334 366 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
335 367 s> x-hgproto-1: cbor\r\n
336 368 s> x-hgupgrade-1: exp-http-v2-0003\r\n
337 369 s> accept: application/mercurial-0.1\r\n
338 370 s> host: $LOCALIP:$HGPORT\r\n (glob)
339 371 s> user-agent: Mercurial debugwireproto\r\n
340 372 s> \r\n
341 373 s> makefile('rb', None)
342 374 s> HTTP/1.1 200 OK\r\n
343 375 s> Server: testing stub value\r\n
344 376 s> Date: $HTTP_DATE$\r\n
345 377 s> Content-Type: application/mercurial-cbor\r\n
346 s> Content-Length: 1898\r\n
378 s> Content-Length: 2158\r\n
347 379 s> \r\n
348 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
380 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
349 381 (remote redirect target target-a is compatible)
350 382 (remote redirect target target-b uses unsupported protocol: unknown)
351 383 sending capabilities command
352 384 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
353 385 s> Accept-Encoding: identity\r\n
354 386 s> accept: application/mercurial-exp-framing-0006\r\n
355 387 s> content-type: application/mercurial-exp-framing-0006\r\n
356 388 s> content-length: 111\r\n
357 389 s> host: $LOCALIP:$HGPORT\r\n (glob)
358 390 s> user-agent: Mercurial debugwireproto\r\n
359 391 s> \r\n
360 392 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
361 393 s> makefile('rb', None)
362 394 s> HTTP/1.1 200 OK\r\n
363 395 s> Server: testing stub value\r\n
364 396 s> Date: $HTTP_DATE$\r\n
365 397 s> Content-Type: application/mercurial-exp-framing-0006\r\n
366 398 s> Transfer-Encoding: chunked\r\n
367 399 s> \r\n
368 400 s> 11\r\n
369 401 s> \t\x00\x00\x01\x00\x02\x01\x92
370 402 s> Hidentity
371 403 s> \r\n
372 404 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
373 405 s> 13\r\n
374 406 s> \x0b\x00\x00\x01\x00\x02\x041
375 407 s> \xa1FstatusBok
376 408 s> \r\n
377 409 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
378 s> 568\r\n
379 s> `\x05\x00\x01\x00\x02\x041
380 s> \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/
410 s> 66c\r\n
411 s> d\x06\x00\x01\x00\x02\x041
412 s> \xa5Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/
381 413 s> \r\n
382 received frame(size=1376; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
414 received frame(size=1636; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
383 415 s> 8\r\n
384 416 s> \x00\x00\x00\x01\x00\x02\x002
385 417 s> \r\n
386 418 s> 0\r\n
387 419 s> \r\n
388 420 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
389 421 response: gen[
390 422 {
391 423 b'commands': {
392 424 b'branchmap': {
393 425 b'args': {},
394 426 b'permissions': [
395 427 b'pull'
396 428 ]
397 429 },
398 430 b'capabilities': {
399 431 b'args': {},
400 432 b'permissions': [
401 433 b'pull'
402 434 ]
403 435 },
404 436 b'changesetdata': {
405 437 b'args': {
406 438 b'fields': {
407 439 b'default': set([]),
408 440 b'required': False,
409 441 b'type': b'set',
410 442 b'validvalues': set([
411 443 b'bookmarks',
412 444 b'parents',
413 445 b'phase',
414 446 b'revision'
415 447 ])
416 448 },
417 449 b'revisions': {
418 450 b'required': True,
419 451 b'type': b'list'
420 452 }
421 453 },
422 454 b'permissions': [
423 455 b'pull'
424 456 ]
425 457 },
426 458 b'filedata': {
427 459 b'args': {
428 460 b'fields': {
429 461 b'default': set([]),
430 462 b'required': False,
431 463 b'type': b'set',
432 464 b'validvalues': set([
433 465 b'parents',
434 466 b'revision'
435 467 ])
436 468 },
437 469 b'haveparents': {
438 470 b'default': False,
439 471 b'required': False,
440 472 b'type': b'bool'
441 473 },
442 474 b'nodes': {
443 475 b'required': True,
444 476 b'type': b'list'
445 477 },
446 478 b'path': {
447 479 b'required': True,
448 480 b'type': b'bytes'
449 481 }
450 482 },
451 483 b'permissions': [
452 484 b'pull'
453 485 ]
454 486 },
487 b'filesdata': {
488 b'args': {
489 b'fields': {
490 b'default': set([]),
491 b'required': False,
492 b'type': b'set',
493 b'validvalues': set([
494 b'firstchangeset',
495 b'parents',
496 b'revision'
497 ])
498 },
499 b'haveparents': {
500 b'default': False,
501 b'required': False,
502 b'type': b'bool'
503 },
504 b'pathfilter': {
505 b'default': None,
506 b'required': False,
507 b'type': b'dict'
508 },
509 b'revisions': {
510 b'required': True,
511 b'type': b'list'
512 }
513 },
514 b'permissions': [
515 b'pull'
516 ],
517 b'recommendedbatchsize': 50000
518 },
455 519 b'heads': {
456 520 b'args': {
457 521 b'publiconly': {
458 522 b'default': False,
459 523 b'required': False,
460 524 b'type': b'bool'
461 525 }
462 526 },
463 527 b'permissions': [
464 528 b'pull'
465 529 ]
466 530 },
467 531 b'known': {
468 532 b'args': {
469 533 b'nodes': {
470 534 b'default': [],
471 535 b'required': False,
472 536 b'type': b'list'
473 537 }
474 538 },
475 539 b'permissions': [
476 540 b'pull'
477 541 ]
478 542 },
479 543 b'listkeys': {
480 544 b'args': {
481 545 b'namespace': {
482 546 b'required': True,
483 547 b'type': b'bytes'
484 548 }
485 549 },
486 550 b'permissions': [
487 551 b'pull'
488 552 ]
489 553 },
490 554 b'lookup': {
491 555 b'args': {
492 556 b'key': {
493 557 b'required': True,
494 558 b'type': b'bytes'
495 559 }
496 560 },
497 561 b'permissions': [
498 562 b'pull'
499 563 ]
500 564 },
501 565 b'manifestdata': {
502 566 b'args': {
503 567 b'fields': {
504 568 b'default': set([]),
505 569 b'required': False,
506 570 b'type': b'set',
507 571 b'validvalues': set([
508 572 b'parents',
509 573 b'revision'
510 574 ])
511 575 },
512 576 b'haveparents': {
513 577 b'default': False,
514 578 b'required': False,
515 579 b'type': b'bool'
516 580 },
517 581 b'nodes': {
518 582 b'required': True,
519 583 b'type': b'list'
520 584 },
521 585 b'tree': {
522 586 b'required': True,
523 587 b'type': b'bytes'
524 588 }
525 589 },
526 590 b'permissions': [
527 591 b'pull'
528 592 ],
529 593 b'recommendedbatchsize': 100000
530 594 },
531 595 b'pushkey': {
532 596 b'args': {
533 597 b'key': {
534 598 b'required': True,
535 599 b'type': b'bytes'
536 600 },
537 601 b'namespace': {
538 602 b'required': True,
539 603 b'type': b'bytes'
540 604 },
541 605 b'new': {
542 606 b'required': True,
543 607 b'type': b'bytes'
544 608 },
545 609 b'old': {
546 610 b'required': True,
547 611 b'type': b'bytes'
548 612 }
549 613 },
550 614 b'permissions': [
551 615 b'push'
552 616 ]
553 617 }
554 618 },
555 619 b'framingmediatypes': [
556 620 b'application/mercurial-exp-framing-0006'
557 621 ],
558 622 b'pathfilterprefixes': set([
559 623 b'path:',
560 624 b'rootfilesin:'
561 625 ]),
562 626 b'rawrepoformats': [
563 627 b'generaldelta',
564 628 b'revlogv1'
565 629 ],
566 630 b'redirect': {
567 631 b'hashes': [
568 632 b'sha256',
569 633 b'sha1'
570 634 ],
571 635 b'targets': [
572 636 {
573 637 b'name': b'target-a',
574 638 b'protocol': b'http',
575 639 b'uris': [
576 640 b'http://example.com/'
577 641 ]
578 642 },
579 643 {
580 644 b'name': b'target-b',
581 645 b'protocol': b'unknown',
582 646 b'uris': [
583 647 b'unknown://example.com/'
584 648 ]
585 649 }
586 650 ]
587 651 }
588 652 }
589 653 ]
590 654 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
591 655
592 656 Missing SNI support filters targets that require SNI
593 657
594 658 $ cat > nosni.py << EOF
595 659 > from mercurial import sslutil
596 660 > sslutil.hassni = False
597 661 > EOF
598 662 $ cat >> $HGRCPATH << EOF
599 663 > [extensions]
600 664 > nosni=`pwd`/nosni.py
601 665 > EOF
602 666
603 667 $ cat > redirects.py << EOF
604 668 > [
605 669 > {
606 670 > b'name': b'target-bad-tls',
607 671 > b'protocol': b'https',
608 672 > b'uris': [b'https://example.com/'],
609 673 > b'snirequired': True,
610 674 > },
611 675 > ]
612 676 > EOF
613 677
614 678 $ sendhttpv2peerhandshake << EOF
615 679 > command capabilities
616 680 > EOF
617 681 creating http peer for wire protocol version 2
618 682 s> GET /?cmd=capabilities HTTP/1.1\r\n
619 683 s> Accept-Encoding: identity\r\n
620 684 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
621 685 s> x-hgproto-1: cbor\r\n
622 686 s> x-hgupgrade-1: exp-http-v2-0003\r\n
623 687 s> accept: application/mercurial-0.1\r\n
624 688 s> host: $LOCALIP:$HGPORT\r\n (glob)
625 689 s> user-agent: Mercurial debugwireproto\r\n
626 690 s> \r\n
627 691 s> makefile('rb', None)
628 692 s> HTTP/1.1 200 OK\r\n
629 693 s> Server: testing stub value\r\n
630 694 s> Date: $HTTP_DATE$\r\n
631 695 s> Content-Type: application/mercurial-cbor\r\n
632 s> Content-Length: 1858\r\n
696 s> Content-Length: 2118\r\n
633 697 s> \r\n
634 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
698 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
635 699 (redirect target target-bad-tls requires SNI, which is unsupported)
636 700 sending capabilities command
637 701 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
638 702 s> Accept-Encoding: identity\r\n
639 703 s> accept: application/mercurial-exp-framing-0006\r\n
640 704 s> content-type: application/mercurial-exp-framing-0006\r\n
641 705 s> content-length: 102\r\n
642 706 s> host: $LOCALIP:$HGPORT\r\n (glob)
643 707 s> user-agent: Mercurial debugwireproto\r\n
644 708 s> \r\n
645 709 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
646 710 s> makefile('rb', None)
647 711 s> HTTP/1.1 200 OK\r\n
648 712 s> Server: testing stub value\r\n
649 713 s> Date: $HTTP_DATE$\r\n
650 714 s> Content-Type: application/mercurial-exp-framing-0006\r\n
651 715 s> Transfer-Encoding: chunked\r\n
652 716 s> \r\n
653 717 s> 11\r\n
654 718 s> \t\x00\x00\x01\x00\x02\x01\x92
655 719 s> Hidentity
656 720 s> \r\n
657 721 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
658 722 s> 13\r\n
659 723 s> \x0b\x00\x00\x01\x00\x02\x041
660 724 s> \xa1FstatusBok
661 725 s> \r\n
662 726 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
663 s> 540\r\n
664 s> 8\x05\x00\x01\x00\x02\x041
665 s> \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
727 s> 644\r\n
728 s> <\x06\x00\x01\x00\x02\x041
729 s> \xa5Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
666 730 s> \r\n
667 received frame(size=1336; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
731 received frame(size=1596; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
668 732 s> 8\r\n
669 733 s> \x00\x00\x00\x01\x00\x02\x002
670 734 s> \r\n
671 735 s> 0\r\n
672 736 s> \r\n
673 737 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
674 738 response: gen[
675 739 {
676 740 b'commands': {
677 741 b'branchmap': {
678 742 b'args': {},
679 743 b'permissions': [
680 744 b'pull'
681 745 ]
682 746 },
683 747 b'capabilities': {
684 748 b'args': {},
685 749 b'permissions': [
686 750 b'pull'
687 751 ]
688 752 },
689 753 b'changesetdata': {
690 754 b'args': {
691 755 b'fields': {
692 756 b'default': set([]),
693 757 b'required': False,
694 758 b'type': b'set',
695 759 b'validvalues': set([
696 760 b'bookmarks',
697 761 b'parents',
698 762 b'phase',
699 763 b'revision'
700 764 ])
701 765 },
702 766 b'revisions': {
703 767 b'required': True,
704 768 b'type': b'list'
705 769 }
706 770 },
707 771 b'permissions': [
708 772 b'pull'
709 773 ]
710 774 },
711 775 b'filedata': {
712 776 b'args': {
713 777 b'fields': {
714 778 b'default': set([]),
715 779 b'required': False,
716 780 b'type': b'set',
717 781 b'validvalues': set([
718 782 b'parents',
719 783 b'revision'
720 784 ])
721 785 },
722 786 b'haveparents': {
723 787 b'default': False,
724 788 b'required': False,
725 789 b'type': b'bool'
726 790 },
727 791 b'nodes': {
728 792 b'required': True,
729 793 b'type': b'list'
730 794 },
731 795 b'path': {
732 796 b'required': True,
733 797 b'type': b'bytes'
734 798 }
735 799 },
736 800 b'permissions': [
737 801 b'pull'
738 802 ]
739 803 },
804 b'filesdata': {
805 b'args': {
806 b'fields': {
807 b'default': set([]),
808 b'required': False,
809 b'type': b'set',
810 b'validvalues': set([
811 b'firstchangeset',
812 b'parents',
813 b'revision'
814 ])
815 },
816 b'haveparents': {
817 b'default': False,
818 b'required': False,
819 b'type': b'bool'
820 },
821 b'pathfilter': {
822 b'default': None,
823 b'required': False,
824 b'type': b'dict'
825 },
826 b'revisions': {
827 b'required': True,
828 b'type': b'list'
829 }
830 },
831 b'permissions': [
832 b'pull'
833 ],
834 b'recommendedbatchsize': 50000
835 },
740 836 b'heads': {
741 837 b'args': {
742 838 b'publiconly': {
743 839 b'default': False,
744 840 b'required': False,
745 841 b'type': b'bool'
746 842 }
747 843 },
748 844 b'permissions': [
749 845 b'pull'
750 846 ]
751 847 },
752 848 b'known': {
753 849 b'args': {
754 850 b'nodes': {
755 851 b'default': [],
756 852 b'required': False,
757 853 b'type': b'list'
758 854 }
759 855 },
760 856 b'permissions': [
761 857 b'pull'
762 858 ]
763 859 },
764 860 b'listkeys': {
765 861 b'args': {
766 862 b'namespace': {
767 863 b'required': True,
768 864 b'type': b'bytes'
769 865 }
770 866 },
771 867 b'permissions': [
772 868 b'pull'
773 869 ]
774 870 },
775 871 b'lookup': {
776 872 b'args': {
777 873 b'key': {
778 874 b'required': True,
779 875 b'type': b'bytes'
780 876 }
781 877 },
782 878 b'permissions': [
783 879 b'pull'
784 880 ]
785 881 },
786 882 b'manifestdata': {
787 883 b'args': {
788 884 b'fields': {
789 885 b'default': set([]),
790 886 b'required': False,
791 887 b'type': b'set',
792 888 b'validvalues': set([
793 889 b'parents',
794 890 b'revision'
795 891 ])
796 892 },
797 893 b'haveparents': {
798 894 b'default': False,
799 895 b'required': False,
800 896 b'type': b'bool'
801 897 },
802 898 b'nodes': {
803 899 b'required': True,
804 900 b'type': b'list'
805 901 },
806 902 b'tree': {
807 903 b'required': True,
808 904 b'type': b'bytes'
809 905 }
810 906 },
811 907 b'permissions': [
812 908 b'pull'
813 909 ],
814 910 b'recommendedbatchsize': 100000
815 911 },
816 912 b'pushkey': {
817 913 b'args': {
818 914 b'key': {
819 915 b'required': True,
820 916 b'type': b'bytes'
821 917 },
822 918 b'namespace': {
823 919 b'required': True,
824 920 b'type': b'bytes'
825 921 },
826 922 b'new': {
827 923 b'required': True,
828 924 b'type': b'bytes'
829 925 },
830 926 b'old': {
831 927 b'required': True,
832 928 b'type': b'bytes'
833 929 }
834 930 },
835 931 b'permissions': [
836 932 b'push'
837 933 ]
838 934 }
839 935 },
840 936 b'framingmediatypes': [
841 937 b'application/mercurial-exp-framing-0006'
842 938 ],
843 939 b'pathfilterprefixes': set([
844 940 b'path:',
845 941 b'rootfilesin:'
846 942 ]),
847 943 b'rawrepoformats': [
848 944 b'generaldelta',
849 945 b'revlogv1'
850 946 ],
851 947 b'redirect': {
852 948 b'hashes': [
853 949 b'sha256',
854 950 b'sha1'
855 951 ],
856 952 b'targets': [
857 953 {
858 954 b'name': b'target-bad-tls',
859 955 b'protocol': b'https',
860 956 b'snirequired': True,
861 957 b'uris': [
862 958 b'https://example.com/'
863 959 ]
864 960 }
865 961 ]
866 962 }
867 963 }
868 964 ]
869 965 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
870 966
871 967 $ cat >> $HGRCPATH << EOF
872 968 > [extensions]
873 969 > nosni=!
874 970 > EOF
875 971
876 972 Unknown tls value is filtered from compatible targets
877 973
878 974 $ cat > redirects.py << EOF
879 975 > [
880 976 > {
881 977 > b'name': b'target-bad-tls',
882 978 > b'protocol': b'https',
883 979 > b'uris': [b'https://example.com/'],
884 980 > b'tlsversions': [b'42', b'39'],
885 981 > },
886 982 > ]
887 983 > EOF
888 984
889 985 $ sendhttpv2peerhandshake << EOF
890 986 > command capabilities
891 987 > EOF
892 988 creating http peer for wire protocol version 2
893 989 s> GET /?cmd=capabilities HTTP/1.1\r\n
894 990 s> Accept-Encoding: identity\r\n
895 991 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
896 992 s> x-hgproto-1: cbor\r\n
897 993 s> x-hgupgrade-1: exp-http-v2-0003\r\n
898 994 s> accept: application/mercurial-0.1\r\n
899 995 s> host: $LOCALIP:$HGPORT\r\n (glob)
900 996 s> user-agent: Mercurial debugwireproto\r\n
901 997 s> \r\n
902 998 s> makefile('rb', None)
903 999 s> HTTP/1.1 200 OK\r\n
904 1000 s> Server: testing stub value\r\n
905 1001 s> Date: $HTTP_DATE$\r\n
906 1002 s> Content-Type: application/mercurial-cbor\r\n
907 s> Content-Length: 1864\r\n
1003 s> Content-Length: 2124\r\n
908 1004 s> \r\n
909 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
1005 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
910 1006 (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42)
911 1007 sending capabilities command
912 1008 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
913 1009 s> Accept-Encoding: identity\r\n
914 1010 s> accept: application/mercurial-exp-framing-0006\r\n
915 1011 s> content-type: application/mercurial-exp-framing-0006\r\n
916 1012 s> content-length: 102\r\n
917 1013 s> host: $LOCALIP:$HGPORT\r\n (glob)
918 1014 s> user-agent: Mercurial debugwireproto\r\n
919 1015 s> \r\n
920 1016 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
921 1017 s> makefile('rb', None)
922 1018 s> HTTP/1.1 200 OK\r\n
923 1019 s> Server: testing stub value\r\n
924 1020 s> Date: $HTTP_DATE$\r\n
925 1021 s> Content-Type: application/mercurial-exp-framing-0006\r\n
926 1022 s> Transfer-Encoding: chunked\r\n
927 1023 s> \r\n
928 1024 s> 11\r\n
929 1025 s> \t\x00\x00\x01\x00\x02\x01\x92
930 1026 s> Hidentity
931 1027 s> \r\n
932 1028 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
933 1029 s> 13\r\n
934 1030 s> \x0b\x00\x00\x01\x00\x02\x041
935 1031 s> \xa1FstatusBok
936 1032 s> \r\n
937 1033 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
938 s> 546\r\n
939 s> >\x05\x00\x01\x00\x02\x041
940 s> \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
1034 s> 64a\r\n
1035 s> B\x06\x00\x01\x00\x02\x041
1036 s> \xa5Hcommands\xabIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83NfirstchangesetGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
941 1037 s> \r\n
942 received frame(size=1342; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
1038 received frame(size=1602; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
943 1039 s> 8\r\n
944 1040 s> \x00\x00\x00\x01\x00\x02\x002
945 1041 s> \r\n
946 1042 s> 0\r\n
947 1043 s> \r\n
948 1044 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
949 1045 response: gen[
950 1046 {
951 1047 b'commands': {
952 1048 b'branchmap': {
953 1049 b'args': {},
954 1050 b'permissions': [
955 1051 b'pull'
956 1052 ]
957 1053 },
958 1054 b'capabilities': {
959 1055 b'args': {},
960 1056 b'permissions': [
961 1057 b'pull'
962 1058 ]
963 1059 },
964 1060 b'changesetdata': {
965 1061 b'args': {
966 1062 b'fields': {
967 1063 b'default': set([]),
968 1064 b'required': False,
969 1065 b'type': b'set',
970 1066 b'validvalues': set([
971 1067 b'bookmarks',
972 1068 b'parents',
973 1069 b'phase',
974 1070 b'revision'
975 1071 ])
976 1072 },
977 1073 b'revisions': {
978 1074 b'required': True,
979 1075 b'type': b'list'
980 1076 }
981 1077 },
982 1078 b'permissions': [
983 1079 b'pull'
984 1080 ]
985 1081 },
986 1082 b'filedata': {
987 1083 b'args': {
988 1084 b'fields': {
989 1085 b'default': set([]),
990 1086 b'required': False,
991 1087 b'type': b'set',
992 1088 b'validvalues': set([
993 1089 b'parents',
994 1090 b'revision'
995 1091 ])
996 1092 },
997 1093 b'haveparents': {
998 1094 b'default': False,
999 1095 b'required': False,
1000 1096 b'type': b'bool'
1001 1097 },
1002 1098 b'nodes': {
1003 1099 b'required': True,
1004 1100 b'type': b'list'
1005 1101 },
1006 1102 b'path': {
1007 1103 b'required': True,
1008 1104 b'type': b'bytes'
1009 1105 }
1010 1106 },
1011 1107 b'permissions': [
1012 1108 b'pull'
1013 1109 ]
1014 1110 },
1111 b'filesdata': {
1112 b'args': {
1113 b'fields': {
1114 b'default': set([]),
1115 b'required': False,
1116 b'type': b'set',
1117 b'validvalues': set([
1118 b'firstchangeset',
1119 b'parents',
1120 b'revision'
1121 ])
1122 },
1123 b'haveparents': {
1124 b'default': False,
1125 b'required': False,
1126 b'type': b'bool'
1127 },
1128 b'pathfilter': {
1129 b'default': None,
1130 b'required': False,
1131 b'type': b'dict'
1132 },
1133 b'revisions': {
1134 b'required': True,
1135 b'type': b'list'
1136 }
1137 },
1138 b'permissions': [
1139 b'pull'
1140 ],
1141 b'recommendedbatchsize': 50000
1142 },
1015 1143 b'heads': {
1016 1144 b'args': {
1017 1145 b'publiconly': {
1018 1146 b'default': False,
1019 1147 b'required': False,
1020 1148 b'type': b'bool'
1021 1149 }
1022 1150 },
1023 1151 b'permissions': [
1024 1152 b'pull'
1025 1153 ]
1026 1154 },
1027 1155 b'known': {
1028 1156 b'args': {
1029 1157 b'nodes': {
1030 1158 b'default': [],
1031 1159 b'required': False,
1032 1160 b'type': b'list'
1033 1161 }
1034 1162 },
1035 1163 b'permissions': [
1036 1164 b'pull'
1037 1165 ]
1038 1166 },
1039 1167 b'listkeys': {
1040 1168 b'args': {
1041 1169 b'namespace': {
1042 1170 b'required': True,
1043 1171 b'type': b'bytes'
1044 1172 }
1045 1173 },
1046 1174 b'permissions': [
1047 1175 b'pull'
1048 1176 ]
1049 1177 },
1050 1178 b'lookup': {
1051 1179 b'args': {
1052 1180 b'key': {
1053 1181 b'required': True,
1054 1182 b'type': b'bytes'
1055 1183 }
1056 1184 },
1057 1185 b'permissions': [
1058 1186 b'pull'
1059 1187 ]
1060 1188 },
1061 1189 b'manifestdata': {
1062 1190 b'args': {
1063 1191 b'fields': {
1064 1192 b'default': set([]),
1065 1193 b'required': False,
1066 1194 b'type': b'set',
1067 1195 b'validvalues': set([
1068 1196 b'parents',
1069 1197 b'revision'
1070 1198 ])
1071 1199 },
1072 1200 b'haveparents': {
1073 1201 b'default': False,
1074 1202 b'required': False,
1075 1203 b'type': b'bool'
1076 1204 },
1077 1205 b'nodes': {
1078 1206 b'required': True,
1079 1207 b'type': b'list'
1080 1208 },
1081 1209 b'tree': {
1082 1210 b'required': True,
1083 1211 b'type': b'bytes'
1084 1212 }
1085 1213 },
1086 1214 b'permissions': [
1087 1215 b'pull'
1088 1216 ],
1089 1217 b'recommendedbatchsize': 100000
1090 1218 },
1091 1219 b'pushkey': {
1092 1220 b'args': {
1093 1221 b'key': {
1094 1222 b'required': True,
1095 1223 b'type': b'bytes'
1096 1224 },
1097 1225 b'namespace': {
1098 1226 b'required': True,
1099 1227 b'type': b'bytes'
1100 1228 },
1101 1229 b'new': {
1102 1230 b'required': True,
1103 1231 b'type': b'bytes'
1104 1232 },
1105 1233 b'old': {
1106 1234 b'required': True,
1107 1235 b'type': b'bytes'
1108 1236 }
1109 1237 },
1110 1238 b'permissions': [
1111 1239 b'push'
1112 1240 ]
1113 1241 }
1114 1242 },
1115 1243 b'framingmediatypes': [
1116 1244 b'application/mercurial-exp-framing-0006'
1117 1245 ],
1118 1246 b'pathfilterprefixes': set([
1119 1247 b'path:',
1120 1248 b'rootfilesin:'
1121 1249 ]),
1122 1250 b'rawrepoformats': [
1123 1251 b'generaldelta',
1124 1252 b'revlogv1'
1125 1253 ],
1126 1254 b'redirect': {
1127 1255 b'hashes': [
1128 1256 b'sha256',
1129 1257 b'sha1'
1130 1258 ],
1131 1259 b'targets': [
1132 1260 {
1133 1261 b'name': b'target-bad-tls',
1134 1262 b'protocol': b'https',
1135 1263 b'tlsversions': [
1136 1264 b'42',
1137 1265 b'39'
1138 1266 ],
1139 1267 b'uris': [
1140 1268 b'https://example.com/'
1141 1269 ]
1142 1270 }
1143 1271 ]
1144 1272 }
1145 1273 }
1146 1274 ]
1147 1275 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1148 1276
1149 1277 Set up the server to issue content redirects to its built-in API server.
1150 1278
1151 1279 $ cat > redirects.py << EOF
1152 1280 > [
1153 1281 > {
1154 1282 > b'name': b'local',
1155 1283 > b'protocol': b'http',
1156 1284 > b'uris': [b'http://example.com/'],
1157 1285 > },
1158 1286 > ]
1159 1287 > EOF
1160 1288
1161 1289 Request to eventual cache URL should return 404 (validating the cache server works)
1162 1290
1163 1291 $ sendhttpraw << EOF
1164 1292 > httprequest GET api/simplecache/missingkey
1165 1293 > user-agent: test
1166 1294 > EOF
1167 1295 using raw connection to peer
1168 1296 s> GET /api/simplecache/missingkey HTTP/1.1\r\n
1169 1297 s> Accept-Encoding: identity\r\n
1170 1298 s> user-agent: test\r\n
1171 1299 s> host: $LOCALIP:$HGPORT\r\n (glob)
1172 1300 s> \r\n
1173 1301 s> makefile('rb', None)
1174 1302 s> HTTP/1.1 404 Not Found\r\n
1175 1303 s> Server: testing stub value\r\n
1176 1304 s> Date: $HTTP_DATE$\r\n
1177 1305 s> Content-Type: text/plain\r\n
1178 1306 s> Content-Length: 22\r\n
1179 1307 s> \r\n
1180 1308 s> key not found in cache
1181 1309
1182 1310 Send a cacheable request
1183 1311
1184 1312 $ sendhttpv2peer << EOF
1185 1313 > command manifestdata
1186 1314 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1187 1315 > tree eval:b''
1188 1316 > fields eval:[b'parents']
1189 1317 > EOF
1190 1318 creating http peer for wire protocol version 2
1191 1319 sending manifestdata command
1192 1320 response: gen[
1193 1321 {
1194 1322 b'totalitems': 1
1195 1323 },
1196 1324 {
1197 1325 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1198 1326 b'parents': [
1199 1327 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1200 1328 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1201 1329 ]
1202 1330 }
1203 1331 ]
1204 1332
1205 1333 Cached entry should be available on server
1206 1334
1207 1335 $ sendhttpraw << EOF
1208 1336 > httprequest GET api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c
1209 1337 > user-agent: test
1210 1338 > EOF
1211 1339 using raw connection to peer
1212 1340 s> GET /api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c HTTP/1.1\r\n
1213 1341 s> Accept-Encoding: identity\r\n
1214 1342 s> user-agent: test\r\n
1215 1343 s> host: $LOCALIP:$HGPORT\r\n (glob)
1216 1344 s> \r\n
1217 1345 s> makefile('rb', None)
1218 1346 s> HTTP/1.1 200 OK\r\n
1219 1347 s> Server: testing stub value\r\n
1220 1348 s> Date: $HTTP_DATE$\r\n
1221 1349 s> Content-Type: application/mercurial-cbor\r\n
1222 1350 s> Content-Length: 91\r\n
1223 1351 s> \r\n
1224 1352 s> \xa1Jtotalitems\x01\xa2DnodeT\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&AGparents\x82T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
1225 1353 cbor> [
1226 1354 {
1227 1355 b'totalitems': 1
1228 1356 },
1229 1357 {
1230 1358 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1231 1359 b'parents': [
1232 1360 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1233 1361 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1234 1362 ]
1235 1363 }
1236 1364 ]
1237 1365
1238 1366 2nd request should result in content redirect response
1239 1367
1240 1368 $ sendhttpv2peer << EOF
1241 1369 > command manifestdata
1242 1370 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1243 1371 > tree eval:b''
1244 1372 > fields eval:[b'parents']
1245 1373 > EOF
1246 1374 creating http peer for wire protocol version 2
1247 1375 sending manifestdata command
1248 1376 response: gen[
1249 1377 {
1250 1378 b'totalitems': 1
1251 1379 },
1252 1380 {
1253 1381 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1254 1382 b'parents': [
1255 1383 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1256 1384 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1257 1385 ]
1258 1386 }
1259 1387 ]
1260 1388
1261 1389 $ cat error.log
1262 1390 $ killdaemons.py
1263 1391
1264 1392 $ cat .hg/blackbox.log
1265 1393 *> cacher constructed for manifestdata (glob)
1266 1394 *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1267 1395 *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1268 1396 *> cacher constructed for manifestdata (glob)
1269 1397 *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1270 1398 *> sending content redirect for 47abb8efa5f01b8964d74917793ad2464db0fa2c to http://*:$HGPORT/api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
General Comments 0
You need to be logged in to leave comments. Login now