##// END OF EJS Templates
wireprotov2: support exposing linknode of file revisions...
Gregory Szorc -
r40427:abbd0779 default
parent child Browse files
Show More
@@ -1,713 +1,722 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 linknode
262 The changeset node introducing this revision.
263
261 264 parents
262 265 Parent nodes for the revision.
263 266
264 267 revision
265 268 The raw revision data for a file.
266 269
267 270 haveparents
268 271 (bool) Whether the client has the parent revisions of all requested
269 272 nodes. If set, the server may emit revision data as deltas against
270 273 any parent revision. If not set, the server MUST only emit deltas for
271 274 revisions previously emitted by this command.
272 275
273 276 False is assumed in the absence of any value.
274 277
275 278 nodes
276 279 (array of bytestrings) File nodes whose data to retrieve.
277 280
278 281 path
279 282 (bytestring) Path of the tracked file whose data to retrieve.
280 283
281 284 TODO allow specifying revisions via alternate means (such as from
282 285 changeset revisions or ranges)
283 286
284 287 The response bytestream starts with a CBOR map describing the data that
285 288 follows. It has the following bytestream keys:
286 289
287 290 totalitems
288 291 (unsigned integer) Total number of file revisions whose data is
289 292 being returned.
290 293
291 294 Following the map header is a series of 0 or more CBOR values. If values
292 295 are present, the first value will always be a map describing a single changeset
293 296 revision.
294 297
295 298 If the ``fieldsfollowing`` key is present, the map will immediately be followed
296 299 by N CBOR bytestring values, where N is the number of elements in
297 300 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
298 301 by ``fieldsfollowing``.
299 302
300 303 Following the optional bytestring field values is the next revision descriptor
301 304 map, or end of stream.
302 305
303 306 Each revision descriptor map has the following bytestring keys:
304 307
305 308 Each map has the following bytestring keys:
306 309
307 310 node
308 311 (bytestring) The node of the file revision whose data is represented.
309 312
310 313 deltabasenode
311 314 (bytestring) Node of the file revision the following delta is against.
312 315
313 316 Only present if the ``revision`` field is requested and delta data
314 317 follows this map.
315 318
316 319 fieldsfollowing
317 320 (array of 2-array) Denotes extra bytestring fields that following this map.
318 321 See the documentation for ``changesetdata`` for semantics.
319 322
320 323 The following named fields may be present:
321 324
322 325 ``delta``
323 326 The delta data to use to construct the fulltext revision.
324 327
325 328 Only present if the ``revision`` field is requested and a delta is
326 329 being emitted. The ``deltabasenode`` top-level key will also be
327 330 present if this field is being emitted.
328 331
329 332 ``revision``
330 333 The fulltext revision data for this manifest. Only present if the
331 334 ``revision`` field is requested and a fulltext revision is being emitted.
332 335
333 336 parents
334 337 (array of bytestring) The nodes of the parents of this file revision.
335 338
336 339 Only present if the ``parents`` field is requested.
337 340
338 341 When ``revision`` data is requested, the server chooses to emit either fulltext
339 342 revision data or a delta. What the server decides can be inferred by looking
340 343 for the presence of the ``delta`` or ``revision`` keys in the
341 344 ``fieldsfollowing`` array.
342 345
343 346 filesdata
344 347 ---------
345 348
346 349 Obtain various data related to multiple tracked files for specific changesets.
347 350
348 351 This command is similar to ``filedata`` with the main difference being that
349 352 individual requests operate on multiple file paths. This allows clients to
350 353 request data for multiple paths by issuing a single command.
351 354
352 355 The command accepts the following arguments:
353 356
354 357 fields
355 358 (set of bytestring) Which data associated with a file to fetch.
356 359 The following values are recognized:
357 360
361 linknode
362 The changeset node introducing this revision.
363
358 364 parents
359 365 Parent nodes for the revision.
360 366
361 367 revision
362 368 The raw revision data for a file.
363 369
364 370 haveparents
365 371 (bool) Whether the client has the parent revisions of all requested
366 372 nodes.
367 373
368 374 pathfilter
369 375 (map) Defines a filter that determines what file paths are relevant.
370 376
371 377 See the *Path Filters* section for more.
372 378
373 379 If the argument is omitted, it is assumed that all paths are relevant.
374 380
375 381 revisions
376 382 (array of maps) Specifies revisions whose data is being requested. Each value
377 383 in the array is a map describing revisions. See the *Revisions Specifiers*
378 384 section below for the format of this map.
379 385
380 386 Data will be sent for the union of all revisions resolved by all revision
381 387 specifiers.
382 388
383 389 Only revision specifiers operating on changeset revisions are allowed.
384 390
385 391 The response bytestream starts with a CBOR map describing the data that
386 392 follows. This map has the following bytestring keys:
387 393
388 394 totalpaths
389 395 (unsigned integer) Total number of paths whose data is being transferred.
390 396
391 397 totalitems
392 398 (unsigned integer) Total number of file revisions whose data is being
393 399 transferred.
394 400
395 401 Following the map header are 0 or more sequences of CBOR values. Each sequence
396 402 represents data for a specific tracked path. Each sequence begins with a CBOR
397 403 map describing the file data that follows. Following that map is N CBOR values
398 404 describing file revision data. The format of this data is identical to that
399 405 returned by the ``filedata`` command.
400 406
401 407 Each sequence's map header has the following bytestring keys:
402 408
403 409 path
404 410 (bytestring) The tracked file path whose data follows.
405 411
406 412 totalitems
407 413 (unsigned integer) Total number of file revisions whose data is being
408 414 transferred.
409 415
410 416 The ``haveparents`` argument has significant implications on the data
411 417 transferred.
412 418
413 419 When ``haveparents`` is true, the command MAY only emit data for file
414 420 revisions introduced by the set of changeset revisions whose data is being
415 421 requested. In other words, the command may assume that all file revisions
416 422 for all relevant paths for ancestors of the requested changeset revisions
417 423 are present on the receiver.
418 424
419 425 When ``haveparents`` is false, the command MUST assume that the receiver
420 426 has no file revisions data. This means that all referenced file revisions
421 427 in the queried set of changeset revisions will be sent.
422 428
423 429 TODO we'll probably want a more complicated mechanism for the client to
424 430 specify which ancestor revisions are known.
431 TODO we may want to make linknodes an array so multiple changesets can be
432 marked as introducing a file revision, since this can occur with e.g. hidden
433 changesets.
425 434
426 435 heads
427 436 -----
428 437
429 438 Obtain DAG heads in the repository.
430 439
431 440 The command accepts the following arguments:
432 441
433 442 publiconly (optional)
434 443 (boolean) If set, operate on the DAG for public phase changesets only.
435 444 Non-public (i.e. draft) phase DAG heads will not be returned.
436 445
437 446 The response is a CBOR array of bytestrings defining changeset nodes
438 447 of DAG heads. The array can be empty if the repository is empty or no
439 448 changesets satisfied the request.
440 449
441 450 TODO consider exposing phase of heads in response
442 451
443 452 known
444 453 -----
445 454
446 455 Determine whether a series of changeset nodes is known to the server.
447 456
448 457 The command accepts the following arguments:
449 458
450 459 nodes
451 460 (array of bytestrings) List of changeset nodes whose presence to
452 461 query.
453 462
454 463 The response is a bytestring where each byte contains a 0 or 1 for the
455 464 corresponding requested node at the same index.
456 465
457 466 TODO use a bit array for even more compact response
458 467
459 468 listkeys
460 469 --------
461 470
462 471 List values in a specified ``pushkey`` namespace.
463 472
464 473 The command receives the following arguments:
465 474
466 475 namespace
467 476 (bytestring) Pushkey namespace to query.
468 477
469 478 The response is a map with bytestring keys and values.
470 479
471 480 TODO consider using binary to represent nodes in certain pushkey namespaces.
472 481
473 482 lookup
474 483 ------
475 484
476 485 Try to resolve a value to a changeset revision.
477 486
478 487 Unlike ``known`` which operates on changeset nodes, lookup operates on
479 488 node fragments and other names that a user may use.
480 489
481 490 The command receives the following arguments:
482 491
483 492 key
484 493 (bytestring) Value to try to resolve.
485 494
486 495 On success, returns a bytestring containing the resolved node.
487 496
488 497 manifestdata
489 498 ------------
490 499
491 500 Obtain various data related to manifests (which are lists of files in
492 501 a revision).
493 502
494 503 The command accepts the following arguments:
495 504
496 505 fields
497 506 (set of bytestring) Which data associated with manifests to fetch.
498 507 The following values are recognized:
499 508
500 509 parents
501 510 Parent nodes for the manifest.
502 511
503 512 revision
504 513 The raw revision data for the manifest.
505 514
506 515 haveparents
507 516 (bool) Whether the client has the parent revisions of all requested
508 517 nodes. If set, the server may emit revision data as deltas against
509 518 any parent revision. If not set, the server MUST only emit deltas for
510 519 revisions previously emitted by this command.
511 520
512 521 False is assumed in the absence of any value.
513 522
514 523 nodes
515 524 (array of bytestring) Manifest nodes whose data to retrieve.
516 525
517 526 tree
518 527 (bytestring) Path to manifest to retrieve. The empty bytestring represents
519 528 the root manifest. All other values represent directories/trees within
520 529 the repository.
521 530
522 531 TODO allow specifying revisions via alternate means (such as from changeset
523 532 revisions or ranges)
524 533 TODO consider recursive expansion of manifests (with path filtering for
525 534 narrow use cases)
526 535
527 536 The response bytestream starts with a CBOR map describing the data that
528 537 follows. It has the following bytestring keys:
529 538
530 539 totalitems
531 540 (unsigned integer) Total number of manifest revisions whose data is
532 541 being returned.
533 542
534 543 Following the map header is a series of 0 or more CBOR values. If values
535 544 are present, the first value will always be a map describing a single manifest
536 545 revision.
537 546
538 547 If the ``fieldsfollowing`` key is present, the map will immediately be followed
539 548 by N CBOR bytestring values, where N is the number of elements in
540 549 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
541 550 by ``fieldsfollowing``.
542 551
543 552 Following the optional bytestring field values is the next revision descriptor
544 553 map, or end of stream.
545 554
546 555 Each revision descriptor map has the following bytestring keys:
547 556
548 557 node
549 558 (bytestring) The node of the manifest revision whose data is represented.
550 559
551 560 deltabasenode
552 561 (bytestring) The node that the delta representation of this revision is
553 562 computed against. Only present if the ``revision`` field is requested and
554 563 a delta is being emitted.
555 564
556 565 fieldsfollowing
557 566 (array of 2-array) Denotes extra bytestring fields that following this map.
558 567 See the documentation for ``changesetdata`` for semantics.
559 568
560 569 The following named fields may be present:
561 570
562 571 ``delta``
563 572 The delta data to use to construct the fulltext revision.
564 573
565 574 Only present if the ``revision`` field is requested and a delta is
566 575 being emitted. The ``deltabasenode`` top-level key will also be
567 576 present if this field is being emitted.
568 577
569 578 ``revision``
570 579 The fulltext revision data for this manifest. Only present if the
571 580 ``revision`` field is requested and a fulltext revision is being emitted.
572 581
573 582 parents
574 583 (array of bytestring) The nodes of the parents of this manifest revision.
575 584 Only present if the ``parents`` field is requested.
576 585
577 586 When ``revision`` data is requested, the server chooses to emit either fulltext
578 587 revision data or a delta. What the server decides can be inferred by looking
579 588 for the presence of ``delta`` or ``revision`` in the ``fieldsfollowing`` array.
580 589
581 590 Servers MAY advertise the following extra fields in the capabilities
582 591 descriptor for this command:
583 592
584 593 recommendedbatchsize
585 594 (unsigned integer) Number of revisions the server recommends as a batch
586 595 query size. If defined, clients needing to issue multiple ``manifestdata``
587 596 commands to obtain needed data SHOULD construct their commands to have
588 597 this many revisions per request.
589 598
590 599 pushkey
591 600 -------
592 601
593 602 Set a value using the ``pushkey`` protocol.
594 603
595 604 The command receives the following arguments:
596 605
597 606 namespace
598 607 (bytestring) Pushkey namespace to operate on.
599 608 key
600 609 (bytestring) The pushkey key to set.
601 610 old
602 611 (bytestring) Old value for this key.
603 612 new
604 613 (bytestring) New value for this key.
605 614
606 615 TODO consider using binary to represent nodes is certain pushkey namespaces.
607 616 TODO better define response type and meaning.
608 617
609 618 rawstorefiledata
610 619 ----------------
611 620
612 621 Allows retrieving raw files used to store repository data.
613 622
614 623 The command accepts the following arguments:
615 624
616 625 files
617 626 (array of bytestring) Describes the files that should be retrieved.
618 627
619 628 The meaning of values in this array is dependent on the storage backend used
620 629 by the server.
621 630
622 631 The response bytestream starts with a CBOR map describing the data that follows.
623 632 This map has the following bytestring keys:
624 633
625 634 filecount
626 635 (unsigned integer) Total number of files whose data is being transferred.
627 636
628 637 totalsize
629 638 (unsigned integer) Total size in bytes of files data that will be
630 639 transferred. This is file on-disk size and not wire size.
631 640
632 641 Following the map header are N file segments. Each file segment consists of a
633 642 CBOR map followed by an indefinite length bytestring. Each map has the following
634 643 bytestring keys:
635 644
636 645 location
637 646 (bytestring) Denotes the location in the repository where the file should be
638 647 written. Values map to vfs instances to use for the writing.
639 648
640 649 path
641 650 (bytestring) Path of file being transferred. Path is the raw store
642 651 path and can be any sequence of bytes that can be tracked in a Mercurial
643 652 manifest.
644 653
645 654 size
646 655 (unsigned integer) Size of file data. This will be the final written
647 656 file size. The total size of the data that follows the CBOR map
648 657 will be greater due to encoding overhead of CBOR.
649 658
650 659 TODO this command is woefully incomplete. If we are to move forward with a
651 660 stream clone analog, it needs a lot more metadata around how to describe what
652 661 files are available to retrieve, other semantics.
653 662
654 663 Revision Specifiers
655 664 ===================
656 665
657 666 A *revision specifier* is a map that evaluates to a set of revisions.
658 667
659 668 A *revision specifier* has a ``type`` key that defines the revision
660 669 selection type to perform. Other keys in the map are used in a
661 670 type-specific manner.
662 671
663 672 The following types are defined:
664 673
665 674 changesetexplicit
666 675 An explicit set of enumerated changeset revisions.
667 676
668 677 The ``nodes`` key MUST contain an array of full binary nodes, expressed
669 678 as bytestrings.
670 679
671 680 changesetexplicitdepth
672 681 Like ``changesetexplicit``, but contains a ``depth`` key defining the
673 682 unsigned integer number of ancestor revisions to also resolve. For each
674 683 value in ``nodes``, DAG ancestors will be walked until up to N total
675 684 revisions from that ancestry walk are present in the final resolved set.
676 685
677 686 changesetdagrange
678 687 Defines revisions via a DAG range of changesets on the changelog.
679 688
680 689 The ``roots`` key MUST contain an array of full, binary node values
681 690 representing the *root* revisions.
682 691
683 692 The ``heads`` key MUST contain an array of full, binary nodes values
684 693 representing the *head* revisions.
685 694
686 695 The DAG range between ``roots`` and ``heads`` will be resolved and all
687 696 revisions between will be used. Nodes in ``roots`` are not part of the
688 697 resolved set. Nodes in ``heads`` are. The ``roots`` array may be empty.
689 698 The ``heads`` array MUST be defined.
690 699
691 700 Path Filters
692 701 ============
693 702
694 703 Various commands accept a *path filter* argument that defines the set of file
695 704 paths relevant to the request.
696 705
697 706 A *path filter* is defined as a map with the bytestring keys ``include`` and
698 707 ``exclude``. Each is an array of bytestring values. Each value defines a pattern
699 708 rule (see :hg:`help patterns`) that is used to match file paths.
700 709
701 710 A path matches the path filter if it is matched by a rule in the ``include``
702 711 set but doesn't match a rule in the ``exclude`` set. In other words, a path
703 712 matcher takes the union of all ``include`` patterns and then substracts the
704 713 union of all ``exclude`` patterns.
705 714
706 715 Patterns MUST be prefixed with their pattern type. Only the following pattern
707 716 types are allowed: ``path:``, ``rootfilesin:``.
708 717
709 718 If the ``include`` key is omitted, it is assumed that all paths are
710 719 relevant. The patterns from ``exclude`` will still be used, if defined.
711 720
712 721 An example value is ``path:tests/foo``, which would match a file named
713 722 ``tests/foo`` or a directory ``tests/foo`` and all files under it.
@@ -1,1448 +1,1460 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 9 import collections
10 10 import contextlib
11 11 import hashlib
12 12
13 13 from .i18n import _
14 14 from .node import (
15 15 hex,
16 16 nullid,
17 17 )
18 18 from . import (
19 19 discovery,
20 20 encoding,
21 21 error,
22 22 match as matchmod,
23 23 narrowspec,
24 24 pycompat,
25 25 streamclone,
26 26 util,
27 27 wireprotoframing,
28 28 wireprototypes,
29 29 )
30 30 from .utils import (
31 31 cborutil,
32 32 interfaceutil,
33 33 stringutil,
34 34 )
35 35
36 36 FRAMINGTYPE = b'application/mercurial-exp-framing-0006'
37 37
38 38 HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
39 39
40 40 COMMANDS = wireprototypes.commanddict()
41 41
42 42 # Value inserted into cache key computation function. Change the value to
43 43 # force new cache keys for every command request. This should be done when
44 44 # there is a change to how caching works, etc.
45 45 GLOBAL_CACHE_VERSION = 1
46 46
47 47 def handlehttpv2request(rctx, req, res, checkperm, urlparts):
48 48 from .hgweb import common as hgwebcommon
49 49
50 50 # URL space looks like: <permissions>/<command>, where <permission> can
51 51 # be ``ro`` or ``rw`` to signal read-only or read-write, respectively.
52 52
53 53 # Root URL does nothing meaningful... yet.
54 54 if not urlparts:
55 55 res.status = b'200 OK'
56 56 res.headers[b'Content-Type'] = b'text/plain'
57 57 res.setbodybytes(_('HTTP version 2 API handler'))
58 58 return
59 59
60 60 if len(urlparts) == 1:
61 61 res.status = b'404 Not Found'
62 62 res.headers[b'Content-Type'] = b'text/plain'
63 63 res.setbodybytes(_('do not know how to process %s\n') %
64 64 req.dispatchpath)
65 65 return
66 66
67 67 permission, command = urlparts[0:2]
68 68
69 69 if permission not in (b'ro', b'rw'):
70 70 res.status = b'404 Not Found'
71 71 res.headers[b'Content-Type'] = b'text/plain'
72 72 res.setbodybytes(_('unknown permission: %s') % permission)
73 73 return
74 74
75 75 if req.method != 'POST':
76 76 res.status = b'405 Method Not Allowed'
77 77 res.headers[b'Allow'] = b'POST'
78 78 res.setbodybytes(_('commands require POST requests'))
79 79 return
80 80
81 81 # At some point we'll want to use our own API instead of recycling the
82 82 # behavior of version 1 of the wire protocol...
83 83 # TODO return reasonable responses - not responses that overload the
84 84 # HTTP status line message for error reporting.
85 85 try:
86 86 checkperm(rctx, req, 'pull' if permission == b'ro' else 'push')
87 87 except hgwebcommon.ErrorResponse as e:
88 88 res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e))
89 89 for k, v in e.headers:
90 90 res.headers[k] = v
91 91 res.setbodybytes('permission denied')
92 92 return
93 93
94 94 # We have a special endpoint to reflect the request back at the client.
95 95 if command == b'debugreflect':
96 96 _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
97 97 return
98 98
99 99 # Extra commands that we handle that aren't really wire protocol
100 100 # commands. Think extra hard before making this hackery available to
101 101 # extension.
102 102 extracommands = {'multirequest'}
103 103
104 104 if command not in COMMANDS and command not in extracommands:
105 105 res.status = b'404 Not Found'
106 106 res.headers[b'Content-Type'] = b'text/plain'
107 107 res.setbodybytes(_('unknown wire protocol command: %s\n') % command)
108 108 return
109 109
110 110 repo = rctx.repo
111 111 ui = repo.ui
112 112
113 113 proto = httpv2protocolhandler(req, ui)
114 114
115 115 if (not COMMANDS.commandavailable(command, proto)
116 116 and command not in extracommands):
117 117 res.status = b'404 Not Found'
118 118 res.headers[b'Content-Type'] = b'text/plain'
119 119 res.setbodybytes(_('invalid wire protocol command: %s') % command)
120 120 return
121 121
122 122 # TODO consider cases where proxies may add additional Accept headers.
123 123 if req.headers.get(b'Accept') != FRAMINGTYPE:
124 124 res.status = b'406 Not Acceptable'
125 125 res.headers[b'Content-Type'] = b'text/plain'
126 126 res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
127 127 % FRAMINGTYPE)
128 128 return
129 129
130 130 if req.headers.get(b'Content-Type') != FRAMINGTYPE:
131 131 res.status = b'415 Unsupported Media Type'
132 132 # TODO we should send a response with appropriate media type,
133 133 # since client does Accept it.
134 134 res.headers[b'Content-Type'] = b'text/plain'
135 135 res.setbodybytes(_('client MUST send Content-Type header with '
136 136 'value: %s\n') % FRAMINGTYPE)
137 137 return
138 138
139 139 _processhttpv2request(ui, repo, req, res, permission, command, proto)
140 140
141 141 def _processhttpv2reflectrequest(ui, repo, req, res):
142 142 """Reads unified frame protocol request and dumps out state to client.
143 143
144 144 This special endpoint can be used to help debug the wire protocol.
145 145
146 146 Instead of routing the request through the normal dispatch mechanism,
147 147 we instead read all frames, decode them, and feed them into our state
148 148 tracker. We then dump the log of all that activity back out to the
149 149 client.
150 150 """
151 151 import json
152 152
153 153 # Reflection APIs have a history of being abused, accidentally disclosing
154 154 # sensitive data, etc. So we have a config knob.
155 155 if not ui.configbool('experimental', 'web.api.debugreflect'):
156 156 res.status = b'404 Not Found'
157 157 res.headers[b'Content-Type'] = b'text/plain'
158 158 res.setbodybytes(_('debugreflect service not available'))
159 159 return
160 160
161 161 # We assume we have a unified framing protocol request body.
162 162
163 163 reactor = wireprotoframing.serverreactor(ui)
164 164 states = []
165 165
166 166 while True:
167 167 frame = wireprotoframing.readframe(req.bodyfh)
168 168
169 169 if not frame:
170 170 states.append(b'received: <no frame>')
171 171 break
172 172
173 173 states.append(b'received: %d %d %d %s' % (frame.typeid, frame.flags,
174 174 frame.requestid,
175 175 frame.payload))
176 176
177 177 action, meta = reactor.onframerecv(frame)
178 178 states.append(json.dumps((action, meta), sort_keys=True,
179 179 separators=(', ', ': ')))
180 180
181 181 action, meta = reactor.oninputeof()
182 182 meta['action'] = action
183 183 states.append(json.dumps(meta, sort_keys=True, separators=(', ',': ')))
184 184
185 185 res.status = b'200 OK'
186 186 res.headers[b'Content-Type'] = b'text/plain'
187 187 res.setbodybytes(b'\n'.join(states))
188 188
189 189 def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
190 190 """Post-validation handler for HTTPv2 requests.
191 191
192 192 Called when the HTTP request contains unified frame-based protocol
193 193 frames for evaluation.
194 194 """
195 195 # TODO Some HTTP clients are full duplex and can receive data before
196 196 # the entire request is transmitted. Figure out a way to indicate support
197 197 # for that so we can opt into full duplex mode.
198 198 reactor = wireprotoframing.serverreactor(ui, deferoutput=True)
199 199 seencommand = False
200 200
201 201 outstream = None
202 202
203 203 while True:
204 204 frame = wireprotoframing.readframe(req.bodyfh)
205 205 if not frame:
206 206 break
207 207
208 208 action, meta = reactor.onframerecv(frame)
209 209
210 210 if action == 'wantframe':
211 211 # Need more data before we can do anything.
212 212 continue
213 213 elif action == 'runcommand':
214 214 # Defer creating output stream because we need to wait for
215 215 # protocol settings frames so proper encoding can be applied.
216 216 if not outstream:
217 217 outstream = reactor.makeoutputstream()
218 218
219 219 sentoutput = _httpv2runcommand(ui, repo, req, res, authedperm,
220 220 reqcommand, reactor, outstream,
221 221 meta, issubsequent=seencommand)
222 222
223 223 if sentoutput:
224 224 return
225 225
226 226 seencommand = True
227 227
228 228 elif action == 'error':
229 229 # TODO define proper error mechanism.
230 230 res.status = b'200 OK'
231 231 res.headers[b'Content-Type'] = b'text/plain'
232 232 res.setbodybytes(meta['message'] + b'\n')
233 233 return
234 234 else:
235 235 raise error.ProgrammingError(
236 236 'unhandled action from frame processor: %s' % action)
237 237
238 238 action, meta = reactor.oninputeof()
239 239 if action == 'sendframes':
240 240 # We assume we haven't started sending the response yet. If we're
241 241 # wrong, the response type will raise an exception.
242 242 res.status = b'200 OK'
243 243 res.headers[b'Content-Type'] = FRAMINGTYPE
244 244 res.setbodygen(meta['framegen'])
245 245 elif action == 'noop':
246 246 pass
247 247 else:
248 248 raise error.ProgrammingError('unhandled action from frame processor: %s'
249 249 % action)
250 250
251 251 def _httpv2runcommand(ui, repo, req, res, authedperm, reqcommand, reactor,
252 252 outstream, command, issubsequent):
253 253 """Dispatch a wire protocol command made from HTTPv2 requests.
254 254
255 255 The authenticated permission (``authedperm``) along with the original
256 256 command from the URL (``reqcommand``) are passed in.
257 257 """
258 258 # We already validated that the session has permissions to perform the
259 259 # actions in ``authedperm``. In the unified frame protocol, the canonical
260 260 # command to run is expressed in a frame. However, the URL also requested
261 261 # to run a specific command. We need to be careful that the command we
262 262 # run doesn't have permissions requirements greater than what was granted
263 263 # by ``authedperm``.
264 264 #
265 265 # Our rule for this is we only allow one command per HTTP request and
266 266 # that command must match the command in the URL. However, we make
267 267 # an exception for the ``multirequest`` URL. This URL is allowed to
268 268 # execute multiple commands. We double check permissions of each command
269 269 # as it is invoked to ensure there is no privilege escalation.
270 270 # TODO consider allowing multiple commands to regular command URLs
271 271 # iff each command is the same.
272 272
273 273 proto = httpv2protocolhandler(req, ui, args=command['args'])
274 274
275 275 if reqcommand == b'multirequest':
276 276 if not COMMANDS.commandavailable(command['command'], proto):
277 277 # TODO proper error mechanism
278 278 res.status = b'200 OK'
279 279 res.headers[b'Content-Type'] = b'text/plain'
280 280 res.setbodybytes(_('wire protocol command not available: %s') %
281 281 command['command'])
282 282 return True
283 283
284 284 # TODO don't use assert here, since it may be elided by -O.
285 285 assert authedperm in (b'ro', b'rw')
286 286 wirecommand = COMMANDS[command['command']]
287 287 assert wirecommand.permission in ('push', 'pull')
288 288
289 289 if authedperm == b'ro' and wirecommand.permission != 'pull':
290 290 # TODO proper error mechanism
291 291 res.status = b'403 Forbidden'
292 292 res.headers[b'Content-Type'] = b'text/plain'
293 293 res.setbodybytes(_('insufficient permissions to execute '
294 294 'command: %s') % command['command'])
295 295 return True
296 296
297 297 # TODO should we also call checkperm() here? Maybe not if we're going
298 298 # to overhaul that API. The granted scope from the URL check should
299 299 # be good enough.
300 300
301 301 else:
302 302 # Don't allow multiple commands outside of ``multirequest`` URL.
303 303 if issubsequent:
304 304 # TODO proper error mechanism
305 305 res.status = b'200 OK'
306 306 res.headers[b'Content-Type'] = b'text/plain'
307 307 res.setbodybytes(_('multiple commands cannot be issued to this '
308 308 'URL'))
309 309 return True
310 310
311 311 if reqcommand != command['command']:
312 312 # TODO define proper error mechanism
313 313 res.status = b'200 OK'
314 314 res.headers[b'Content-Type'] = b'text/plain'
315 315 res.setbodybytes(_('command in frame must match command in URL'))
316 316 return True
317 317
318 318 res.status = b'200 OK'
319 319 res.headers[b'Content-Type'] = FRAMINGTYPE
320 320
321 321 try:
322 322 objs = dispatch(repo, proto, command['command'], command['redirect'])
323 323
324 324 action, meta = reactor.oncommandresponsereadyobjects(
325 325 outstream, command['requestid'], objs)
326 326
327 327 except error.WireprotoCommandError as e:
328 328 action, meta = reactor.oncommanderror(
329 329 outstream, command['requestid'], e.message, e.messageargs)
330 330
331 331 except Exception as e:
332 332 action, meta = reactor.onservererror(
333 333 outstream, command['requestid'],
334 334 _('exception when invoking command: %s') %
335 335 stringutil.forcebytestr(e))
336 336
337 337 if action == 'sendframes':
338 338 res.setbodygen(meta['framegen'])
339 339 return True
340 340 elif action == 'noop':
341 341 return False
342 342 else:
343 343 raise error.ProgrammingError('unhandled event from reactor: %s' %
344 344 action)
345 345
346 346 def getdispatchrepo(repo, proto, command):
347 347 return repo.filtered('served')
348 348
349 349 def dispatch(repo, proto, command, redirect):
350 350 """Run a wire protocol command.
351 351
352 352 Returns an iterable of objects that will be sent to the client.
353 353 """
354 354 repo = getdispatchrepo(repo, proto, command)
355 355
356 356 entry = COMMANDS[command]
357 357 func = entry.func
358 358 spec = entry.args
359 359
360 360 args = proto.getargs(spec)
361 361
362 362 # There is some duplicate boilerplate code here for calling the command and
363 363 # emitting objects. It is either that or a lot of indented code that looks
364 364 # like a pyramid (since there are a lot of code paths that result in not
365 365 # using the cacher).
366 366 callcommand = lambda: func(repo, proto, **pycompat.strkwargs(args))
367 367
368 368 # Request is not cacheable. Don't bother instantiating a cacher.
369 369 if not entry.cachekeyfn:
370 370 for o in callcommand():
371 371 yield o
372 372 return
373 373
374 374 if redirect:
375 375 redirecttargets = redirect[b'targets']
376 376 redirecthashes = redirect[b'hashes']
377 377 else:
378 378 redirecttargets = []
379 379 redirecthashes = []
380 380
381 381 cacher = makeresponsecacher(repo, proto, command, args,
382 382 cborutil.streamencode,
383 383 redirecttargets=redirecttargets,
384 384 redirecthashes=redirecthashes)
385 385
386 386 # But we have no cacher. Do default handling.
387 387 if not cacher:
388 388 for o in callcommand():
389 389 yield o
390 390 return
391 391
392 392 with cacher:
393 393 cachekey = entry.cachekeyfn(repo, proto, cacher, **args)
394 394
395 395 # No cache key or the cacher doesn't like it. Do default handling.
396 396 if cachekey is None or not cacher.setcachekey(cachekey):
397 397 for o in callcommand():
398 398 yield o
399 399 return
400 400
401 401 # Serve it from the cache, if possible.
402 402 cached = cacher.lookup()
403 403
404 404 if cached:
405 405 for o in cached['objs']:
406 406 yield o
407 407 return
408 408
409 409 # Else call the command and feed its output into the cacher, allowing
410 410 # the cacher to buffer/mutate objects as it desires.
411 411 for o in callcommand():
412 412 for o in cacher.onobject(o):
413 413 yield o
414 414
415 415 for o in cacher.onfinished():
416 416 yield o
417 417
418 418 @interfaceutil.implementer(wireprototypes.baseprotocolhandler)
419 419 class httpv2protocolhandler(object):
420 420 def __init__(self, req, ui, args=None):
421 421 self._req = req
422 422 self._ui = ui
423 423 self._args = args
424 424
425 425 @property
426 426 def name(self):
427 427 return HTTP_WIREPROTO_V2
428 428
429 429 def getargs(self, args):
430 430 # First look for args that were passed but aren't registered on this
431 431 # command.
432 432 extra = set(self._args) - set(args)
433 433 if extra:
434 434 raise error.WireprotoCommandError(
435 435 'unsupported argument to command: %s' %
436 436 ', '.join(sorted(extra)))
437 437
438 438 # And look for required arguments that are missing.
439 439 missing = {a for a in args if args[a]['required']} - set(self._args)
440 440
441 441 if missing:
442 442 raise error.WireprotoCommandError(
443 443 'missing required arguments: %s' % ', '.join(sorted(missing)))
444 444
445 445 # Now derive the arguments to pass to the command, taking into
446 446 # account the arguments specified by the client.
447 447 data = {}
448 448 for k, meta in sorted(args.items()):
449 449 # This argument wasn't passed by the client.
450 450 if k not in self._args:
451 451 data[k] = meta['default']()
452 452 continue
453 453
454 454 v = self._args[k]
455 455
456 456 # Sets may be expressed as lists. Silently normalize.
457 457 if meta['type'] == 'set' and isinstance(v, list):
458 458 v = set(v)
459 459
460 460 # TODO consider more/stronger type validation.
461 461
462 462 data[k] = v
463 463
464 464 return data
465 465
466 466 def getprotocaps(self):
467 467 # Protocol capabilities are currently not implemented for HTTP V2.
468 468 return set()
469 469
470 470 def getpayload(self):
471 471 raise NotImplementedError
472 472
473 473 @contextlib.contextmanager
474 474 def mayberedirectstdio(self):
475 475 raise NotImplementedError
476 476
477 477 def client(self):
478 478 raise NotImplementedError
479 479
480 480 def addcapabilities(self, repo, caps):
481 481 return caps
482 482
483 483 def checkperm(self, perm):
484 484 raise NotImplementedError
485 485
486 486 def httpv2apidescriptor(req, repo):
487 487 proto = httpv2protocolhandler(req, repo.ui)
488 488
489 489 return _capabilitiesv2(repo, proto)
490 490
491 491 def _capabilitiesv2(repo, proto):
492 492 """Obtain the set of capabilities for version 2 transports.
493 493
494 494 These capabilities are distinct from the capabilities for version 1
495 495 transports.
496 496 """
497 497 caps = {
498 498 'commands': {},
499 499 'framingmediatypes': [FRAMINGTYPE],
500 500 'pathfilterprefixes': set(narrowspec.VALID_PREFIXES),
501 501 }
502 502
503 503 for command, entry in COMMANDS.items():
504 504 args = {}
505 505
506 506 for arg, meta in entry.args.items():
507 507 args[arg] = {
508 508 # TODO should this be a normalized type using CBOR's
509 509 # terminology?
510 510 b'type': meta['type'],
511 511 b'required': meta['required'],
512 512 }
513 513
514 514 if not meta['required']:
515 515 args[arg][b'default'] = meta['default']()
516 516
517 517 if meta['validvalues']:
518 518 args[arg][b'validvalues'] = meta['validvalues']
519 519
520 520 # TODO this type of check should be defined in a per-command callback.
521 521 if (command == b'rawstorefiledata'
522 522 and not streamclone.allowservergeneration(repo)):
523 523 continue
524 524
525 525 caps['commands'][command] = {
526 526 'args': args,
527 527 'permissions': [entry.permission],
528 528 }
529 529
530 530 if entry.extracapabilitiesfn:
531 531 extracaps = entry.extracapabilitiesfn(repo, proto)
532 532 caps['commands'][command].update(extracaps)
533 533
534 534 caps['rawrepoformats'] = sorted(repo.requirements &
535 535 repo.supportedformats)
536 536
537 537 targets = getadvertisedredirecttargets(repo, proto)
538 538 if targets:
539 539 caps[b'redirect'] = {
540 540 b'targets': [],
541 541 b'hashes': [b'sha256', b'sha1'],
542 542 }
543 543
544 544 for target in targets:
545 545 entry = {
546 546 b'name': target['name'],
547 547 b'protocol': target['protocol'],
548 548 b'uris': target['uris'],
549 549 }
550 550
551 551 for key in ('snirequired', 'tlsversions'):
552 552 if key in target:
553 553 entry[key] = target[key]
554 554
555 555 caps[b'redirect'][b'targets'].append(entry)
556 556
557 557 return proto.addcapabilities(repo, caps)
558 558
559 559 def getadvertisedredirecttargets(repo, proto):
560 560 """Obtain a list of content redirect targets.
561 561
562 562 Returns a list containing potential redirect targets that will be
563 563 advertised in capabilities data. Each dict MUST have the following
564 564 keys:
565 565
566 566 name
567 567 The name of this redirect target. This is the identifier clients use
568 568 to refer to a target. It is transferred as part of every command
569 569 request.
570 570
571 571 protocol
572 572 Network protocol used by this target. Typically this is the string
573 573 in front of the ``://`` in a URL. e.g. ``https``.
574 574
575 575 uris
576 576 List of representative URIs for this target. Clients can use the
577 577 URIs to test parsing for compatibility or for ordering preference
578 578 for which target to use.
579 579
580 580 The following optional keys are recognized:
581 581
582 582 snirequired
583 583 Bool indicating if Server Name Indication (SNI) is required to
584 584 connect to this target.
585 585
586 586 tlsversions
587 587 List of bytes indicating which TLS versions are supported by this
588 588 target.
589 589
590 590 By default, clients reflect the target order advertised by servers
591 591 and servers will use the first client-advertised target when picking
592 592 a redirect target. So targets should be advertised in the order the
593 593 server prefers they be used.
594 594 """
595 595 return []
596 596
597 597 def wireprotocommand(name, args=None, permission='push', cachekeyfn=None,
598 598 extracapabilitiesfn=None):
599 599 """Decorator to declare a wire protocol command.
600 600
601 601 ``name`` is the name of the wire protocol command being provided.
602 602
603 603 ``args`` is a dict defining arguments accepted by the command. Keys are
604 604 the argument name. Values are dicts with the following keys:
605 605
606 606 ``type``
607 607 The argument data type. Must be one of the following string
608 608 literals: ``bytes``, ``int``, ``list``, ``dict``, ``set``,
609 609 or ``bool``.
610 610
611 611 ``default``
612 612 A callable returning the default value for this argument. If not
613 613 specified, ``None`` will be the default value.
614 614
615 615 ``example``
616 616 An example value for this argument.
617 617
618 618 ``validvalues``
619 619 Set of recognized values for this argument.
620 620
621 621 ``permission`` defines the permission type needed to run this command.
622 622 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
623 623 respectively. Default is to assume command requires ``push`` permissions
624 624 because otherwise commands not declaring their permissions could modify
625 625 a repository that is supposed to be read-only.
626 626
627 627 ``cachekeyfn`` defines an optional callable that can derive the
628 628 cache key for this request.
629 629
630 630 ``extracapabilitiesfn`` defines an optional callable that defines extra
631 631 command capabilities/parameters that are advertised next to the command
632 632 in the capabilities data structure describing the server. The callable
633 633 receives as arguments the repository and protocol objects. It returns
634 634 a dict of extra fields to add to the command descriptor.
635 635
636 636 Wire protocol commands are generators of objects to be serialized and
637 637 sent to the client.
638 638
639 639 If a command raises an uncaught exception, this will be translated into
640 640 a command error.
641 641
642 642 All commands can opt in to being cacheable by defining a function
643 643 (``cachekeyfn``) that is called to derive a cache key. This function
644 644 receives the same arguments as the command itself plus a ``cacher``
645 645 argument containing the active cacher for the request and returns a bytes
646 646 containing the key in a cache the response to this command may be cached
647 647 under.
648 648 """
649 649 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
650 650 if v['version'] == 2}
651 651
652 652 if permission not in ('push', 'pull'):
653 653 raise error.ProgrammingError('invalid wire protocol permission; '
654 654 'got %s; expected "push" or "pull"' %
655 655 permission)
656 656
657 657 if args is None:
658 658 args = {}
659 659
660 660 if not isinstance(args, dict):
661 661 raise error.ProgrammingError('arguments for version 2 commands '
662 662 'must be declared as dicts')
663 663
664 664 for arg, meta in args.items():
665 665 if arg == '*':
666 666 raise error.ProgrammingError('* argument name not allowed on '
667 667 'version 2 commands')
668 668
669 669 if not isinstance(meta, dict):
670 670 raise error.ProgrammingError('arguments for version 2 commands '
671 671 'must declare metadata as a dict')
672 672
673 673 if 'type' not in meta:
674 674 raise error.ProgrammingError('%s argument for command %s does not '
675 675 'declare type field' % (arg, name))
676 676
677 677 if meta['type'] not in ('bytes', 'int', 'list', 'dict', 'set', 'bool'):
678 678 raise error.ProgrammingError('%s argument for command %s has '
679 679 'illegal type: %s' % (arg, name,
680 680 meta['type']))
681 681
682 682 if 'example' not in meta:
683 683 raise error.ProgrammingError('%s argument for command %s does not '
684 684 'declare example field' % (arg, name))
685 685
686 686 meta['required'] = 'default' not in meta
687 687
688 688 meta.setdefault('default', lambda: None)
689 689 meta.setdefault('validvalues', None)
690 690
691 691 def register(func):
692 692 if name in COMMANDS:
693 693 raise error.ProgrammingError('%s command already registered '
694 694 'for version 2' % name)
695 695
696 696 COMMANDS[name] = wireprototypes.commandentry(
697 697 func, args=args, transports=transports, permission=permission,
698 698 cachekeyfn=cachekeyfn, extracapabilitiesfn=extracapabilitiesfn)
699 699
700 700 return func
701 701
702 702 return register
703 703
704 704 def makecommandcachekeyfn(command, localversion=None, allargs=False):
705 705 """Construct a cache key derivation function with common features.
706 706
707 707 By default, the cache key is a hash of:
708 708
709 709 * The command name.
710 710 * A global cache version number.
711 711 * A local cache version number (passed via ``localversion``).
712 712 * All the arguments passed to the command.
713 713 * The media type used.
714 714 * Wire protocol version string.
715 715 * The repository path.
716 716 """
717 717 if not allargs:
718 718 raise error.ProgrammingError('only allargs=True is currently supported')
719 719
720 720 if localversion is None:
721 721 raise error.ProgrammingError('must set localversion argument value')
722 722
723 723 def cachekeyfn(repo, proto, cacher, **args):
724 724 spec = COMMANDS[command]
725 725
726 726 # Commands that mutate the repo can not be cached.
727 727 if spec.permission == 'push':
728 728 return None
729 729
730 730 # TODO config option to disable caching.
731 731
732 732 # Our key derivation strategy is to construct a data structure
733 733 # holding everything that could influence cacheability and to hash
734 734 # the CBOR representation of that. Using CBOR seems like it might
735 735 # be overkill. However, simpler hashing mechanisms are prone to
736 736 # duplicate input issues. e.g. if you just concatenate two values,
737 737 # "foo"+"bar" is identical to "fo"+"obar". Using CBOR provides
738 738 # "padding" between values and prevents these problems.
739 739
740 740 # Seed the hash with various data.
741 741 state = {
742 742 # To invalidate all cache keys.
743 743 b'globalversion': GLOBAL_CACHE_VERSION,
744 744 # More granular cache key invalidation.
745 745 b'localversion': localversion,
746 746 # Cache keys are segmented by command.
747 747 b'command': pycompat.sysbytes(command),
748 748 # Throw in the media type and API version strings so changes
749 749 # to exchange semantics invalid cache.
750 750 b'mediatype': FRAMINGTYPE,
751 751 b'version': HTTP_WIREPROTO_V2,
752 752 # So same requests for different repos don't share cache keys.
753 753 b'repo': repo.root,
754 754 }
755 755
756 756 # The arguments passed to us will have already been normalized.
757 757 # Default values will be set, etc. This is important because it
758 758 # means that it doesn't matter if clients send an explicit argument
759 759 # or rely on the default value: it will all normalize to the same
760 760 # set of arguments on the server and therefore the same cache key.
761 761 #
762 762 # Arguments by their very nature must support being encoded to CBOR.
763 763 # And the CBOR encoder is deterministic. So we hash the arguments
764 764 # by feeding the CBOR of their representation into the hasher.
765 765 if allargs:
766 766 state[b'args'] = pycompat.byteskwargs(args)
767 767
768 768 cacher.adjustcachekeystate(state)
769 769
770 770 hasher = hashlib.sha1()
771 771 for chunk in cborutil.streamencode(state):
772 772 hasher.update(chunk)
773 773
774 774 return pycompat.sysbytes(hasher.hexdigest())
775 775
776 776 return cachekeyfn
777 777
778 778 def makeresponsecacher(repo, proto, command, args, objencoderfn,
779 779 redirecttargets, redirecthashes):
780 780 """Construct a cacher for a cacheable command.
781 781
782 782 Returns an ``iwireprotocolcommandcacher`` instance.
783 783
784 784 Extensions can monkeypatch this function to provide custom caching
785 785 backends.
786 786 """
787 787 return None
788 788
789 789 def resolvenodes(repo, revisions):
790 790 """Resolve nodes from a revisions specifier data structure."""
791 791 cl = repo.changelog
792 792 clhasnode = cl.hasnode
793 793
794 794 seen = set()
795 795 nodes = []
796 796
797 797 if not isinstance(revisions, list):
798 798 raise error.WireprotoCommandError('revisions must be defined as an '
799 799 'array')
800 800
801 801 for spec in revisions:
802 802 if b'type' not in spec:
803 803 raise error.WireprotoCommandError(
804 804 'type key not present in revision specifier')
805 805
806 806 typ = spec[b'type']
807 807
808 808 if typ == b'changesetexplicit':
809 809 if b'nodes' not in spec:
810 810 raise error.WireprotoCommandError(
811 811 'nodes key not present in changesetexplicit revision '
812 812 'specifier')
813 813
814 814 for node in spec[b'nodes']:
815 815 if node not in seen:
816 816 nodes.append(node)
817 817 seen.add(node)
818 818
819 819 elif typ == b'changesetexplicitdepth':
820 820 for key in (b'nodes', b'depth'):
821 821 if key not in spec:
822 822 raise error.WireprotoCommandError(
823 823 '%s key not present in changesetexplicitdepth revision '
824 824 'specifier', (key,))
825 825
826 826 for rev in repo.revs(b'ancestors(%ln, %d)', spec[b'nodes'],
827 827 spec[b'depth'] - 1):
828 828 node = cl.node(rev)
829 829
830 830 if node not in seen:
831 831 nodes.append(node)
832 832 seen.add(node)
833 833
834 834 elif typ == b'changesetdagrange':
835 835 for key in (b'roots', b'heads'):
836 836 if key not in spec:
837 837 raise error.WireprotoCommandError(
838 838 '%s key not present in changesetdagrange revision '
839 839 'specifier', (key,))
840 840
841 841 if not spec[b'heads']:
842 842 raise error.WireprotoCommandError(
843 843 'heads key in changesetdagrange cannot be empty')
844 844
845 845 if spec[b'roots']:
846 846 common = [n for n in spec[b'roots'] if clhasnode(n)]
847 847 else:
848 848 common = [nullid]
849 849
850 850 for n in discovery.outgoing(repo, common, spec[b'heads']).missing:
851 851 if n not in seen:
852 852 nodes.append(n)
853 853 seen.add(n)
854 854
855 855 else:
856 856 raise error.WireprotoCommandError(
857 857 'unknown revision specifier type: %s', (typ,))
858 858
859 859 return nodes
860 860
861 861 @wireprotocommand('branchmap', permission='pull')
862 862 def branchmapv2(repo, proto):
863 863 yield {encoding.fromlocal(k): v
864 864 for k, v in repo.branchmap().iteritems()}
865 865
866 866 @wireprotocommand('capabilities', permission='pull')
867 867 def capabilitiesv2(repo, proto):
868 868 yield _capabilitiesv2(repo, proto)
869 869
870 870 @wireprotocommand(
871 871 'changesetdata',
872 872 args={
873 873 'revisions': {
874 874 'type': 'list',
875 875 'example': [{
876 876 b'type': b'changesetexplicit',
877 877 b'nodes': [b'abcdef...'],
878 878 }],
879 879 },
880 880 'fields': {
881 881 'type': 'set',
882 882 'default': set,
883 883 'example': {b'parents', b'revision'},
884 884 'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
885 885 },
886 886 },
887 887 permission='pull')
888 888 def changesetdata(repo, proto, revisions, fields):
889 889 # TODO look for unknown fields and abort when they can't be serviced.
890 890 # This could probably be validated by dispatcher using validvalues.
891 891
892 892 cl = repo.changelog
893 893 outgoing = resolvenodes(repo, revisions)
894 894 publishing = repo.publishing()
895 895
896 896 if outgoing:
897 897 repo.hook('preoutgoing', throw=True, source='serve')
898 898
899 899 yield {
900 900 b'totalitems': len(outgoing),
901 901 }
902 902
903 903 # The phases of nodes already transferred to the client may have changed
904 904 # since the client last requested data. We send phase-only records
905 905 # for these revisions, if requested.
906 906 # TODO actually do this. We'll probably want to emit phase heads
907 907 # in the ancestry set of the outgoing revisions. This will ensure
908 908 # that phase updates within that set are seen.
909 909 if b'phase' in fields:
910 910 pass
911 911
912 912 nodebookmarks = {}
913 913 for mark, node in repo._bookmarks.items():
914 914 nodebookmarks.setdefault(node, set()).add(mark)
915 915
916 916 # It is already topologically sorted by revision number.
917 917 for node in outgoing:
918 918 d = {
919 919 b'node': node,
920 920 }
921 921
922 922 if b'parents' in fields:
923 923 d[b'parents'] = cl.parents(node)
924 924
925 925 if b'phase' in fields:
926 926 if publishing:
927 927 d[b'phase'] = b'public'
928 928 else:
929 929 ctx = repo[node]
930 930 d[b'phase'] = ctx.phasestr()
931 931
932 932 if b'bookmarks' in fields and node in nodebookmarks:
933 933 d[b'bookmarks'] = sorted(nodebookmarks[node])
934 934 del nodebookmarks[node]
935 935
936 936 followingmeta = []
937 937 followingdata = []
938 938
939 939 if b'revision' in fields:
940 940 revisiondata = cl.revision(node, raw=True)
941 941 followingmeta.append((b'revision', len(revisiondata)))
942 942 followingdata.append(revisiondata)
943 943
944 944 # TODO make it possible for extensions to wrap a function or register
945 945 # a handler to service custom fields.
946 946
947 947 if followingmeta:
948 948 d[b'fieldsfollowing'] = followingmeta
949 949
950 950 yield d
951 951
952 952 for extra in followingdata:
953 953 yield extra
954 954
955 955 # If requested, send bookmarks from nodes that didn't have revision
956 956 # data sent so receiver is aware of any bookmark updates.
957 957 if b'bookmarks' in fields:
958 958 for node, marks in sorted(nodebookmarks.iteritems()):
959 959 yield {
960 960 b'node': node,
961 961 b'bookmarks': sorted(marks),
962 962 }
963 963
964 964 class FileAccessError(Exception):
965 965 """Represents an error accessing a specific file."""
966 966
967 967 def __init__(self, path, msg, args):
968 968 self.path = path
969 969 self.msg = msg
970 970 self.args = args
971 971
972 972 def getfilestore(repo, proto, path):
973 973 """Obtain a file storage object for use with wire protocol.
974 974
975 975 Exists as a standalone function so extensions can monkeypatch to add
976 976 access control.
977 977 """
978 978 # This seems to work even if the file doesn't exist. So catch
979 979 # "empty" files and return an error.
980 980 fl = repo.file(path)
981 981
982 982 if not len(fl):
983 983 raise FileAccessError(path, 'unknown file: %s', (path,))
984 984
985 985 return fl
986 986
987 def emitfilerevisions(revisions, fields):
987 def emitfilerevisions(repo, path, revisions, fields):
988 clnode = repo.changelog.node
989
988 990 for revision in revisions:
989 991 d = {
990 992 b'node': revision.node,
991 993 }
992 994
993 995 if b'parents' in fields:
994 996 d[b'parents'] = [revision.p1node, revision.p2node]
995 997
998 if b'linknode' in fields:
999 # TODO by creating the filectx against a specific file revision
1000 # instead of changeset, linkrev() is always used. This is wrong for
1001 # cases where linkrev() may refer to a hidden changeset. We need an
1002 # API for performing linkrev adjustment that takes this into
1003 # account.
1004 fctx = repo.filectx(path, fileid=revision.node)
1005 d[b'linknode'] = clnode(fctx.introrev())
1006
996 1007 followingmeta = []
997 1008 followingdata = []
998 1009
999 1010 if b'revision' in fields:
1000 1011 if revision.revision is not None:
1001 1012 followingmeta.append((b'revision', len(revision.revision)))
1002 1013 followingdata.append(revision.revision)
1003 1014 else:
1004 1015 d[b'deltabasenode'] = revision.basenode
1005 1016 followingmeta.append((b'delta', len(revision.delta)))
1006 1017 followingdata.append(revision.delta)
1007 1018
1008 1019 if followingmeta:
1009 1020 d[b'fieldsfollowing'] = followingmeta
1010 1021
1011 1022 yield d
1012 1023
1013 1024 for extra in followingdata:
1014 1025 yield extra
1015 1026
1016 1027 def makefilematcher(repo, pathfilter):
1017 1028 """Construct a matcher from a path filter dict."""
1018 1029
1019 1030 # Validate values.
1020 1031 if pathfilter:
1021 1032 for key in (b'include', b'exclude'):
1022 1033 for pattern in pathfilter.get(key, []):
1023 1034 if not pattern.startswith((b'path:', b'rootfilesin:')):
1024 1035 raise error.WireprotoCommandError(
1025 1036 '%s pattern must begin with `path:` or `rootfilesin:`; '
1026 1037 'got %s', (key, pattern))
1027 1038
1028 1039 if pathfilter:
1029 1040 matcher = matchmod.match(repo.root, b'',
1030 1041 include=pathfilter.get(b'include', []),
1031 1042 exclude=pathfilter.get(b'exclude', []))
1032 1043 else:
1033 1044 matcher = matchmod.match(repo.root, b'')
1034 1045
1035 1046 # Requested patterns could include files not in the local store. So
1036 1047 # filter those out.
1037 1048 return matchmod.intersectmatchers(repo.narrowmatch(), matcher)
1038 1049
1039 1050 @wireprotocommand(
1040 1051 'filedata',
1041 1052 args={
1042 1053 'haveparents': {
1043 1054 'type': 'bool',
1044 1055 'default': lambda: False,
1045 1056 'example': True,
1046 1057 },
1047 1058 'nodes': {
1048 1059 'type': 'list',
1049 1060 'example': [b'0123456...'],
1050 1061 },
1051 1062 'fields': {
1052 1063 'type': 'set',
1053 1064 'default': set,
1054 1065 'example': {b'parents', b'revision'},
1055 'validvalues': {b'parents', b'revision'},
1066 'validvalues': {b'parents', b'revision', b'linknode'},
1056 1067 },
1057 1068 'path': {
1058 1069 'type': 'bytes',
1059 1070 'example': b'foo.txt',
1060 1071 }
1061 1072 },
1062 1073 permission='pull',
1063 1074 # TODO censoring a file revision won't invalidate the cache.
1064 1075 # Figure out a way to take censoring into account when deriving
1065 1076 # the cache key.
1066 1077 cachekeyfn=makecommandcachekeyfn('filedata', 1, allargs=True))
1067 1078 def filedata(repo, proto, haveparents, nodes, fields, path):
1068 1079 # TODO this API allows access to file revisions that are attached to
1069 1080 # secret changesets. filesdata does not have this problem. Maybe this
1070 1081 # API should be deleted?
1071 1082
1072 1083 try:
1073 1084 # Extensions may wish to access the protocol handler.
1074 1085 store = getfilestore(repo, proto, path)
1075 1086 except FileAccessError as e:
1076 1087 raise error.WireprotoCommandError(e.msg, e.args)
1077 1088
1078 1089 # Validate requested nodes.
1079 1090 for node in nodes:
1080 1091 try:
1081 1092 store.rev(node)
1082 1093 except error.LookupError:
1083 1094 raise error.WireprotoCommandError('unknown file node: %s',
1084 1095 (hex(node),))
1085 1096
1086 1097 revisions = store.emitrevisions(nodes,
1087 1098 revisiondata=b'revision' in fields,
1088 1099 assumehaveparentrevisions=haveparents)
1089 1100
1090 1101 yield {
1091 1102 b'totalitems': len(nodes),
1092 1103 }
1093 1104
1094 for o in emitfilerevisions(revisions, fields):
1105 for o in emitfilerevisions(repo, path, revisions, fields):
1095 1106 yield o
1096 1107
1097 1108 def filesdatacapabilities(repo, proto):
1098 1109 batchsize = repo.ui.configint(
1099 1110 b'experimental', b'server.filesdata.recommended-batch-size')
1100 1111 return {
1101 1112 b'recommendedbatchsize': batchsize,
1102 1113 }
1103 1114
1104 1115 @wireprotocommand(
1105 1116 'filesdata',
1106 1117 args={
1107 1118 'haveparents': {
1108 1119 'type': 'bool',
1109 1120 'default': lambda: False,
1110 1121 'example': True,
1111 1122 },
1112 1123 'fields': {
1113 1124 'type': 'set',
1114 1125 'default': set,
1115 1126 'example': {b'parents', b'revision'},
1116 'validvalues': {b'firstchangeset', b'parents', b'revision'},
1127 'validvalues': {b'firstchangeset', b'linknode', b'parents',
1128 b'revision'},
1117 1129 },
1118 1130 'pathfilter': {
1119 1131 'type': 'dict',
1120 1132 'default': lambda: None,
1121 1133 'example': {b'include': [b'path:tests']},
1122 1134 },
1123 1135 'revisions': {
1124 1136 'type': 'list',
1125 1137 'example': [{
1126 1138 b'type': b'changesetexplicit',
1127 1139 b'nodes': [b'abcdef...'],
1128 1140 }],
1129 1141 },
1130 1142 },
1131 1143 permission='pull',
1132 1144 # TODO censoring a file revision won't invalidate the cache.
1133 1145 # Figure out a way to take censoring into account when deriving
1134 1146 # the cache key.
1135 1147 cachekeyfn=makecommandcachekeyfn('filesdata', 1, allargs=True),
1136 1148 extracapabilitiesfn=filesdatacapabilities)
1137 1149 def filesdata(repo, proto, haveparents, fields, pathfilter, revisions):
1138 1150 # TODO This should operate on a repo that exposes obsolete changesets. There
1139 1151 # is a race between a client making a push that obsoletes a changeset and
1140 1152 # another client fetching files data for that changeset. If a client has a
1141 1153 # changeset, it should probably be allowed to access files data for that
1142 1154 # changeset.
1143 1155
1144 1156 cl = repo.changelog
1145 1157 outgoing = resolvenodes(repo, revisions)
1146 1158 filematcher = makefilematcher(repo, pathfilter)
1147 1159
1148 1160 # Figure out what needs to be emitted.
1149 1161 changedpaths = set()
1150 1162 fnodes = collections.defaultdict(set)
1151 1163
1152 1164 for node in outgoing:
1153 1165 ctx = repo[node]
1154 1166 changedpaths.update(ctx.files())
1155 1167
1156 1168 changedpaths = sorted(p for p in changedpaths if filematcher(p))
1157 1169
1158 1170 # If ancestors are known, we send file revisions having a linkrev in the
1159 1171 # outgoing set of changeset revisions.
1160 1172 if haveparents:
1161 1173 outgoingclrevs = set(cl.rev(n) for n in outgoing)
1162 1174
1163 1175 for path in changedpaths:
1164 1176 try:
1165 1177 store = getfilestore(repo, proto, path)
1166 1178 except FileAccessError as e:
1167 1179 raise error.WireprotoCommandError(e.msg, e.args)
1168 1180
1169 1181 for rev in store:
1170 1182 linkrev = store.linkrev(rev)
1171 1183
1172 1184 if linkrev in outgoingclrevs:
1173 1185 fnodes[path].add(store.node(rev))
1174 1186
1175 1187 # If ancestors aren't known, we walk the manifests and send all
1176 1188 # encountered file revisions.
1177 1189 else:
1178 1190 for node in outgoing:
1179 1191 mctx = repo[node].manifestctx()
1180 1192
1181 1193 for path, fnode in mctx.read().items():
1182 1194 if filematcher(path):
1183 1195 fnodes[path].add(fnode)
1184 1196
1185 1197 yield {
1186 1198 b'totalpaths': len(fnodes),
1187 1199 b'totalitems': sum(len(v) for v in fnodes.values())
1188 1200 }
1189 1201
1190 1202 for path, filenodes in sorted(fnodes.items()):
1191 1203 try:
1192 1204 store = getfilestore(repo, proto, path)
1193 1205 except FileAccessError as e:
1194 1206 raise error.WireprotoCommandError(e.msg, e.args)
1195 1207
1196 1208 yield {
1197 1209 b'path': path,
1198 1210 b'totalitems': len(filenodes),
1199 1211 }
1200 1212
1201 1213 revisions = store.emitrevisions(filenodes,
1202 1214 revisiondata=b'revision' in fields,
1203 1215 assumehaveparentrevisions=haveparents)
1204 1216
1205 for o in emitfilerevisions(revisions, fields):
1217 for o in emitfilerevisions(repo, path, revisions, fields):
1206 1218 yield o
1207 1219
1208 1220 @wireprotocommand(
1209 1221 'heads',
1210 1222 args={
1211 1223 'publiconly': {
1212 1224 'type': 'bool',
1213 1225 'default': lambda: False,
1214 1226 'example': False,
1215 1227 },
1216 1228 },
1217 1229 permission='pull')
1218 1230 def headsv2(repo, proto, publiconly):
1219 1231 if publiconly:
1220 1232 repo = repo.filtered('immutable')
1221 1233
1222 1234 yield repo.heads()
1223 1235
1224 1236 @wireprotocommand(
1225 1237 'known',
1226 1238 args={
1227 1239 'nodes': {
1228 1240 'type': 'list',
1229 1241 'default': list,
1230 1242 'example': [b'deadbeef'],
1231 1243 },
1232 1244 },
1233 1245 permission='pull')
1234 1246 def knownv2(repo, proto, nodes):
1235 1247 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
1236 1248 yield result
1237 1249
1238 1250 @wireprotocommand(
1239 1251 'listkeys',
1240 1252 args={
1241 1253 'namespace': {
1242 1254 'type': 'bytes',
1243 1255 'example': b'ns',
1244 1256 },
1245 1257 },
1246 1258 permission='pull')
1247 1259 def listkeysv2(repo, proto, namespace):
1248 1260 keys = repo.listkeys(encoding.tolocal(namespace))
1249 1261 keys = {encoding.fromlocal(k): encoding.fromlocal(v)
1250 1262 for k, v in keys.iteritems()}
1251 1263
1252 1264 yield keys
1253 1265
1254 1266 @wireprotocommand(
1255 1267 'lookup',
1256 1268 args={
1257 1269 'key': {
1258 1270 'type': 'bytes',
1259 1271 'example': b'foo',
1260 1272 },
1261 1273 },
1262 1274 permission='pull')
1263 1275 def lookupv2(repo, proto, key):
1264 1276 key = encoding.tolocal(key)
1265 1277
1266 1278 # TODO handle exception.
1267 1279 node = repo.lookup(key)
1268 1280
1269 1281 yield node
1270 1282
1271 1283 def manifestdatacapabilities(repo, proto):
1272 1284 batchsize = repo.ui.configint(
1273 1285 b'experimental', b'server.manifestdata.recommended-batch-size')
1274 1286
1275 1287 return {
1276 1288 b'recommendedbatchsize': batchsize,
1277 1289 }
1278 1290
1279 1291 @wireprotocommand(
1280 1292 'manifestdata',
1281 1293 args={
1282 1294 'nodes': {
1283 1295 'type': 'list',
1284 1296 'example': [b'0123456...'],
1285 1297 },
1286 1298 'haveparents': {
1287 1299 'type': 'bool',
1288 1300 'default': lambda: False,
1289 1301 'example': True,
1290 1302 },
1291 1303 'fields': {
1292 1304 'type': 'set',
1293 1305 'default': set,
1294 1306 'example': {b'parents', b'revision'},
1295 1307 'validvalues': {b'parents', b'revision'},
1296 1308 },
1297 1309 'tree': {
1298 1310 'type': 'bytes',
1299 1311 'example': b'',
1300 1312 },
1301 1313 },
1302 1314 permission='pull',
1303 1315 cachekeyfn=makecommandcachekeyfn('manifestdata', 1, allargs=True),
1304 1316 extracapabilitiesfn=manifestdatacapabilities)
1305 1317 def manifestdata(repo, proto, haveparents, nodes, fields, tree):
1306 1318 store = repo.manifestlog.getstorage(tree)
1307 1319
1308 1320 # Validate the node is known and abort on unknown revisions.
1309 1321 for node in nodes:
1310 1322 try:
1311 1323 store.rev(node)
1312 1324 except error.LookupError:
1313 1325 raise error.WireprotoCommandError(
1314 1326 'unknown node: %s', (node,))
1315 1327
1316 1328 revisions = store.emitrevisions(nodes,
1317 1329 revisiondata=b'revision' in fields,
1318 1330 assumehaveparentrevisions=haveparents)
1319 1331
1320 1332 yield {
1321 1333 b'totalitems': len(nodes),
1322 1334 }
1323 1335
1324 1336 for revision in revisions:
1325 1337 d = {
1326 1338 b'node': revision.node,
1327 1339 }
1328 1340
1329 1341 if b'parents' in fields:
1330 1342 d[b'parents'] = [revision.p1node, revision.p2node]
1331 1343
1332 1344 followingmeta = []
1333 1345 followingdata = []
1334 1346
1335 1347 if b'revision' in fields:
1336 1348 if revision.revision is not None:
1337 1349 followingmeta.append((b'revision', len(revision.revision)))
1338 1350 followingdata.append(revision.revision)
1339 1351 else:
1340 1352 d[b'deltabasenode'] = revision.basenode
1341 1353 followingmeta.append((b'delta', len(revision.delta)))
1342 1354 followingdata.append(revision.delta)
1343 1355
1344 1356 if followingmeta:
1345 1357 d[b'fieldsfollowing'] = followingmeta
1346 1358
1347 1359 yield d
1348 1360
1349 1361 for extra in followingdata:
1350 1362 yield extra
1351 1363
1352 1364 @wireprotocommand(
1353 1365 'pushkey',
1354 1366 args={
1355 1367 'namespace': {
1356 1368 'type': 'bytes',
1357 1369 'example': b'ns',
1358 1370 },
1359 1371 'key': {
1360 1372 'type': 'bytes',
1361 1373 'example': b'key',
1362 1374 },
1363 1375 'old': {
1364 1376 'type': 'bytes',
1365 1377 'example': b'old',
1366 1378 },
1367 1379 'new': {
1368 1380 'type': 'bytes',
1369 1381 'example': 'new',
1370 1382 },
1371 1383 },
1372 1384 permission='push')
1373 1385 def pushkeyv2(repo, proto, namespace, key, old, new):
1374 1386 # TODO handle ui output redirection
1375 1387 yield repo.pushkey(encoding.tolocal(namespace),
1376 1388 encoding.tolocal(key),
1377 1389 encoding.tolocal(old),
1378 1390 encoding.tolocal(new))
1379 1391
1380 1392
1381 1393 @wireprotocommand(
1382 1394 'rawstorefiledata',
1383 1395 args={
1384 1396 'files': {
1385 1397 'type': 'list',
1386 1398 'example': [b'changelog', b'manifestlog'],
1387 1399 },
1388 1400 'pathfilter': {
1389 1401 'type': 'list',
1390 1402 'default': lambda: None,
1391 1403 'example': {b'include': [b'path:tests']},
1392 1404 },
1393 1405 },
1394 1406 permission='pull')
1395 1407 def rawstorefiledata(repo, proto, files, pathfilter):
1396 1408 if not streamclone.allowservergeneration(repo):
1397 1409 raise error.WireprotoCommandError(b'stream clone is disabled')
1398 1410
1399 1411 # TODO support dynamically advertising what store files "sets" are
1400 1412 # available. For now, we support changelog, manifestlog, and files.
1401 1413 files = set(files)
1402 1414 allowedfiles = {b'changelog', b'manifestlog'}
1403 1415
1404 1416 unsupported = files - allowedfiles
1405 1417 if unsupported:
1406 1418 raise error.WireprotoCommandError(b'unknown file type: %s',
1407 1419 (b', '.join(sorted(unsupported)),))
1408 1420
1409 1421 with repo.lock():
1410 1422 topfiles = list(repo.store.topfiles())
1411 1423
1412 1424 sendfiles = []
1413 1425 totalsize = 0
1414 1426
1415 1427 # TODO this is a bunch of storage layer interface abstractions because
1416 1428 # it assumes revlogs.
1417 1429 for name, encodedname, size in topfiles:
1418 1430 if b'changelog' in files and name.startswith(b'00changelog'):
1419 1431 pass
1420 1432 elif b'manifestlog' in files and name.startswith(b'00manifest'):
1421 1433 pass
1422 1434 else:
1423 1435 continue
1424 1436
1425 1437 sendfiles.append((b'store', name, size))
1426 1438 totalsize += size
1427 1439
1428 1440 yield {
1429 1441 b'filecount': len(sendfiles),
1430 1442 b'totalsize': totalsize,
1431 1443 }
1432 1444
1433 1445 for location, name, size in sendfiles:
1434 1446 yield {
1435 1447 b'location': location,
1436 1448 b'path': name,
1437 1449 b'size': size,
1438 1450 }
1439 1451
1440 1452 # We have to use a closure for this to ensure the context manager is
1441 1453 # closed only after sending the final chunk.
1442 1454 def getfiledata():
1443 1455 with repo.svfs(name, 'rb', auditpath=False) as fh:
1444 1456 for chunk in util.filechunkiter(fh, limit=size):
1445 1457 yield chunk
1446 1458
1447 1459 yield wireprototypes.indefinitebytestringresponse(
1448 1460 getfiledata())
@@ -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\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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,460 +1,462 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 b'linknode',
254 255 b'parents',
255 256 b'revision'
256 257 ])
257 258 },
258 259 b'haveparents': {
259 260 b'default': False,
260 261 b'required': False,
261 262 b'type': b'bool'
262 263 },
263 264 b'nodes': {
264 265 b'required': True,
265 266 b'type': b'list'
266 267 },
267 268 b'path': {
268 269 b'required': True,
269 270 b'type': b'bytes'
270 271 }
271 272 },
272 273 b'permissions': [
273 274 b'pull'
274 275 ]
275 276 },
276 277 b'filesdata': {
277 278 b'args': {
278 279 b'fields': {
279 280 b'default': set([]),
280 281 b'required': False,
281 282 b'type': b'set',
282 283 b'validvalues': set([
283 284 b'firstchangeset',
285 b'linknode',
284 286 b'parents',
285 287 b'revision'
286 288 ])
287 289 },
288 290 b'haveparents': {
289 291 b'default': False,
290 292 b'required': False,
291 293 b'type': b'bool'
292 294 },
293 295 b'pathfilter': {
294 296 b'default': None,
295 297 b'required': False,
296 298 b'type': b'dict'
297 299 },
298 300 b'revisions': {
299 301 b'required': True,
300 302 b'type': b'list'
301 303 }
302 304 },
303 305 b'permissions': [
304 306 b'pull'
305 307 ],
306 308 b'recommendedbatchsize': 50000
307 309 },
308 310 b'heads': {
309 311 b'args': {
310 312 b'publiconly': {
311 313 b'default': False,
312 314 b'required': False,
313 315 b'type': b'bool'
314 316 }
315 317 },
316 318 b'permissions': [
317 319 b'pull'
318 320 ]
319 321 },
320 322 b'known': {
321 323 b'args': {
322 324 b'nodes': {
323 325 b'default': [],
324 326 b'required': False,
325 327 b'type': b'list'
326 328 }
327 329 },
328 330 b'permissions': [
329 331 b'pull'
330 332 ]
331 333 },
332 334 b'listkeys': {
333 335 b'args': {
334 336 b'namespace': {
335 337 b'required': True,
336 338 b'type': b'bytes'
337 339 }
338 340 },
339 341 b'permissions': [
340 342 b'pull'
341 343 ]
342 344 },
343 345 b'lookup': {
344 346 b'args': {
345 347 b'key': {
346 348 b'required': True,
347 349 b'type': b'bytes'
348 350 }
349 351 },
350 352 b'permissions': [
351 353 b'pull'
352 354 ]
353 355 },
354 356 b'manifestdata': {
355 357 b'args': {
356 358 b'fields': {
357 359 b'default': set([]),
358 360 b'required': False,
359 361 b'type': b'set',
360 362 b'validvalues': set([
361 363 b'parents',
362 364 b'revision'
363 365 ])
364 366 },
365 367 b'haveparents': {
366 368 b'default': False,
367 369 b'required': False,
368 370 b'type': b'bool'
369 371 },
370 372 b'nodes': {
371 373 b'required': True,
372 374 b'type': b'list'
373 375 },
374 376 b'tree': {
375 377 b'required': True,
376 378 b'type': b'bytes'
377 379 }
378 380 },
379 381 b'permissions': [
380 382 b'pull'
381 383 ],
382 384 b'recommendedbatchsize': 100000
383 385 },
384 386 b'pushkey': {
385 387 b'args': {
386 388 b'key': {
387 389 b'required': True,
388 390 b'type': b'bytes'
389 391 },
390 392 b'namespace': {
391 393 b'required': True,
392 394 b'type': b'bytes'
393 395 },
394 396 b'new': {
395 397 b'required': True,
396 398 b'type': b'bytes'
397 399 },
398 400 b'old': {
399 401 b'required': True,
400 402 b'type': b'bytes'
401 403 }
402 404 },
403 405 b'permissions': [
404 406 b'push'
405 407 ]
406 408 },
407 409 b'rawstorefiledata': {
408 410 b'args': {
409 411 b'files': {
410 412 b'required': True,
411 413 b'type': b'list'
412 414 },
413 415 b'pathfilter': {
414 416 b'default': None,
415 417 b'required': False,
416 418 b'type': b'list'
417 419 }
418 420 },
419 421 b'permissions': [
420 422 b'pull'
421 423 ]
422 424 }
423 425 },
424 426 b'framingmediatypes': [
425 427 b'application/mercurial-exp-framing-0006'
426 428 ],
427 429 b'pathfilterprefixes': set([
428 430 b'path:',
429 431 b'rootfilesin:'
430 432 ]),
431 433 b'rawrepoformats': [
432 434 b'generaldelta',
433 435 b'revlogv1'
434 436 ]
435 437 }
436 438 ]
437 439
438 440 $ test -f .hg/blackbox.log
439 441 [1]
440 442
441 443 An error is not cached
442 444
443 445 $ sendhttpv2peer << EOF
444 446 > command manifestdata
445 447 > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
446 448 > tree eval:b''
447 449 > fields eval:[b'parents']
448 450 > EOF
449 451 creating http peer for wire protocol version 2
450 452 sending manifestdata command
451 453 abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa! (esc)
452 454 [255]
453 455
454 456 $ cat .hg/blackbox.log
455 457 *> cacher constructed for manifestdata (glob)
456 458 *> cache miss for 2cba2a7d0d1575fea2fe68f597e97a7c2ac2f705 (glob)
457 459 *> cacher exiting due to error (glob)
458 460
459 461 $ killdaemons.py
460 462 $ rm .hg/blackbox.log
@@ -1,744 +1,748 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\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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 b'linknode',
267 268 b'parents',
268 269 b'revision'
269 270 ])
270 271 },
271 272 b'haveparents': {
272 273 b'default': False,
273 274 b'required': False,
274 275 b'type': b'bool'
275 276 },
276 277 b'nodes': {
277 278 b'required': True,
278 279 b'type': b'list'
279 280 },
280 281 b'path': {
281 282 b'required': True,
282 283 b'type': b'bytes'
283 284 }
284 285 },
285 286 b'permissions': [
286 287 b'pull'
287 288 ]
288 289 },
289 290 b'filesdata': {
290 291 b'args': {
291 292 b'fields': {
292 293 b'default': set([]),
293 294 b'required': False,
294 295 b'type': b'set',
295 296 b'validvalues': set([
296 297 b'firstchangeset',
298 b'linknode',
297 299 b'parents',
298 300 b'revision'
299 301 ])
300 302 },
301 303 b'haveparents': {
302 304 b'default': False,
303 305 b'required': False,
304 306 b'type': b'bool'
305 307 },
306 308 b'pathfilter': {
307 309 b'default': None,
308 310 b'required': False,
309 311 b'type': b'dict'
310 312 },
311 313 b'revisions': {
312 314 b'required': True,
313 315 b'type': b'list'
314 316 }
315 317 },
316 318 b'permissions': [
317 319 b'pull'
318 320 ],
319 321 b'recommendedbatchsize': 50000
320 322 },
321 323 b'heads': {
322 324 b'args': {
323 325 b'publiconly': {
324 326 b'default': False,
325 327 b'required': False,
326 328 b'type': b'bool'
327 329 }
328 330 },
329 331 b'permissions': [
330 332 b'pull'
331 333 ]
332 334 },
333 335 b'known': {
334 336 b'args': {
335 337 b'nodes': {
336 338 b'default': [],
337 339 b'required': False,
338 340 b'type': b'list'
339 341 }
340 342 },
341 343 b'permissions': [
342 344 b'pull'
343 345 ]
344 346 },
345 347 b'listkeys': {
346 348 b'args': {
347 349 b'namespace': {
348 350 b'required': True,
349 351 b'type': b'bytes'
350 352 }
351 353 },
352 354 b'permissions': [
353 355 b'pull'
354 356 ]
355 357 },
356 358 b'lookup': {
357 359 b'args': {
358 360 b'key': {
359 361 b'required': True,
360 362 b'type': b'bytes'
361 363 }
362 364 },
363 365 b'permissions': [
364 366 b'pull'
365 367 ]
366 368 },
367 369 b'manifestdata': {
368 370 b'args': {
369 371 b'fields': {
370 372 b'default': set([]),
371 373 b'required': False,
372 374 b'type': b'set',
373 375 b'validvalues': set([
374 376 b'parents',
375 377 b'revision'
376 378 ])
377 379 },
378 380 b'haveparents': {
379 381 b'default': False,
380 382 b'required': False,
381 383 b'type': b'bool'
382 384 },
383 385 b'nodes': {
384 386 b'required': True,
385 387 b'type': b'list'
386 388 },
387 389 b'tree': {
388 390 b'required': True,
389 391 b'type': b'bytes'
390 392 }
391 393 },
392 394 b'permissions': [
393 395 b'pull'
394 396 ],
395 397 b'recommendedbatchsize': 100000
396 398 },
397 399 b'pushkey': {
398 400 b'args': {
399 401 b'key': {
400 402 b'required': True,
401 403 b'type': b'bytes'
402 404 },
403 405 b'namespace': {
404 406 b'required': True,
405 407 b'type': b'bytes'
406 408 },
407 409 b'new': {
408 410 b'required': True,
409 411 b'type': b'bytes'
410 412 },
411 413 b'old': {
412 414 b'required': True,
413 415 b'type': b'bytes'
414 416 }
415 417 },
416 418 b'permissions': [
417 419 b'push'
418 420 ]
419 421 },
420 422 b'rawstorefiledata': {
421 423 b'args': {
422 424 b'files': {
423 425 b'required': True,
424 426 b'type': b'list'
425 427 },
426 428 b'pathfilter': {
427 429 b'default': None,
428 430 b'required': False,
429 431 b'type': b'list'
430 432 }
431 433 },
432 434 b'permissions': [
433 435 b'pull'
434 436 ]
435 437 }
436 438 },
437 439 b'framingmediatypes': [
438 440 b'application/mercurial-exp-framing-0006'
439 441 ],
440 442 b'pathfilterprefixes': set([
441 443 b'path:',
442 444 b'rootfilesin:'
443 445 ]),
444 446 b'rawrepoformats': [
445 447 b'generaldelta',
446 448 b'revlogv1'
447 449 ]
448 450 }
449 451 },
450 452 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'
451 453 }
452 454 ]
453 455
454 456 capabilities command returns expected info
455 457
456 458 $ sendhttpv2peerhandshake << EOF
457 459 > command capabilities
458 460 > EOF
459 461 creating http peer for wire protocol version 2
460 462 s> GET /?cmd=capabilities HTTP/1.1\r\n
461 463 s> Accept-Encoding: identity\r\n
462 464 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
463 465 s> x-hgproto-1: cbor\r\n
464 466 s> x-hgupgrade-1: exp-http-v2-0003\r\n
465 467 s> accept: application/mercurial-0.1\r\n
466 468 s> host: $LOCALIP:$HGPORT\r\n (glob)
467 469 s> user-agent: Mercurial debugwireproto\r\n
468 470 s> \r\n
469 471 s> makefile('rb', None)
470 472 s> HTTP/1.1 200 OK\r\n
471 473 s> Server: testing stub value\r\n
472 474 s> Date: $HTTP_DATE$\r\n
473 475 s> Content-Type: application/mercurial-cbor\r\n
474 476 s> Content-Length: *\r\n (glob)
475 477 s> \r\n
476 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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
478 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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
477 479 sending capabilities command
478 480 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
479 481 s> Accept-Encoding: identity\r\n
480 482 s> accept: application/mercurial-exp-framing-0006\r\n
481 483 s> content-type: application/mercurial-exp-framing-0006\r\n
482 484 s> content-length: 63\r\n
483 485 s> host: $LOCALIP:$HGPORT\r\n (glob)
484 486 s> user-agent: Mercurial debugwireproto\r\n
485 487 s> \r\n
486 488 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x13\x00\x00\x01\x00\x01\x00\x11\xa1DnameLcapabilities
487 489 s> makefile('rb', None)
488 490 s> HTTP/1.1 200 OK\r\n
489 491 s> Server: testing stub value\r\n
490 492 s> Date: $HTTP_DATE$\r\n
491 493 s> Content-Type: application/mercurial-exp-framing-0006\r\n
492 494 s> Transfer-Encoding: chunked\r\n
493 495 s> \r\n
494 496 s> 11\r\n
495 497 s> \t\x00\x00\x01\x00\x02\x01\x92
496 498 s> Hidentity
497 499 s> \r\n
498 500 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
499 501 s> 13\r\n
500 502 s> \x0b\x00\x00\x01\x00\x02\x041
501 503 s> \xa1FstatusBok
502 504 s> \r\n
503 505 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
504 s> 63f\r\n
505 s> 7\x06\x00\x01\x00\x02\x041
506 s> \xa4Hcommands\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1
506 s> 651\r\n
507 s> I\x06\x00\x01\x00\x02\x041
508 s> \xa4Hcommands\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1
507 509 s> \r\n
508 received frame(size=1591; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
510 received frame(size=1609; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
509 511 s> 8\r\n
510 512 s> \x00\x00\x00\x01\x00\x02\x002
511 513 s> \r\n
512 514 s> 0\r\n
513 515 s> \r\n
514 516 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
515 517 response: gen[
516 518 {
517 519 b'commands': {
518 520 b'branchmap': {
519 521 b'args': {},
520 522 b'permissions': [
521 523 b'pull'
522 524 ]
523 525 },
524 526 b'capabilities': {
525 527 b'args': {},
526 528 b'permissions': [
527 529 b'pull'
528 530 ]
529 531 },
530 532 b'changesetdata': {
531 533 b'args': {
532 534 b'fields': {
533 535 b'default': set([]),
534 536 b'required': False,
535 537 b'type': b'set',
536 538 b'validvalues': set([
537 539 b'bookmarks',
538 540 b'parents',
539 541 b'phase',
540 542 b'revision'
541 543 ])
542 544 },
543 545 b'revisions': {
544 546 b'required': True,
545 547 b'type': b'list'
546 548 }
547 549 },
548 550 b'permissions': [
549 551 b'pull'
550 552 ]
551 553 },
552 554 b'filedata': {
553 555 b'args': {
554 556 b'fields': {
555 557 b'default': set([]),
556 558 b'required': False,
557 559 b'type': b'set',
558 560 b'validvalues': set([
561 b'linknode',
559 562 b'parents',
560 563 b'revision'
561 564 ])
562 565 },
563 566 b'haveparents': {
564 567 b'default': False,
565 568 b'required': False,
566 569 b'type': b'bool'
567 570 },
568 571 b'nodes': {
569 572 b'required': True,
570 573 b'type': b'list'
571 574 },
572 575 b'path': {
573 576 b'required': True,
574 577 b'type': b'bytes'
575 578 }
576 579 },
577 580 b'permissions': [
578 581 b'pull'
579 582 ]
580 583 },
581 584 b'filesdata': {
582 585 b'args': {
583 586 b'fields': {
584 587 b'default': set([]),
585 588 b'required': False,
586 589 b'type': b'set',
587 590 b'validvalues': set([
588 591 b'firstchangeset',
592 b'linknode',
589 593 b'parents',
590 594 b'revision'
591 595 ])
592 596 },
593 597 b'haveparents': {
594 598 b'default': False,
595 599 b'required': False,
596 600 b'type': b'bool'
597 601 },
598 602 b'pathfilter': {
599 603 b'default': None,
600 604 b'required': False,
601 605 b'type': b'dict'
602 606 },
603 607 b'revisions': {
604 608 b'required': True,
605 609 b'type': b'list'
606 610 }
607 611 },
608 612 b'permissions': [
609 613 b'pull'
610 614 ],
611 615 b'recommendedbatchsize': 50000
612 616 },
613 617 b'heads': {
614 618 b'args': {
615 619 b'publiconly': {
616 620 b'default': False,
617 621 b'required': False,
618 622 b'type': b'bool'
619 623 }
620 624 },
621 625 b'permissions': [
622 626 b'pull'
623 627 ]
624 628 },
625 629 b'known': {
626 630 b'args': {
627 631 b'nodes': {
628 632 b'default': [],
629 633 b'required': False,
630 634 b'type': b'list'
631 635 }
632 636 },
633 637 b'permissions': [
634 638 b'pull'
635 639 ]
636 640 },
637 641 b'listkeys': {
638 642 b'args': {
639 643 b'namespace': {
640 644 b'required': True,
641 645 b'type': b'bytes'
642 646 }
643 647 },
644 648 b'permissions': [
645 649 b'pull'
646 650 ]
647 651 },
648 652 b'lookup': {
649 653 b'args': {
650 654 b'key': {
651 655 b'required': True,
652 656 b'type': b'bytes'
653 657 }
654 658 },
655 659 b'permissions': [
656 660 b'pull'
657 661 ]
658 662 },
659 663 b'manifestdata': {
660 664 b'args': {
661 665 b'fields': {
662 666 b'default': set([]),
663 667 b'required': False,
664 668 b'type': b'set',
665 669 b'validvalues': set([
666 670 b'parents',
667 671 b'revision'
668 672 ])
669 673 },
670 674 b'haveparents': {
671 675 b'default': False,
672 676 b'required': False,
673 677 b'type': b'bool'
674 678 },
675 679 b'nodes': {
676 680 b'required': True,
677 681 b'type': b'list'
678 682 },
679 683 b'tree': {
680 684 b'required': True,
681 685 b'type': b'bytes'
682 686 }
683 687 },
684 688 b'permissions': [
685 689 b'pull'
686 690 ],
687 691 b'recommendedbatchsize': 100000
688 692 },
689 693 b'pushkey': {
690 694 b'args': {
691 695 b'key': {
692 696 b'required': True,
693 697 b'type': b'bytes'
694 698 },
695 699 b'namespace': {
696 700 b'required': True,
697 701 b'type': b'bytes'
698 702 },
699 703 b'new': {
700 704 b'required': True,
701 705 b'type': b'bytes'
702 706 },
703 707 b'old': {
704 708 b'required': True,
705 709 b'type': b'bytes'
706 710 }
707 711 },
708 712 b'permissions': [
709 713 b'push'
710 714 ]
711 715 },
712 716 b'rawstorefiledata': {
713 717 b'args': {
714 718 b'files': {
715 719 b'required': True,
716 720 b'type': b'list'
717 721 },
718 722 b'pathfilter': {
719 723 b'default': None,
720 724 b'required': False,
721 725 b'type': b'list'
722 726 }
723 727 },
724 728 b'permissions': [
725 729 b'pull'
726 730 ]
727 731 }
728 732 },
729 733 b'framingmediatypes': [
730 734 b'application/mercurial-exp-framing-0006'
731 735 ],
732 736 b'pathfilterprefixes': set([
733 737 b'path:',
734 738 b'rootfilesin:'
735 739 ]),
736 740 b'rawrepoformats': [
737 741 b'generaldelta',
738 742 b'revlogv1'
739 743 ]
740 744 }
741 745 ]
742 746 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
743 747
744 748 $ cat error.log
@@ -1,1058 +1,1164 b''
1 1 $ . $TESTDIR/wireprotohelpers.sh
2 2
3 3 $ hg init server
4 4 $ enablehttpv2 server
5 5 $ cd server
6 6 $ cat > a << EOF
7 7 > a0
8 8 > 00000000000000000000000000000000000000
9 9 > 11111111111111111111111111111111111111
10 10 > EOF
11 11 $ cat > b << EOF
12 12 > b0
13 13 > aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
14 14 > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
15 15 > EOF
16 16 $ mkdir -p dir0/child0 dir0/child1 dir1
17 17 $ echo c0 > dir0/c
18 18 $ echo d0 > dir0/d
19 19 $ echo e0 > dir0/child0/e
20 20 $ echo f0 > dir0/child1/f
21 21 $ hg -q commit -A -m 'commit 0'
22 22
23 23 $ echo a1 >> a
24 24 $ echo d1 > dir0/d
25 25 $ echo g0 > g
26 26 $ echo h0 > h
27 27 $ hg -q commit -A -m 'commit 1'
28 28 $ echo f1 > dir0/child1/f
29 29 $ echo i0 > dir0/i
30 30 $ hg -q commit -A -m 'commit 2'
31 31
32 32 $ hg -q up -r 0
33 33 $ echo a2 >> a
34 34 $ hg commit -m 'commit 3'
35 35 created new head
36 36
37 37 $ hg log -G -T '{rev}:{node} {desc}\n'
38 38 @ 3:476fbf122cd82f6726f0191ff146f67140946abc commit 3
39 39 |
40 40 | o 2:b91c03cbba3519ab149b6cd0a0afbdb5cf1b5c8a commit 2
41 41 | |
42 42 | o 1:5b0b1a23577e205ea240e39c9704e28d7697cbd8 commit 1
43 43 |/
44 44 o 0:6e875ff18c227659ad6143bb3580c65700734884 commit 0
45 45
46 46
47 47 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
48 48 $ cat hg.pid > $DAEMON_PIDS
49 49
50 50 Missing arguments is an error
51 51
52 52 $ sendhttpv2peer << EOF
53 53 > command filesdata
54 54 > EOF
55 55 creating http peer for wire protocol version 2
56 56 sending filesdata command
57 57 abort: missing required arguments: revisions!
58 58 [255]
59 59
60 60 Bad pattern to pathfilter is rejected
61 61
62 62 $ sendhttpv2peer << EOF
63 63 > command filesdata
64 64 > revisions eval:[{
65 65 > b'type': b'changesetexplicit',
66 66 > b'nodes': [
67 67 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
68 68 > ]}]
69 69 > pathfilter eval:{b'include': [b'bad:foo']}
70 70 > EOF
71 71 creating http peer for wire protocol version 2
72 72 sending filesdata command
73 73 abort: include pattern must begin with `path:` or `rootfilesin:`; got bad:foo!
74 74 [255]
75 75
76 76 $ sendhttpv2peer << EOF
77 77 > command filesdata
78 78 > revisions eval:[{
79 79 > b'type': b'changesetexplicit',
80 80 > b'nodes': [
81 81 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
82 82 > ]}]
83 83 > pathfilter eval:{b'exclude': [b'glob:foo']}
84 84 > EOF
85 85 creating http peer for wire protocol version 2
86 86 sending filesdata command
87 87 abort: exclude pattern must begin with `path:` or `rootfilesin:`; got glob:foo!
88 88 [255]
89 89
90 90 Fetching a single changeset without parents fetches all files
91 91
92 92 $ sendhttpv2peer << EOF
93 93 > command filesdata
94 94 > revisions eval:[{
95 95 > b'type': b'changesetexplicit',
96 96 > b'nodes': [
97 97 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
98 98 > ]}]
99 99 > EOF
100 100 creating http peer for wire protocol version 2
101 101 sending filesdata command
102 102 response: gen[
103 103 {
104 104 b'totalitems': 8,
105 105 b'totalpaths': 8
106 106 },
107 107 {
108 108 b'path': b'a',
109 109 b'totalitems': 1
110 110 },
111 111 {
112 112 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
113 113 },
114 114 {
115 115 b'path': b'b',
116 116 b'totalitems': 1
117 117 },
118 118 {
119 119 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
120 120 },
121 121 {
122 122 b'path': b'dir0/c',
123 123 b'totalitems': 1
124 124 },
125 125 {
126 126 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
127 127 },
128 128 {
129 129 b'path': b'dir0/child0/e',
130 130 b'totalitems': 1
131 131 },
132 132 {
133 133 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
134 134 },
135 135 {
136 136 b'path': b'dir0/child1/f',
137 137 b'totalitems': 1
138 138 },
139 139 {
140 140 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
141 141 },
142 142 {
143 143 b'path': b'dir0/d',
144 144 b'totalitems': 1
145 145 },
146 146 {
147 147 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
148 148 },
149 149 {
150 150 b'path': b'g',
151 151 b'totalitems': 1
152 152 },
153 153 {
154 154 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
155 155 },
156 156 {
157 157 b'path': b'h',
158 158 b'totalitems': 1
159 159 },
160 160 {
161 161 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
162 162 }
163 163 ]
164 164
165 165 Fetching a single changeset saying parents data is available fetches just new files
166 166
167 167 $ sendhttpv2peer << EOF
168 168 > command filesdata
169 169 > revisions eval:[{
170 170 > b'type': b'changesetexplicit',
171 171 > b'nodes': [
172 172 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
173 173 > ]}]
174 174 > haveparents eval:True
175 175 > EOF
176 176 creating http peer for wire protocol version 2
177 177 sending filesdata command
178 178 response: gen[
179 179 {
180 180 b'totalitems': 4,
181 181 b'totalpaths': 4
182 182 },
183 183 {
184 184 b'path': b'a',
185 185 b'totalitems': 1
186 186 },
187 187 {
188 188 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
189 189 },
190 190 {
191 191 b'path': b'dir0/d',
192 192 b'totalitems': 1
193 193 },
194 194 {
195 195 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
196 196 },
197 197 {
198 198 b'path': b'g',
199 199 b'totalitems': 1
200 200 },
201 201 {
202 202 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
203 203 },
204 204 {
205 205 b'path': b'h',
206 206 b'totalitems': 1
207 207 },
208 208 {
209 209 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
210 210 }
211 211 ]
212 212
213 213 A path filter for a sub-directory is honored
214 214
215 215 $ sendhttpv2peer << EOF
216 216 > command filesdata
217 217 > revisions eval:[{
218 218 > b'type': b'changesetexplicit',
219 219 > b'nodes': [
220 220 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
221 221 > ]}]
222 222 > haveparents eval:True
223 223 > pathfilter eval:{b'include': [b'path:dir0']}
224 224 > EOF
225 225 creating http peer for wire protocol version 2
226 226 sending filesdata command
227 227 response: gen[
228 228 {
229 229 b'totalitems': 1,
230 230 b'totalpaths': 1
231 231 },
232 232 {
233 233 b'path': b'dir0/d',
234 234 b'totalitems': 1
235 235 },
236 236 {
237 237 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
238 238 }
239 239 ]
240 240
241 241 $ sendhttpv2peer << EOF
242 242 > command filesdata
243 243 > revisions eval:[{
244 244 > b'type': b'changesetexplicit',
245 245 > b'nodes': [
246 246 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
247 247 > ]}]
248 248 > haveparents eval:True
249 249 > pathfilter eval:{b'exclude': [b'path:a', b'path:g']}
250 250 > EOF
251 251 creating http peer for wire protocol version 2
252 252 sending filesdata command
253 253 response: gen[
254 254 {
255 255 b'totalitems': 2,
256 256 b'totalpaths': 2
257 257 },
258 258 {
259 259 b'path': b'dir0/d',
260 260 b'totalitems': 1
261 261 },
262 262 {
263 263 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
264 264 },
265 265 {
266 266 b'path': b'h',
267 267 b'totalitems': 1
268 268 },
269 269 {
270 270 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
271 271 }
272 272 ]
273 273
274 274 Requesting multiple changeset nodes without haveparents sends all data for both
275 275
276 276 $ sendhttpv2peer << EOF
277 277 > command filesdata
278 278 > revisions eval:[{
279 279 > b'type': b'changesetexplicit',
280 280 > b'nodes': [
281 281 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
282 282 > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
283 283 > ]}]
284 284 > EOF
285 285 creating http peer for wire protocol version 2
286 286 sending filesdata command
287 287 response: gen[
288 288 {
289 289 b'totalitems': 10,
290 290 b'totalpaths': 9
291 291 },
292 292 {
293 293 b'path': b'a',
294 294 b'totalitems': 1
295 295 },
296 296 {
297 297 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
298 298 },
299 299 {
300 300 b'path': b'b',
301 301 b'totalitems': 1
302 302 },
303 303 {
304 304 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
305 305 },
306 306 {
307 307 b'path': b'dir0/c',
308 308 b'totalitems': 1
309 309 },
310 310 {
311 311 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
312 312 },
313 313 {
314 314 b'path': b'dir0/child0/e',
315 315 b'totalitems': 1
316 316 },
317 317 {
318 318 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
319 319 },
320 320 {
321 321 b'path': b'dir0/child1/f',
322 322 b'totalitems': 2
323 323 },
324 324 {
325 325 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
326 326 },
327 327 {
328 328 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
329 329 },
330 330 {
331 331 b'path': b'dir0/d',
332 332 b'totalitems': 1
333 333 },
334 334 {
335 335 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
336 336 },
337 337 {
338 338 b'path': b'dir0/i',
339 339 b'totalitems': 1
340 340 },
341 341 {
342 342 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
343 343 },
344 344 {
345 345 b'path': b'g',
346 346 b'totalitems': 1
347 347 },
348 348 {
349 349 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
350 350 },
351 351 {
352 352 b'path': b'h',
353 353 b'totalitems': 1
354 354 },
355 355 {
356 356 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
357 357 }
358 358 ]
359 359
360 360 Requesting multiple changeset nodes with haveparents sends incremental data for both
361 361
362 362 $ sendhttpv2peer << EOF
363 363 > command filesdata
364 364 > revisions eval:[{
365 365 > b'type': b'changesetexplicit',
366 366 > b'nodes': [
367 367 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
368 368 > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
369 369 > ]}]
370 370 > haveparents eval:True
371 371 > EOF
372 372 creating http peer for wire protocol version 2
373 373 sending filesdata command
374 374 response: gen[
375 375 {
376 376 b'totalitems': 6,
377 377 b'totalpaths': 6
378 378 },
379 379 {
380 380 b'path': b'a',
381 381 b'totalitems': 1
382 382 },
383 383 {
384 384 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
385 385 },
386 386 {
387 387 b'path': b'dir0/child1/f',
388 388 b'totalitems': 1
389 389 },
390 390 {
391 391 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
392 392 },
393 393 {
394 394 b'path': b'dir0/d',
395 395 b'totalitems': 1
396 396 },
397 397 {
398 398 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
399 399 },
400 400 {
401 401 b'path': b'dir0/i',
402 402 b'totalitems': 1
403 403 },
404 404 {
405 405 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
406 406 },
407 407 {
408 408 b'path': b'g',
409 409 b'totalitems': 1
410 410 },
411 411 {
412 412 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
413 413 },
414 414 {
415 415 b'path': b'h',
416 416 b'totalitems': 1
417 417 },
418 418 {
419 419 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
420 420 }
421 421 ]
422 422
423 423 Requesting parents works
424 424
425 425 $ sendhttpv2peer << EOF
426 426 > command filesdata
427 427 > revisions eval:[{
428 428 > b'type': b'changesetexplicit',
429 429 > b'nodes': [
430 430 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
431 431 > ]}]
432 432 > fields eval:[b'parents']
433 433 > EOF
434 434 creating http peer for wire protocol version 2
435 435 sending filesdata command
436 436 response: gen[
437 437 {
438 438 b'totalitems': 8,
439 439 b'totalpaths': 8
440 440 },
441 441 {
442 442 b'path': b'a',
443 443 b'totalitems': 1
444 444 },
445 445 {
446 446 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11',
447 447 b'parents': [
448 448 b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
449 449 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
450 450 ]
451 451 },
452 452 {
453 453 b'path': b'b',
454 454 b'totalitems': 1
455 455 },
456 456 {
457 457 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2',
458 458 b'parents': [
459 459 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
460 460 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
461 461 ]
462 462 },
463 463 {
464 464 b'path': b'dir0/c',
465 465 b'totalitems': 1
466 466 },
467 467 {
468 468 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01',
469 469 b'parents': [
470 470 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
471 471 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
472 472 ]
473 473 },
474 474 {
475 475 b'path': b'dir0/child0/e',
476 476 b'totalitems': 1
477 477 },
478 478 {
479 479 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4',
480 480 b'parents': [
481 481 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
482 482 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
483 483 ]
484 484 },
485 485 {
486 486 b'path': b'dir0/child1/f',
487 487 b'totalitems': 1
488 488 },
489 489 {
490 490 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4',
491 491 b'parents': [
492 492 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
493 493 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
494 494 ]
495 495 },
496 496 {
497 497 b'path': b'dir0/d',
498 498 b'totalitems': 1
499 499 },
500 500 {
501 501 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G',
502 502 b'parents': [
503 503 b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
504 504 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
505 505 ]
506 506 },
507 507 {
508 508 b'path': b'g',
509 509 b'totalitems': 1
510 510 },
511 511 {
512 512 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c',
513 513 b'parents': [
514 514 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
515 515 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
516 516 ]
517 517 },
518 518 {
519 519 b'path': b'h',
520 520 b'totalitems': 1
521 521 },
522 522 {
523 523 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K',
524 524 b'parents': [
525 525 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
526 526 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
527 527 ]
528 528 }
529 529 ]
530 530
531 531 Requesting revision data works
532 532 (haveparents defaults to False, so fulltext is emitted)
533 533
534 534 $ sendhttpv2peer << EOF
535 535 > command filesdata
536 536 > revisions eval:[{
537 537 > b'type': b'changesetexplicit',
538 538 > b'nodes': [
539 539 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
540 540 > ]}]
541 541 > fields eval:[b'revision']
542 542 > EOF
543 543 creating http peer for wire protocol version 2
544 544 sending filesdata command
545 545 response: gen[
546 546 {
547 547 b'totalitems': 8,
548 548 b'totalpaths': 8
549 549 },
550 550 {
551 551 b'path': b'a',
552 552 b'totalitems': 1
553 553 },
554 554 {
555 555 b'fieldsfollowing': [
556 556 [
557 557 b'revision',
558 558 84
559 559 ]
560 560 ],
561 561 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
562 562 },
563 563 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n',
564 564 {
565 565 b'path': b'b',
566 566 b'totalitems': 1
567 567 },
568 568 {
569 569 b'fieldsfollowing': [
570 570 [
571 571 b'revision',
572 572 81
573 573 ]
574 574 ],
575 575 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
576 576 },
577 577 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
578 578 {
579 579 b'path': b'dir0/c',
580 580 b'totalitems': 1
581 581 },
582 582 {
583 583 b'fieldsfollowing': [
584 584 [
585 585 b'revision',
586 586 3
587 587 ]
588 588 ],
589 589 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
590 590 },
591 591 b'c0\n',
592 592 {
593 593 b'path': b'dir0/child0/e',
594 594 b'totalitems': 1
595 595 },
596 596 {
597 597 b'fieldsfollowing': [
598 598 [
599 599 b'revision',
600 600 3
601 601 ]
602 602 ],
603 603 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
604 604 },
605 605 b'e0\n',
606 606 {
607 607 b'path': b'dir0/child1/f',
608 608 b'totalitems': 1
609 609 },
610 610 {
611 611 b'fieldsfollowing': [
612 612 [
613 613 b'revision',
614 614 3
615 615 ]
616 616 ],
617 617 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
618 618 },
619 619 b'f0\n',
620 620 {
621 621 b'path': b'dir0/d',
622 622 b'totalitems': 1
623 623 },
624 624 {
625 625 b'fieldsfollowing': [
626 626 [
627 627 b'revision',
628 628 3
629 629 ]
630 630 ],
631 631 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
632 632 },
633 633 b'd1\n',
634 634 {
635 635 b'path': b'g',
636 636 b'totalitems': 1
637 637 },
638 638 {
639 639 b'fieldsfollowing': [
640 640 [
641 641 b'revision',
642 642 3
643 643 ]
644 644 ],
645 645 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
646 646 },
647 647 b'g0\n',
648 648 {
649 649 b'path': b'h',
650 650 b'totalitems': 1
651 651 },
652 652 {
653 653 b'fieldsfollowing': [
654 654 [
655 655 b'revision',
656 656 3
657 657 ]
658 658 ],
659 659 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
660 660 },
661 661 b'h0\n'
662 662 ]
663 663
664 664 haveparents=False should be same as above
665 665
666 666 $ sendhttpv2peer << EOF
667 667 > command filesdata
668 668 > revisions eval:[{
669 669 > b'type': b'changesetexplicit',
670 670 > b'nodes': [
671 671 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
672 672 > ]}]
673 673 > fields eval:[b'revision']
674 674 > haveparents eval:False
675 675 > EOF
676 676 creating http peer for wire protocol version 2
677 677 sending filesdata command
678 678 response: gen[
679 679 {
680 680 b'totalitems': 8,
681 681 b'totalpaths': 8
682 682 },
683 683 {
684 684 b'path': b'a',
685 685 b'totalitems': 1
686 686 },
687 687 {
688 688 b'fieldsfollowing': [
689 689 [
690 690 b'revision',
691 691 84
692 692 ]
693 693 ],
694 694 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
695 695 },
696 696 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n',
697 697 {
698 698 b'path': b'b',
699 699 b'totalitems': 1
700 700 },
701 701 {
702 702 b'fieldsfollowing': [
703 703 [
704 704 b'revision',
705 705 81
706 706 ]
707 707 ],
708 708 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
709 709 },
710 710 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
711 711 {
712 712 b'path': b'dir0/c',
713 713 b'totalitems': 1
714 714 },
715 715 {
716 716 b'fieldsfollowing': [
717 717 [
718 718 b'revision',
719 719 3
720 720 ]
721 721 ],
722 722 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
723 723 },
724 724 b'c0\n',
725 725 {
726 726 b'path': b'dir0/child0/e',
727 727 b'totalitems': 1
728 728 },
729 729 {
730 730 b'fieldsfollowing': [
731 731 [
732 732 b'revision',
733 733 3
734 734 ]
735 735 ],
736 736 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
737 737 },
738 738 b'e0\n',
739 739 {
740 740 b'path': b'dir0/child1/f',
741 741 b'totalitems': 1
742 742 },
743 743 {
744 744 b'fieldsfollowing': [
745 745 [
746 746 b'revision',
747 747 3
748 748 ]
749 749 ],
750 750 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
751 751 },
752 752 b'f0\n',
753 753 {
754 754 b'path': b'dir0/d',
755 755 b'totalitems': 1
756 756 },
757 757 {
758 758 b'fieldsfollowing': [
759 759 [
760 760 b'revision',
761 761 3
762 762 ]
763 763 ],
764 764 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
765 765 },
766 766 b'd1\n',
767 767 {
768 768 b'path': b'g',
769 769 b'totalitems': 1
770 770 },
771 771 {
772 772 b'fieldsfollowing': [
773 773 [
774 774 b'revision',
775 775 3
776 776 ]
777 777 ],
778 778 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
779 779 },
780 780 b'g0\n',
781 781 {
782 782 b'path': b'h',
783 783 b'totalitems': 1
784 784 },
785 785 {
786 786 b'fieldsfollowing': [
787 787 [
788 788 b'revision',
789 789 3
790 790 ]
791 791 ],
792 792 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
793 793 },
794 794 b'h0\n'
795 795 ]
796 796
797 797 haveparents=True should emit a delta
798 798
799 799 $ sendhttpv2peer << EOF
800 800 > command filesdata
801 801 > revisions eval:[{
802 802 > b'type': b'changesetexplicit',
803 803 > b'nodes': [
804 804 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
805 805 > ]}]
806 806 > fields eval:[b'revision']
807 807 > haveparents eval:True
808 808 > EOF
809 809 creating http peer for wire protocol version 2
810 810 sending filesdata command
811 811 response: gen[
812 812 {
813 813 b'totalitems': 4,
814 814 b'totalpaths': 4
815 815 },
816 816 {
817 817 b'path': b'a',
818 818 b'totalitems': 1
819 819 },
820 820 {
821 821 b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
822 822 b'fieldsfollowing': [
823 823 [
824 824 b'delta',
825 825 15
826 826 ]
827 827 ],
828 828 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
829 829 },
830 830 b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n',
831 831 {
832 832 b'path': b'dir0/d',
833 833 b'totalitems': 1
834 834 },
835 835 {
836 836 b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
837 837 b'fieldsfollowing': [
838 838 [
839 839 b'delta',
840 840 15
841 841 ]
842 842 ],
843 843 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
844 844 },
845 845 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n',
846 846 {
847 847 b'path': b'g',
848 848 b'totalitems': 1
849 849 },
850 850 {
851 851 b'fieldsfollowing': [
852 852 [
853 853 b'revision',
854 854 3
855 855 ]
856 856 ],
857 857 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
858 858 },
859 859 b'g0\n',
860 860 {
861 861 b'path': b'h',
862 862 b'totalitems': 1
863 863 },
864 864 {
865 865 b'fieldsfollowing': [
866 866 [
867 867 b'revision',
868 868 3
869 869 ]
870 870 ],
871 871 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
872 872 },
873 873 b'h0\n'
874 874 ]
875 875
876 876 Requesting multiple revisions works
877 877 (first revision is a fulltext since haveparents=False by default)
878 878
879 879 $ sendhttpv2peer << EOF
880 880 > command filesdata
881 881 > revisions eval:[{
882 882 > b'type': b'changesetexplicit',
883 883 > b'nodes': [
884 884 > b'\x6e\x87\x5f\xf1\x8c\x22\x76\x59\xad\x61\x43\xbb\x35\x80\xc6\x57\x00\x73\x48\x84',
885 885 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
886 886 > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
887 887 > ]}]
888 888 > fields eval:[b'revision']
889 889 > EOF
890 890 creating http peer for wire protocol version 2
891 891 sending filesdata command
892 892 response: gen[
893 893 {
894 894 b'totalitems': 12,
895 895 b'totalpaths': 9
896 896 },
897 897 {
898 898 b'path': b'a',
899 899 b'totalitems': 2
900 900 },
901 901 {
902 902 b'fieldsfollowing': [
903 903 [
904 904 b'revision',
905 905 81
906 906 ]
907 907 ],
908 908 b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9'
909 909 },
910 910 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\n',
911 911 {
912 912 b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
913 913 b'fieldsfollowing': [
914 914 [
915 915 b'delta',
916 916 15
917 917 ]
918 918 ],
919 919 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
920 920 },
921 921 b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n',
922 922 {
923 923 b'path': b'b',
924 924 b'totalitems': 1
925 925 },
926 926 {
927 927 b'fieldsfollowing': [
928 928 [
929 929 b'revision',
930 930 81
931 931 ]
932 932 ],
933 933 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
934 934 },
935 935 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
936 936 {
937 937 b'path': b'dir0/c',
938 938 b'totalitems': 1
939 939 },
940 940 {
941 941 b'fieldsfollowing': [
942 942 [
943 943 b'revision',
944 944 3
945 945 ]
946 946 ],
947 947 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
948 948 },
949 949 b'c0\n',
950 950 {
951 951 b'path': b'dir0/child0/e',
952 952 b'totalitems': 1
953 953 },
954 954 {
955 955 b'fieldsfollowing': [
956 956 [
957 957 b'revision',
958 958 3
959 959 ]
960 960 ],
961 961 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
962 962 },
963 963 b'e0\n',
964 964 {
965 965 b'path': b'dir0/child1/f',
966 966 b'totalitems': 2
967 967 },
968 968 {
969 969 b'fieldsfollowing': [
970 970 [
971 971 b'revision',
972 972 3
973 973 ]
974 974 ],
975 975 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
976 976 },
977 977 b'f0\n',
978 978 {
979 979 b'deltabasenode': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4',
980 980 b'fieldsfollowing': [
981 981 [
982 982 b'delta',
983 983 15
984 984 ]
985 985 ],
986 986 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
987 987 },
988 988 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03f1\n',
989 989 {
990 990 b'path': b'dir0/d',
991 991 b'totalitems': 2
992 992 },
993 993 {
994 994 b'fieldsfollowing': [
995 995 [
996 996 b'revision',
997 997 3
998 998 ]
999 999 ],
1000 1000 b'node': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&'
1001 1001 },
1002 1002 b'd0\n',
1003 1003 {
1004 1004 b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
1005 1005 b'fieldsfollowing': [
1006 1006 [
1007 1007 b'delta',
1008 1008 15
1009 1009 ]
1010 1010 ],
1011 1011 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
1012 1012 },
1013 1013 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n',
1014 1014 {
1015 1015 b'path': b'dir0/i',
1016 1016 b'totalitems': 1
1017 1017 },
1018 1018 {
1019 1019 b'fieldsfollowing': [
1020 1020 [
1021 1021 b'revision',
1022 1022 3
1023 1023 ]
1024 1024 ],
1025 1025 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
1026 1026 },
1027 1027 b'i0\n',
1028 1028 {
1029 1029 b'path': b'g',
1030 1030 b'totalitems': 1
1031 1031 },
1032 1032 {
1033 1033 b'fieldsfollowing': [
1034 1034 [
1035 1035 b'revision',
1036 1036 3
1037 1037 ]
1038 1038 ],
1039 1039 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
1040 1040 },
1041 1041 b'g0\n',
1042 1042 {
1043 1043 b'path': b'h',
1044 1044 b'totalitems': 1
1045 1045 },
1046 1046 {
1047 1047 b'fieldsfollowing': [
1048 1048 [
1049 1049 b'revision',
1050 1050 3
1051 1051 ]
1052 1052 ],
1053 1053 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
1054 1054 },
1055 1055 b'h0\n'
1056 1056 ]
1057 1057
1058 Requesting linknode field works
1059
1060 $ sendhttpv2peer << EOF
1061 > command filesdata
1062 > revisions eval:[{
1063 > b'type': b'changesetexplicit',
1064 > b'nodes': [
1065 > b'\x6e\x87\x5f\xf1\x8c\x22\x76\x59\xad\x61\x43\xbb\x35\x80\xc6\x57\x00\x73\x48\x84',
1066 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
1067 > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
1068 > ]}]
1069 > fields eval:[b'linknode']
1070 > EOF
1071 creating http peer for wire protocol version 2
1072 sending filesdata command
1073 response: gen[
1074 {
1075 b'totalitems': 12,
1076 b'totalpaths': 9
1077 },
1078 {
1079 b'path': b'a',
1080 b'totalitems': 2
1081 },
1082 {
1083 b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
1084 b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9'
1085 },
1086 {
1087 b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8',
1088 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
1089 },
1090 {
1091 b'path': b'b',
1092 b'totalitems': 1
1093 },
1094 {
1095 b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
1096 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
1097 },
1098 {
1099 b'path': b'dir0/c',
1100 b'totalitems': 1
1101 },
1102 {
1103 b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
1104 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
1105 },
1106 {
1107 b'path': b'dir0/child0/e',
1108 b'totalitems': 1
1109 },
1110 {
1111 b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
1112 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
1113 },
1114 {
1115 b'path': b'dir0/child1/f',
1116 b'totalitems': 2
1117 },
1118 {
1119 b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
1120 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
1121 },
1122 {
1123 b'linknode': b'\xb9\x1c\x03\xcb\xba5\x19\xab\x14\x9bl\xd0\xa0\xaf\xbd\xb5\xcf\x1b\\\x8a',
1124 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
1125 },
1126 {
1127 b'path': b'dir0/d',
1128 b'totalitems': 2
1129 },
1130 {
1131 b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
1132 b'node': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&'
1133 },
1134 {
1135 b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8',
1136 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
1137 },
1138 {
1139 b'path': b'dir0/i',
1140 b'totalitems': 1
1141 },
1142 {
1143 b'linknode': b'\xb9\x1c\x03\xcb\xba5\x19\xab\x14\x9bl\xd0\xa0\xaf\xbd\xb5\xcf\x1b\\\x8a',
1144 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
1145 },
1146 {
1147 b'path': b'g',
1148 b'totalitems': 1
1149 },
1150 {
1151 b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8',
1152 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
1153 },
1154 {
1155 b'path': b'h',
1156 b'totalitems': 1
1157 },
1158 {
1159 b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8',
1160 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
1161 }
1162 ]
1163
1058 1164 $ cat error.log
@@ -1,1462 +1,1470 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: 2241\r\n
68 s> Content-Length: 2259\r\n
69 69 s> \r\n
70 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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> 6bf\r\n
100 s> \xb7\x06\x00\x01\x00\x02\x041
101 s> \xa5Hcommands\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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> 6d1\r\n
100 s> \xc9\x06\x00\x01\x00\x02\x041
101 s> \xa5Hcommands\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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=1719; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
103 received frame(size=1737; 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 b'linknode',
154 155 b'parents',
155 156 b'revision'
156 157 ])
157 158 },
158 159 b'haveparents': {
159 160 b'default': False,
160 161 b'required': False,
161 162 b'type': b'bool'
162 163 },
163 164 b'nodes': {
164 165 b'required': True,
165 166 b'type': b'list'
166 167 },
167 168 b'path': {
168 169 b'required': True,
169 170 b'type': b'bytes'
170 171 }
171 172 },
172 173 b'permissions': [
173 174 b'pull'
174 175 ]
175 176 },
176 177 b'filesdata': {
177 178 b'args': {
178 179 b'fields': {
179 180 b'default': set([]),
180 181 b'required': False,
181 182 b'type': b'set',
182 183 b'validvalues': set([
183 184 b'firstchangeset',
185 b'linknode',
184 186 b'parents',
185 187 b'revision'
186 188 ])
187 189 },
188 190 b'haveparents': {
189 191 b'default': False,
190 192 b'required': False,
191 193 b'type': b'bool'
192 194 },
193 195 b'pathfilter': {
194 196 b'default': None,
195 197 b'required': False,
196 198 b'type': b'dict'
197 199 },
198 200 b'revisions': {
199 201 b'required': True,
200 202 b'type': b'list'
201 203 }
202 204 },
203 205 b'permissions': [
204 206 b'pull'
205 207 ],
206 208 b'recommendedbatchsize': 50000
207 209 },
208 210 b'heads': {
209 211 b'args': {
210 212 b'publiconly': {
211 213 b'default': False,
212 214 b'required': False,
213 215 b'type': b'bool'
214 216 }
215 217 },
216 218 b'permissions': [
217 219 b'pull'
218 220 ]
219 221 },
220 222 b'known': {
221 223 b'args': {
222 224 b'nodes': {
223 225 b'default': [],
224 226 b'required': False,
225 227 b'type': b'list'
226 228 }
227 229 },
228 230 b'permissions': [
229 231 b'pull'
230 232 ]
231 233 },
232 234 b'listkeys': {
233 235 b'args': {
234 236 b'namespace': {
235 237 b'required': True,
236 238 b'type': b'bytes'
237 239 }
238 240 },
239 241 b'permissions': [
240 242 b'pull'
241 243 ]
242 244 },
243 245 b'lookup': {
244 246 b'args': {
245 247 b'key': {
246 248 b'required': True,
247 249 b'type': b'bytes'
248 250 }
249 251 },
250 252 b'permissions': [
251 253 b'pull'
252 254 ]
253 255 },
254 256 b'manifestdata': {
255 257 b'args': {
256 258 b'fields': {
257 259 b'default': set([]),
258 260 b'required': False,
259 261 b'type': b'set',
260 262 b'validvalues': set([
261 263 b'parents',
262 264 b'revision'
263 265 ])
264 266 },
265 267 b'haveparents': {
266 268 b'default': False,
267 269 b'required': False,
268 270 b'type': b'bool'
269 271 },
270 272 b'nodes': {
271 273 b'required': True,
272 274 b'type': b'list'
273 275 },
274 276 b'tree': {
275 277 b'required': True,
276 278 b'type': b'bytes'
277 279 }
278 280 },
279 281 b'permissions': [
280 282 b'pull'
281 283 ],
282 284 b'recommendedbatchsize': 100000
283 285 },
284 286 b'pushkey': {
285 287 b'args': {
286 288 b'key': {
287 289 b'required': True,
288 290 b'type': b'bytes'
289 291 },
290 292 b'namespace': {
291 293 b'required': True,
292 294 b'type': b'bytes'
293 295 },
294 296 b'new': {
295 297 b'required': True,
296 298 b'type': b'bytes'
297 299 },
298 300 b'old': {
299 301 b'required': True,
300 302 b'type': b'bytes'
301 303 }
302 304 },
303 305 b'permissions': [
304 306 b'push'
305 307 ]
306 308 },
307 309 b'rawstorefiledata': {
308 310 b'args': {
309 311 b'files': {
310 312 b'required': True,
311 313 b'type': b'list'
312 314 },
313 315 b'pathfilter': {
314 316 b'default': None,
315 317 b'required': False,
316 318 b'type': b'list'
317 319 }
318 320 },
319 321 b'permissions': [
320 322 b'pull'
321 323 ]
322 324 }
323 325 },
324 326 b'framingmediatypes': [
325 327 b'application/mercurial-exp-framing-0006'
326 328 ],
327 329 b'pathfilterprefixes': set([
328 330 b'path:',
329 331 b'rootfilesin:'
330 332 ]),
331 333 b'rawrepoformats': [
332 334 b'generaldelta',
333 335 b'revlogv1'
334 336 ],
335 337 b'redirect': {
336 338 b'hashes': [
337 339 b'sha256',
338 340 b'sha1'
339 341 ],
340 342 b'targets': [
341 343 {
342 344 b'name': b'target-a',
343 345 b'protocol': b'http',
344 346 b'snirequired': False,
345 347 b'tlsversions': [
346 348 b'1.2',
347 349 b'1.3'
348 350 ],
349 351 b'uris': [
350 352 b'http://example.com/'
351 353 ]
352 354 }
353 355 ]
354 356 }
355 357 }
356 358 ]
357 359 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
358 360
359 361 Unknown protocol is filtered from compatible targets
360 362
361 363 $ cat > redirects.py << EOF
362 364 > [
363 365 > {
364 366 > b'name': b'target-a',
365 367 > b'protocol': b'http',
366 368 > b'uris': [b'http://example.com/'],
367 369 > },
368 370 > {
369 371 > b'name': b'target-b',
370 372 > b'protocol': b'unknown',
371 373 > b'uris': [b'unknown://example.com/'],
372 374 > },
373 375 > ]
374 376 > EOF
375 377
376 378 $ sendhttpv2peerhandshake << EOF
377 379 > command capabilities
378 380 > EOF
379 381 creating http peer for wire protocol version 2
380 382 s> GET /?cmd=capabilities HTTP/1.1\r\n
381 383 s> Accept-Encoding: identity\r\n
382 384 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
383 385 s> x-hgproto-1: cbor\r\n
384 386 s> x-hgupgrade-1: exp-http-v2-0003\r\n
385 387 s> accept: application/mercurial-0.1\r\n
386 388 s> host: $LOCALIP:$HGPORT\r\n (glob)
387 389 s> user-agent: Mercurial debugwireproto\r\n
388 390 s> \r\n
389 391 s> makefile('rb', None)
390 392 s> HTTP/1.1 200 OK\r\n
391 393 s> Server: testing stub value\r\n
392 394 s> Date: $HTTP_DATE$\r\n
393 395 s> Content-Type: application/mercurial-cbor\r\n
394 s> Content-Length: 2268\r\n
396 s> Content-Length: 2286\r\n
395 397 s> \r\n
396 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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
398 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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
397 399 (remote redirect target target-a is compatible)
398 400 (remote redirect target target-b uses unsupported protocol: unknown)
399 401 sending capabilities command
400 402 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
401 403 s> Accept-Encoding: identity\r\n
402 404 s> accept: application/mercurial-exp-framing-0006\r\n
403 405 s> content-type: application/mercurial-exp-framing-0006\r\n
404 406 s> content-length: 111\r\n
405 407 s> host: $LOCALIP:$HGPORT\r\n (glob)
406 408 s> user-agent: Mercurial debugwireproto\r\n
407 409 s> \r\n
408 410 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
409 411 s> makefile('rb', None)
410 412 s> HTTP/1.1 200 OK\r\n
411 413 s> Server: testing stub value\r\n
412 414 s> Date: $HTTP_DATE$\r\n
413 415 s> Content-Type: application/mercurial-exp-framing-0006\r\n
414 416 s> Transfer-Encoding: chunked\r\n
415 417 s> \r\n
416 418 s> 11\r\n
417 419 s> \t\x00\x00\x01\x00\x02\x01\x92
418 420 s> Hidentity
419 421 s> \r\n
420 422 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
421 423 s> 13\r\n
422 424 s> \x0b\x00\x00\x01\x00\x02\x041
423 425 s> \xa1FstatusBok
424 426 s> \r\n
425 427 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
426 s> 6da\r\n
427 s> \xd2\x06\x00\x01\x00\x02\x041
428 s> \xa5Hcommands\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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/
428 s> 6ec\r\n
429 s> \xe4\x06\x00\x01\x00\x02\x041
430 s> \xa5Hcommands\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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/
429 431 s> \r\n
430 received frame(size=1746; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
432 received frame(size=1764; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
431 433 s> 8\r\n
432 434 s> \x00\x00\x00\x01\x00\x02\x002
433 435 s> \r\n
434 436 s> 0\r\n
435 437 s> \r\n
436 438 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
437 439 response: gen[
438 440 {
439 441 b'commands': {
440 442 b'branchmap': {
441 443 b'args': {},
442 444 b'permissions': [
443 445 b'pull'
444 446 ]
445 447 },
446 448 b'capabilities': {
447 449 b'args': {},
448 450 b'permissions': [
449 451 b'pull'
450 452 ]
451 453 },
452 454 b'changesetdata': {
453 455 b'args': {
454 456 b'fields': {
455 457 b'default': set([]),
456 458 b'required': False,
457 459 b'type': b'set',
458 460 b'validvalues': set([
459 461 b'bookmarks',
460 462 b'parents',
461 463 b'phase',
462 464 b'revision'
463 465 ])
464 466 },
465 467 b'revisions': {
466 468 b'required': True,
467 469 b'type': b'list'
468 470 }
469 471 },
470 472 b'permissions': [
471 473 b'pull'
472 474 ]
473 475 },
474 476 b'filedata': {
475 477 b'args': {
476 478 b'fields': {
477 479 b'default': set([]),
478 480 b'required': False,
479 481 b'type': b'set',
480 482 b'validvalues': set([
483 b'linknode',
481 484 b'parents',
482 485 b'revision'
483 486 ])
484 487 },
485 488 b'haveparents': {
486 489 b'default': False,
487 490 b'required': False,
488 491 b'type': b'bool'
489 492 },
490 493 b'nodes': {
491 494 b'required': True,
492 495 b'type': b'list'
493 496 },
494 497 b'path': {
495 498 b'required': True,
496 499 b'type': b'bytes'
497 500 }
498 501 },
499 502 b'permissions': [
500 503 b'pull'
501 504 ]
502 505 },
503 506 b'filesdata': {
504 507 b'args': {
505 508 b'fields': {
506 509 b'default': set([]),
507 510 b'required': False,
508 511 b'type': b'set',
509 512 b'validvalues': set([
510 513 b'firstchangeset',
514 b'linknode',
511 515 b'parents',
512 516 b'revision'
513 517 ])
514 518 },
515 519 b'haveparents': {
516 520 b'default': False,
517 521 b'required': False,
518 522 b'type': b'bool'
519 523 },
520 524 b'pathfilter': {
521 525 b'default': None,
522 526 b'required': False,
523 527 b'type': b'dict'
524 528 },
525 529 b'revisions': {
526 530 b'required': True,
527 531 b'type': b'list'
528 532 }
529 533 },
530 534 b'permissions': [
531 535 b'pull'
532 536 ],
533 537 b'recommendedbatchsize': 50000
534 538 },
535 539 b'heads': {
536 540 b'args': {
537 541 b'publiconly': {
538 542 b'default': False,
539 543 b'required': False,
540 544 b'type': b'bool'
541 545 }
542 546 },
543 547 b'permissions': [
544 548 b'pull'
545 549 ]
546 550 },
547 551 b'known': {
548 552 b'args': {
549 553 b'nodes': {
550 554 b'default': [],
551 555 b'required': False,
552 556 b'type': b'list'
553 557 }
554 558 },
555 559 b'permissions': [
556 560 b'pull'
557 561 ]
558 562 },
559 563 b'listkeys': {
560 564 b'args': {
561 565 b'namespace': {
562 566 b'required': True,
563 567 b'type': b'bytes'
564 568 }
565 569 },
566 570 b'permissions': [
567 571 b'pull'
568 572 ]
569 573 },
570 574 b'lookup': {
571 575 b'args': {
572 576 b'key': {
573 577 b'required': True,
574 578 b'type': b'bytes'
575 579 }
576 580 },
577 581 b'permissions': [
578 582 b'pull'
579 583 ]
580 584 },
581 585 b'manifestdata': {
582 586 b'args': {
583 587 b'fields': {
584 588 b'default': set([]),
585 589 b'required': False,
586 590 b'type': b'set',
587 591 b'validvalues': set([
588 592 b'parents',
589 593 b'revision'
590 594 ])
591 595 },
592 596 b'haveparents': {
593 597 b'default': False,
594 598 b'required': False,
595 599 b'type': b'bool'
596 600 },
597 601 b'nodes': {
598 602 b'required': True,
599 603 b'type': b'list'
600 604 },
601 605 b'tree': {
602 606 b'required': True,
603 607 b'type': b'bytes'
604 608 }
605 609 },
606 610 b'permissions': [
607 611 b'pull'
608 612 ],
609 613 b'recommendedbatchsize': 100000
610 614 },
611 615 b'pushkey': {
612 616 b'args': {
613 617 b'key': {
614 618 b'required': True,
615 619 b'type': b'bytes'
616 620 },
617 621 b'namespace': {
618 622 b'required': True,
619 623 b'type': b'bytes'
620 624 },
621 625 b'new': {
622 626 b'required': True,
623 627 b'type': b'bytes'
624 628 },
625 629 b'old': {
626 630 b'required': True,
627 631 b'type': b'bytes'
628 632 }
629 633 },
630 634 b'permissions': [
631 635 b'push'
632 636 ]
633 637 },
634 638 b'rawstorefiledata': {
635 639 b'args': {
636 640 b'files': {
637 641 b'required': True,
638 642 b'type': b'list'
639 643 },
640 644 b'pathfilter': {
641 645 b'default': None,
642 646 b'required': False,
643 647 b'type': b'list'
644 648 }
645 649 },
646 650 b'permissions': [
647 651 b'pull'
648 652 ]
649 653 }
650 654 },
651 655 b'framingmediatypes': [
652 656 b'application/mercurial-exp-framing-0006'
653 657 ],
654 658 b'pathfilterprefixes': set([
655 659 b'path:',
656 660 b'rootfilesin:'
657 661 ]),
658 662 b'rawrepoformats': [
659 663 b'generaldelta',
660 664 b'revlogv1'
661 665 ],
662 666 b'redirect': {
663 667 b'hashes': [
664 668 b'sha256',
665 669 b'sha1'
666 670 ],
667 671 b'targets': [
668 672 {
669 673 b'name': b'target-a',
670 674 b'protocol': b'http',
671 675 b'uris': [
672 676 b'http://example.com/'
673 677 ]
674 678 },
675 679 {
676 680 b'name': b'target-b',
677 681 b'protocol': b'unknown',
678 682 b'uris': [
679 683 b'unknown://example.com/'
680 684 ]
681 685 }
682 686 ]
683 687 }
684 688 }
685 689 ]
686 690 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
687 691
688 692 Missing SNI support filters targets that require SNI
689 693
690 694 $ cat > nosni.py << EOF
691 695 > from mercurial import sslutil
692 696 > sslutil.hassni = False
693 697 > EOF
694 698 $ cat >> $HGRCPATH << EOF
695 699 > [extensions]
696 700 > nosni=`pwd`/nosni.py
697 701 > EOF
698 702
699 703 $ cat > redirects.py << EOF
700 704 > [
701 705 > {
702 706 > b'name': b'target-bad-tls',
703 707 > b'protocol': b'https',
704 708 > b'uris': [b'https://example.com/'],
705 709 > b'snirequired': True,
706 710 > },
707 711 > ]
708 712 > EOF
709 713
710 714 $ sendhttpv2peerhandshake << EOF
711 715 > command capabilities
712 716 > EOF
713 717 creating http peer for wire protocol version 2
714 718 s> GET /?cmd=capabilities HTTP/1.1\r\n
715 719 s> Accept-Encoding: identity\r\n
716 720 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
717 721 s> x-hgproto-1: cbor\r\n
718 722 s> x-hgupgrade-1: exp-http-v2-0003\r\n
719 723 s> accept: application/mercurial-0.1\r\n
720 724 s> host: $LOCALIP:$HGPORT\r\n (glob)
721 725 s> user-agent: Mercurial debugwireproto\r\n
722 726 s> \r\n
723 727 s> makefile('rb', None)
724 728 s> HTTP/1.1 200 OK\r\n
725 729 s> Server: testing stub value\r\n
726 730 s> Date: $HTTP_DATE$\r\n
727 731 s> Content-Type: application/mercurial-cbor\r\n
728 s> Content-Length: 2228\r\n
732 s> Content-Length: 2246\r\n
729 733 s> \r\n
730 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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
734 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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
731 735 (redirect target target-bad-tls requires SNI, which is unsupported)
732 736 sending capabilities command
733 737 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
734 738 s> Accept-Encoding: identity\r\n
735 739 s> accept: application/mercurial-exp-framing-0006\r\n
736 740 s> content-type: application/mercurial-exp-framing-0006\r\n
737 741 s> content-length: 102\r\n
738 742 s> host: $LOCALIP:$HGPORT\r\n (glob)
739 743 s> user-agent: Mercurial debugwireproto\r\n
740 744 s> \r\n
741 745 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
742 746 s> makefile('rb', None)
743 747 s> HTTP/1.1 200 OK\r\n
744 748 s> Server: testing stub value\r\n
745 749 s> Date: $HTTP_DATE$\r\n
746 750 s> Content-Type: application/mercurial-exp-framing-0006\r\n
747 751 s> Transfer-Encoding: chunked\r\n
748 752 s> \r\n
749 753 s> 11\r\n
750 754 s> \t\x00\x00\x01\x00\x02\x01\x92
751 755 s> Hidentity
752 756 s> \r\n
753 757 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
754 758 s> 13\r\n
755 759 s> \x0b\x00\x00\x01\x00\x02\x041
756 760 s> \xa1FstatusBok
757 761 s> \r\n
758 762 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
759 s> 6b2\r\n
760 s> \xaa\x06\x00\x01\x00\x02\x041
761 s> \xa5Hcommands\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
763 s> 6c4\r\n
764 s> \xbc\x06\x00\x01\x00\x02\x041
765 s> \xa5Hcommands\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
762 766 s> \r\n
763 received frame(size=1706; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
767 received frame(size=1724; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
764 768 s> 8\r\n
765 769 s> \x00\x00\x00\x01\x00\x02\x002
766 770 s> \r\n
767 771 s> 0\r\n
768 772 s> \r\n
769 773 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
770 774 response: gen[
771 775 {
772 776 b'commands': {
773 777 b'branchmap': {
774 778 b'args': {},
775 779 b'permissions': [
776 780 b'pull'
777 781 ]
778 782 },
779 783 b'capabilities': {
780 784 b'args': {},
781 785 b'permissions': [
782 786 b'pull'
783 787 ]
784 788 },
785 789 b'changesetdata': {
786 790 b'args': {
787 791 b'fields': {
788 792 b'default': set([]),
789 793 b'required': False,
790 794 b'type': b'set',
791 795 b'validvalues': set([
792 796 b'bookmarks',
793 797 b'parents',
794 798 b'phase',
795 799 b'revision'
796 800 ])
797 801 },
798 802 b'revisions': {
799 803 b'required': True,
800 804 b'type': b'list'
801 805 }
802 806 },
803 807 b'permissions': [
804 808 b'pull'
805 809 ]
806 810 },
807 811 b'filedata': {
808 812 b'args': {
809 813 b'fields': {
810 814 b'default': set([]),
811 815 b'required': False,
812 816 b'type': b'set',
813 817 b'validvalues': set([
818 b'linknode',
814 819 b'parents',
815 820 b'revision'
816 821 ])
817 822 },
818 823 b'haveparents': {
819 824 b'default': False,
820 825 b'required': False,
821 826 b'type': b'bool'
822 827 },
823 828 b'nodes': {
824 829 b'required': True,
825 830 b'type': b'list'
826 831 },
827 832 b'path': {
828 833 b'required': True,
829 834 b'type': b'bytes'
830 835 }
831 836 },
832 837 b'permissions': [
833 838 b'pull'
834 839 ]
835 840 },
836 841 b'filesdata': {
837 842 b'args': {
838 843 b'fields': {
839 844 b'default': set([]),
840 845 b'required': False,
841 846 b'type': b'set',
842 847 b'validvalues': set([
843 848 b'firstchangeset',
849 b'linknode',
844 850 b'parents',
845 851 b'revision'
846 852 ])
847 853 },
848 854 b'haveparents': {
849 855 b'default': False,
850 856 b'required': False,
851 857 b'type': b'bool'
852 858 },
853 859 b'pathfilter': {
854 860 b'default': None,
855 861 b'required': False,
856 862 b'type': b'dict'
857 863 },
858 864 b'revisions': {
859 865 b'required': True,
860 866 b'type': b'list'
861 867 }
862 868 },
863 869 b'permissions': [
864 870 b'pull'
865 871 ],
866 872 b'recommendedbatchsize': 50000
867 873 },
868 874 b'heads': {
869 875 b'args': {
870 876 b'publiconly': {
871 877 b'default': False,
872 878 b'required': False,
873 879 b'type': b'bool'
874 880 }
875 881 },
876 882 b'permissions': [
877 883 b'pull'
878 884 ]
879 885 },
880 886 b'known': {
881 887 b'args': {
882 888 b'nodes': {
883 889 b'default': [],
884 890 b'required': False,
885 891 b'type': b'list'
886 892 }
887 893 },
888 894 b'permissions': [
889 895 b'pull'
890 896 ]
891 897 },
892 898 b'listkeys': {
893 899 b'args': {
894 900 b'namespace': {
895 901 b'required': True,
896 902 b'type': b'bytes'
897 903 }
898 904 },
899 905 b'permissions': [
900 906 b'pull'
901 907 ]
902 908 },
903 909 b'lookup': {
904 910 b'args': {
905 911 b'key': {
906 912 b'required': True,
907 913 b'type': b'bytes'
908 914 }
909 915 },
910 916 b'permissions': [
911 917 b'pull'
912 918 ]
913 919 },
914 920 b'manifestdata': {
915 921 b'args': {
916 922 b'fields': {
917 923 b'default': set([]),
918 924 b'required': False,
919 925 b'type': b'set',
920 926 b'validvalues': set([
921 927 b'parents',
922 928 b'revision'
923 929 ])
924 930 },
925 931 b'haveparents': {
926 932 b'default': False,
927 933 b'required': False,
928 934 b'type': b'bool'
929 935 },
930 936 b'nodes': {
931 937 b'required': True,
932 938 b'type': b'list'
933 939 },
934 940 b'tree': {
935 941 b'required': True,
936 942 b'type': b'bytes'
937 943 }
938 944 },
939 945 b'permissions': [
940 946 b'pull'
941 947 ],
942 948 b'recommendedbatchsize': 100000
943 949 },
944 950 b'pushkey': {
945 951 b'args': {
946 952 b'key': {
947 953 b'required': True,
948 954 b'type': b'bytes'
949 955 },
950 956 b'namespace': {
951 957 b'required': True,
952 958 b'type': b'bytes'
953 959 },
954 960 b'new': {
955 961 b'required': True,
956 962 b'type': b'bytes'
957 963 },
958 964 b'old': {
959 965 b'required': True,
960 966 b'type': b'bytes'
961 967 }
962 968 },
963 969 b'permissions': [
964 970 b'push'
965 971 ]
966 972 },
967 973 b'rawstorefiledata': {
968 974 b'args': {
969 975 b'files': {
970 976 b'required': True,
971 977 b'type': b'list'
972 978 },
973 979 b'pathfilter': {
974 980 b'default': None,
975 981 b'required': False,
976 982 b'type': b'list'
977 983 }
978 984 },
979 985 b'permissions': [
980 986 b'pull'
981 987 ]
982 988 }
983 989 },
984 990 b'framingmediatypes': [
985 991 b'application/mercurial-exp-framing-0006'
986 992 ],
987 993 b'pathfilterprefixes': set([
988 994 b'path:',
989 995 b'rootfilesin:'
990 996 ]),
991 997 b'rawrepoformats': [
992 998 b'generaldelta',
993 999 b'revlogv1'
994 1000 ],
995 1001 b'redirect': {
996 1002 b'hashes': [
997 1003 b'sha256',
998 1004 b'sha1'
999 1005 ],
1000 1006 b'targets': [
1001 1007 {
1002 1008 b'name': b'target-bad-tls',
1003 1009 b'protocol': b'https',
1004 1010 b'snirequired': True,
1005 1011 b'uris': [
1006 1012 b'https://example.com/'
1007 1013 ]
1008 1014 }
1009 1015 ]
1010 1016 }
1011 1017 }
1012 1018 ]
1013 1019 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1014 1020
1015 1021 $ cat >> $HGRCPATH << EOF
1016 1022 > [extensions]
1017 1023 > nosni=!
1018 1024 > EOF
1019 1025
1020 1026 Unknown tls value is filtered from compatible targets
1021 1027
1022 1028 $ cat > redirects.py << EOF
1023 1029 > [
1024 1030 > {
1025 1031 > b'name': b'target-bad-tls',
1026 1032 > b'protocol': b'https',
1027 1033 > b'uris': [b'https://example.com/'],
1028 1034 > b'tlsversions': [b'42', b'39'],
1029 1035 > },
1030 1036 > ]
1031 1037 > EOF
1032 1038
1033 1039 $ sendhttpv2peerhandshake << EOF
1034 1040 > command capabilities
1035 1041 > EOF
1036 1042 creating http peer for wire protocol version 2
1037 1043 s> GET /?cmd=capabilities HTTP/1.1\r\n
1038 1044 s> Accept-Encoding: identity\r\n
1039 1045 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
1040 1046 s> x-hgproto-1: cbor\r\n
1041 1047 s> x-hgupgrade-1: exp-http-v2-0003\r\n
1042 1048 s> accept: application/mercurial-0.1\r\n
1043 1049 s> host: $LOCALIP:$HGPORT\r\n (glob)
1044 1050 s> user-agent: Mercurial debugwireproto\r\n
1045 1051 s> \r\n
1046 1052 s> makefile('rb', None)
1047 1053 s> HTTP/1.1 200 OK\r\n
1048 1054 s> Server: testing stub value\r\n
1049 1055 s> Date: $HTTP_DATE$\r\n
1050 1056 s> Content-Type: application/mercurial-cbor\r\n
1051 s> Content-Length: 2234\r\n
1057 s> Content-Length: 2252\r\n
1052 1058 s> \r\n
1053 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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
1059 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\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
1054 1060 (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42)
1055 1061 sending capabilities command
1056 1062 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
1057 1063 s> Accept-Encoding: identity\r\n
1058 1064 s> accept: application/mercurial-exp-framing-0006\r\n
1059 1065 s> content-type: application/mercurial-exp-framing-0006\r\n
1060 1066 s> content-length: 102\r\n
1061 1067 s> host: $LOCALIP:$HGPORT\r\n (glob)
1062 1068 s> user-agent: Mercurial debugwireproto\r\n
1063 1069 s> \r\n
1064 1070 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
1065 1071 s> makefile('rb', None)
1066 1072 s> HTTP/1.1 200 OK\r\n
1067 1073 s> Server: testing stub value\r\n
1068 1074 s> Date: $HTTP_DATE$\r\n
1069 1075 s> Content-Type: application/mercurial-exp-framing-0006\r\n
1070 1076 s> Transfer-Encoding: chunked\r\n
1071 1077 s> \r\n
1072 1078 s> 11\r\n
1073 1079 s> \t\x00\x00\x01\x00\x02\x01\x92
1074 1080 s> Hidentity
1075 1081 s> \r\n
1076 1082 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
1077 1083 s> 13\r\n
1078 1084 s> \x0b\x00\x00\x01\x00\x02\x041
1079 1085 s> \xa1FstatusBok
1080 1086 s> \r\n
1081 1087 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
1082 s> 6b8\r\n
1083 s> \xb0\x06\x00\x01\x00\x02\x041
1084 s> \xa5Hcommands\xacIbranchmap\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
1088 s> 6ca\r\n
1089 s> \xc2\x06\x00\x01\x00\x02\x041
1090 s> \xa5Hcommands\xacIbranchmap\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\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\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\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
1085 1091 s> \r\n
1086 received frame(size=1712; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
1092 received frame(size=1730; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
1087 1093 s> 8\r\n
1088 1094 s> \x00\x00\x00\x01\x00\x02\x002
1089 1095 s> \r\n
1090 1096 s> 0\r\n
1091 1097 s> \r\n
1092 1098 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
1093 1099 response: gen[
1094 1100 {
1095 1101 b'commands': {
1096 1102 b'branchmap': {
1097 1103 b'args': {},
1098 1104 b'permissions': [
1099 1105 b'pull'
1100 1106 ]
1101 1107 },
1102 1108 b'capabilities': {
1103 1109 b'args': {},
1104 1110 b'permissions': [
1105 1111 b'pull'
1106 1112 ]
1107 1113 },
1108 1114 b'changesetdata': {
1109 1115 b'args': {
1110 1116 b'fields': {
1111 1117 b'default': set([]),
1112 1118 b'required': False,
1113 1119 b'type': b'set',
1114 1120 b'validvalues': set([
1115 1121 b'bookmarks',
1116 1122 b'parents',
1117 1123 b'phase',
1118 1124 b'revision'
1119 1125 ])
1120 1126 },
1121 1127 b'revisions': {
1122 1128 b'required': True,
1123 1129 b'type': b'list'
1124 1130 }
1125 1131 },
1126 1132 b'permissions': [
1127 1133 b'pull'
1128 1134 ]
1129 1135 },
1130 1136 b'filedata': {
1131 1137 b'args': {
1132 1138 b'fields': {
1133 1139 b'default': set([]),
1134 1140 b'required': False,
1135 1141 b'type': b'set',
1136 1142 b'validvalues': set([
1143 b'linknode',
1137 1144 b'parents',
1138 1145 b'revision'
1139 1146 ])
1140 1147 },
1141 1148 b'haveparents': {
1142 1149 b'default': False,
1143 1150 b'required': False,
1144 1151 b'type': b'bool'
1145 1152 },
1146 1153 b'nodes': {
1147 1154 b'required': True,
1148 1155 b'type': b'list'
1149 1156 },
1150 1157 b'path': {
1151 1158 b'required': True,
1152 1159 b'type': b'bytes'
1153 1160 }
1154 1161 },
1155 1162 b'permissions': [
1156 1163 b'pull'
1157 1164 ]
1158 1165 },
1159 1166 b'filesdata': {
1160 1167 b'args': {
1161 1168 b'fields': {
1162 1169 b'default': set([]),
1163 1170 b'required': False,
1164 1171 b'type': b'set',
1165 1172 b'validvalues': set([
1166 1173 b'firstchangeset',
1174 b'linknode',
1167 1175 b'parents',
1168 1176 b'revision'
1169 1177 ])
1170 1178 },
1171 1179 b'haveparents': {
1172 1180 b'default': False,
1173 1181 b'required': False,
1174 1182 b'type': b'bool'
1175 1183 },
1176 1184 b'pathfilter': {
1177 1185 b'default': None,
1178 1186 b'required': False,
1179 1187 b'type': b'dict'
1180 1188 },
1181 1189 b'revisions': {
1182 1190 b'required': True,
1183 1191 b'type': b'list'
1184 1192 }
1185 1193 },
1186 1194 b'permissions': [
1187 1195 b'pull'
1188 1196 ],
1189 1197 b'recommendedbatchsize': 50000
1190 1198 },
1191 1199 b'heads': {
1192 1200 b'args': {
1193 1201 b'publiconly': {
1194 1202 b'default': False,
1195 1203 b'required': False,
1196 1204 b'type': b'bool'
1197 1205 }
1198 1206 },
1199 1207 b'permissions': [
1200 1208 b'pull'
1201 1209 ]
1202 1210 },
1203 1211 b'known': {
1204 1212 b'args': {
1205 1213 b'nodes': {
1206 1214 b'default': [],
1207 1215 b'required': False,
1208 1216 b'type': b'list'
1209 1217 }
1210 1218 },
1211 1219 b'permissions': [
1212 1220 b'pull'
1213 1221 ]
1214 1222 },
1215 1223 b'listkeys': {
1216 1224 b'args': {
1217 1225 b'namespace': {
1218 1226 b'required': True,
1219 1227 b'type': b'bytes'
1220 1228 }
1221 1229 },
1222 1230 b'permissions': [
1223 1231 b'pull'
1224 1232 ]
1225 1233 },
1226 1234 b'lookup': {
1227 1235 b'args': {
1228 1236 b'key': {
1229 1237 b'required': True,
1230 1238 b'type': b'bytes'
1231 1239 }
1232 1240 },
1233 1241 b'permissions': [
1234 1242 b'pull'
1235 1243 ]
1236 1244 },
1237 1245 b'manifestdata': {
1238 1246 b'args': {
1239 1247 b'fields': {
1240 1248 b'default': set([]),
1241 1249 b'required': False,
1242 1250 b'type': b'set',
1243 1251 b'validvalues': set([
1244 1252 b'parents',
1245 1253 b'revision'
1246 1254 ])
1247 1255 },
1248 1256 b'haveparents': {
1249 1257 b'default': False,
1250 1258 b'required': False,
1251 1259 b'type': b'bool'
1252 1260 },
1253 1261 b'nodes': {
1254 1262 b'required': True,
1255 1263 b'type': b'list'
1256 1264 },
1257 1265 b'tree': {
1258 1266 b'required': True,
1259 1267 b'type': b'bytes'
1260 1268 }
1261 1269 },
1262 1270 b'permissions': [
1263 1271 b'pull'
1264 1272 ],
1265 1273 b'recommendedbatchsize': 100000
1266 1274 },
1267 1275 b'pushkey': {
1268 1276 b'args': {
1269 1277 b'key': {
1270 1278 b'required': True,
1271 1279 b'type': b'bytes'
1272 1280 },
1273 1281 b'namespace': {
1274 1282 b'required': True,
1275 1283 b'type': b'bytes'
1276 1284 },
1277 1285 b'new': {
1278 1286 b'required': True,
1279 1287 b'type': b'bytes'
1280 1288 },
1281 1289 b'old': {
1282 1290 b'required': True,
1283 1291 b'type': b'bytes'
1284 1292 }
1285 1293 },
1286 1294 b'permissions': [
1287 1295 b'push'
1288 1296 ]
1289 1297 },
1290 1298 b'rawstorefiledata': {
1291 1299 b'args': {
1292 1300 b'files': {
1293 1301 b'required': True,
1294 1302 b'type': b'list'
1295 1303 },
1296 1304 b'pathfilter': {
1297 1305 b'default': None,
1298 1306 b'required': False,
1299 1307 b'type': b'list'
1300 1308 }
1301 1309 },
1302 1310 b'permissions': [
1303 1311 b'pull'
1304 1312 ]
1305 1313 }
1306 1314 },
1307 1315 b'framingmediatypes': [
1308 1316 b'application/mercurial-exp-framing-0006'
1309 1317 ],
1310 1318 b'pathfilterprefixes': set([
1311 1319 b'path:',
1312 1320 b'rootfilesin:'
1313 1321 ]),
1314 1322 b'rawrepoformats': [
1315 1323 b'generaldelta',
1316 1324 b'revlogv1'
1317 1325 ],
1318 1326 b'redirect': {
1319 1327 b'hashes': [
1320 1328 b'sha256',
1321 1329 b'sha1'
1322 1330 ],
1323 1331 b'targets': [
1324 1332 {
1325 1333 b'name': b'target-bad-tls',
1326 1334 b'protocol': b'https',
1327 1335 b'tlsversions': [
1328 1336 b'42',
1329 1337 b'39'
1330 1338 ],
1331 1339 b'uris': [
1332 1340 b'https://example.com/'
1333 1341 ]
1334 1342 }
1335 1343 ]
1336 1344 }
1337 1345 }
1338 1346 ]
1339 1347 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1340 1348
1341 1349 Set up the server to issue content redirects to its built-in API server.
1342 1350
1343 1351 $ cat > redirects.py << EOF
1344 1352 > [
1345 1353 > {
1346 1354 > b'name': b'local',
1347 1355 > b'protocol': b'http',
1348 1356 > b'uris': [b'http://example.com/'],
1349 1357 > },
1350 1358 > ]
1351 1359 > EOF
1352 1360
1353 1361 Request to eventual cache URL should return 404 (validating the cache server works)
1354 1362
1355 1363 $ sendhttpraw << EOF
1356 1364 > httprequest GET api/simplecache/missingkey
1357 1365 > user-agent: test
1358 1366 > EOF
1359 1367 using raw connection to peer
1360 1368 s> GET /api/simplecache/missingkey HTTP/1.1\r\n
1361 1369 s> Accept-Encoding: identity\r\n
1362 1370 s> user-agent: test\r\n
1363 1371 s> host: $LOCALIP:$HGPORT\r\n (glob)
1364 1372 s> \r\n
1365 1373 s> makefile('rb', None)
1366 1374 s> HTTP/1.1 404 Not Found\r\n
1367 1375 s> Server: testing stub value\r\n
1368 1376 s> Date: $HTTP_DATE$\r\n
1369 1377 s> Content-Type: text/plain\r\n
1370 1378 s> Content-Length: 22\r\n
1371 1379 s> \r\n
1372 1380 s> key not found in cache
1373 1381
1374 1382 Send a cacheable request
1375 1383
1376 1384 $ sendhttpv2peer << EOF
1377 1385 > command manifestdata
1378 1386 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1379 1387 > tree eval:b''
1380 1388 > fields eval:[b'parents']
1381 1389 > EOF
1382 1390 creating http peer for wire protocol version 2
1383 1391 sending manifestdata command
1384 1392 response: gen[
1385 1393 {
1386 1394 b'totalitems': 1
1387 1395 },
1388 1396 {
1389 1397 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1390 1398 b'parents': [
1391 1399 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1392 1400 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1393 1401 ]
1394 1402 }
1395 1403 ]
1396 1404
1397 1405 Cached entry should be available on server
1398 1406
1399 1407 $ sendhttpraw << EOF
1400 1408 > httprequest GET api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c
1401 1409 > user-agent: test
1402 1410 > EOF
1403 1411 using raw connection to peer
1404 1412 s> GET /api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c HTTP/1.1\r\n
1405 1413 s> Accept-Encoding: identity\r\n
1406 1414 s> user-agent: test\r\n
1407 1415 s> host: $LOCALIP:$HGPORT\r\n (glob)
1408 1416 s> \r\n
1409 1417 s> makefile('rb', None)
1410 1418 s> HTTP/1.1 200 OK\r\n
1411 1419 s> Server: testing stub value\r\n
1412 1420 s> Date: $HTTP_DATE$\r\n
1413 1421 s> Content-Type: application/mercurial-cbor\r\n
1414 1422 s> Content-Length: 91\r\n
1415 1423 s> \r\n
1416 1424 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
1417 1425 cbor> [
1418 1426 {
1419 1427 b'totalitems': 1
1420 1428 },
1421 1429 {
1422 1430 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1423 1431 b'parents': [
1424 1432 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1425 1433 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1426 1434 ]
1427 1435 }
1428 1436 ]
1429 1437
1430 1438 2nd request should result in content redirect response
1431 1439
1432 1440 $ sendhttpv2peer << EOF
1433 1441 > command manifestdata
1434 1442 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1435 1443 > tree eval:b''
1436 1444 > fields eval:[b'parents']
1437 1445 > EOF
1438 1446 creating http peer for wire protocol version 2
1439 1447 sending manifestdata command
1440 1448 response: gen[
1441 1449 {
1442 1450 b'totalitems': 1
1443 1451 },
1444 1452 {
1445 1453 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1446 1454 b'parents': [
1447 1455 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1448 1456 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1449 1457 ]
1450 1458 }
1451 1459 ]
1452 1460
1453 1461 $ cat error.log
1454 1462 $ killdaemons.py
1455 1463
1456 1464 $ cat .hg/blackbox.log
1457 1465 *> cacher constructed for manifestdata (glob)
1458 1466 *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1459 1467 *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1460 1468 *> cacher constructed for manifestdata (glob)
1461 1469 *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1462 1470 *> 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