##// 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 **Experimental and under active development**
1 **Experimental and under active development**
2
2
3 This section documents the wire protocol commands exposed to transports
3 This section documents the wire protocol commands exposed to transports
4 using the frame-based protocol. The set of commands exposed through
4 using the frame-based protocol. The set of commands exposed through
5 these transports is distinct from the set of commands exposed to legacy
5 these transports is distinct from the set of commands exposed to legacy
6 transports.
6 transports.
7
7
8 The frame-based protocol uses CBOR to encode command execution requests.
8 The frame-based protocol uses CBOR to encode command execution requests.
9 All command arguments must be mapped to a specific or set of CBOR data
9 All command arguments must be mapped to a specific or set of CBOR data
10 types.
10 types.
11
11
12 The response to many commands is also CBOR. There is no common response
12 The response to many commands is also CBOR. There is no common response
13 format: each command defines its own response format.
13 format: each command defines its own response format.
14
14
15 TODOs
15 TODOs
16 =====
16 =====
17
17
18 * Add "node namespace" support to each command. In order to support
18 * Add "node namespace" support to each command. In order to support
19 SHA-1 hash transition, we want servers to be able to expose different
19 SHA-1 hash transition, we want servers to be able to expose different
20 "node namespaces" for the same data. Every command operating on nodes
20 "node namespaces" for the same data. Every command operating on nodes
21 should specify which "node namespace" it is operating on and responses
21 should specify which "node namespace" it is operating on and responses
22 should encode the "node namespace" accordingly.
22 should encode the "node namespace" accordingly.
23
23
24 Commands
24 Commands
25 ========
25 ========
26
26
27 The sections below detail all commands available to wire protocol version
27 The sections below detail all commands available to wire protocol version
28 2.
28 2.
29
29
30 branchmap
30 branchmap
31 ---------
31 ---------
32
32
33 Obtain heads in named branches.
33 Obtain heads in named branches.
34
34
35 Receives no arguments.
35 Receives no arguments.
36
36
37 The response is a map with bytestring keys defining the branch name.
37 The response is a map with bytestring keys defining the branch name.
38 Values are arrays of bytestring defining raw changeset nodes.
38 Values are arrays of bytestring defining raw changeset nodes.
39
39
40 capabilities
40 capabilities
41 ------------
41 ------------
42
42
43 Obtain the server's capabilities.
43 Obtain the server's capabilities.
44
44
45 Receives no arguments.
45 Receives no arguments.
46
46
47 This command is typically called only as part of the handshake during
47 This command is typically called only as part of the handshake during
48 initial connection establishment.
48 initial connection establishment.
49
49
50 The response is a map with bytestring keys defining server information.
50 The response is a map with bytestring keys defining server information.
51
51
52 The defined keys are:
52 The defined keys are:
53
53
54 commands
54 commands
55 A map defining available wire protocol commands on this server.
55 A map defining available wire protocol commands on this server.
56
56
57 Keys in the map are the names of commands that can be invoked. Values
57 Keys in the map are the names of commands that can be invoked. Values
58 are maps defining information about that command. The bytestring keys
58 are maps defining information about that command. The bytestring keys
59 are:
59 are:
60
60
61 args
61 args
62 (map) Describes arguments accepted by the command.
62 (map) Describes arguments accepted by the command.
63
63
64 Keys are bytestrings denoting the argument name.
64 Keys are bytestrings denoting the argument name.
65
65
66 Values are maps describing the argument. The map has the following
66 Values are maps describing the argument. The map has the following
67 bytestring keys:
67 bytestring keys:
68
68
69 default
69 default
70 (varied) The default value for this argument if not specified. Only
70 (varied) The default value for this argument if not specified. Only
71 present if ``required`` is not true.
71 present if ``required`` is not true.
72
72
73 required
73 required
74 (boolean) Whether the argument must be specified. Failure to send
74 (boolean) Whether the argument must be specified. Failure to send
75 required arguments will result in an error executing the command.
75 required arguments will result in an error executing the command.
76
76
77 type
77 type
78 (bytestring) The type of the argument. e.g. ``bytes`` or ``bool``.
78 (bytestring) The type of the argument. e.g. ``bytes`` or ``bool``.
79
79
80 validvalues
80 validvalues
81 (set) Values that are recognized for this argument. Some arguments
81 (set) Values that are recognized for this argument. Some arguments
82 only allow a fixed set of values to be specified. These arguments
82 only allow a fixed set of values to be specified. These arguments
83 may advertise that set in this key. If this set is advertised and
83 may advertise that set in this key. If this set is advertised and
84 a value not in this set is specified, the command should result
84 a value not in this set is specified, the command should result
85 in error.
85 in error.
86
86
87 permissions
87 permissions
88 An array of permissions required to execute this command.
88 An array of permissions required to execute this command.
89
89
90 *
90 *
91 (various) Individual commands may define extra keys that supplement
91 (various) Individual commands may define extra keys that supplement
92 generic command metadata. See the command definition for more.
92 generic command metadata. See the command definition for more.
93
93
94 framingmediatypes
94 framingmediatypes
95 An array of bytestrings defining the supported framing protocol
95 An array of bytestrings defining the supported framing protocol
96 media types. Servers will not accept media types not in this list.
96 media types. Servers will not accept media types not in this list.
97
97
98 pathfilterprefixes
98 pathfilterprefixes
99 (set of bytestring) Matcher prefixes that are recognized when performing
99 (set of bytestring) Matcher prefixes that are recognized when performing
100 path filtering. Specifying a path filter whose type/prefix does not
100 path filtering. Specifying a path filter whose type/prefix does not
101 match one in this set will likely be rejected by the server.
101 match one in this set will likely be rejected by the server.
102
102
103 rawrepoformats
103 rawrepoformats
104 An array of storage formats the repository is using. This set of
104 An array of storage formats the repository is using. This set of
105 requirements can be used to determine whether a client can read a
105 requirements can be used to determine whether a client can read a
106 *raw* copy of file data available.
106 *raw* copy of file data available.
107
107
108 redirect
108 redirect
109 A map declaring potential *content redirects* that may be used by this
109 A map declaring potential *content redirects* that may be used by this
110 server. Contains the following bytestring keys:
110 server. Contains the following bytestring keys:
111
111
112 targets
112 targets
113 (array of maps) Potential redirect targets. Values are maps describing
113 (array of maps) Potential redirect targets. Values are maps describing
114 this target in more detail. Each map has the following bytestring keys:
114 this target in more detail. Each map has the following bytestring keys:
115
115
116 name
116 name
117 (bytestring) Identifier for this target. The identifier will be used
117 (bytestring) Identifier for this target. The identifier will be used
118 by clients to uniquely identify this target.
118 by clients to uniquely identify this target.
119
119
120 protocol
120 protocol
121 (bytestring) High-level network protocol. Values can be
121 (bytestring) High-level network protocol. Values can be
122 ``http``, ```https``, ``ssh``, etc.
122 ``http``, ```https``, ``ssh``, etc.
123
123
124 uris
124 uris
125 (array of bytestrings) Representative URIs for this target.
125 (array of bytestrings) Representative URIs for this target.
126
126
127 snirequired (optional)
127 snirequired (optional)
128 (boolean) Indicates whether Server Name Indication is required
128 (boolean) Indicates whether Server Name Indication is required
129 to use this target. Defaults to False.
129 to use this target. Defaults to False.
130
130
131 tlsversions (optional)
131 tlsversions (optional)
132 (array of bytestring) Indicates which TLS versions are supported by
132 (array of bytestring) Indicates which TLS versions are supported by
133 this target. Values are ``1.1``, ``1.2``, ``1.3``, etc.
133 this target. Values are ``1.1``, ``1.2``, ``1.3``, etc.
134
134
135 hashes
135 hashes
136 (array of bytestring) Indicates support for hashing algorithms that are
136 (array of bytestring) Indicates support for hashing algorithms that are
137 used to ensure content integrity. Values include ``sha1``, ``sha256``,
137 used to ensure content integrity. Values include ``sha1``, ``sha256``,
138 etc.
138 etc.
139
139
140 changesetdata
140 changesetdata
141 -------------
141 -------------
142
142
143 Obtain various data related to changesets.
143 Obtain various data related to changesets.
144
144
145 The command accepts the following arguments:
145 The command accepts the following arguments:
146
146
147 revisions
147 revisions
148 (array of maps) Specifies revisions whose data is being requested. Each
148 (array of maps) Specifies revisions whose data is being requested. Each
149 value in the array is a map describing revisions. See the
149 value in the array is a map describing revisions. See the
150 *Revisions Specifiers* section below for the format of this map.
150 *Revisions Specifiers* section below for the format of this map.
151
151
152 Data will be sent for the union of all revisions resolved by all
152 Data will be sent for the union of all revisions resolved by all
153 revision specifiers.
153 revision specifiers.
154
154
155 Only revision specifiers operating on changeset revisions are allowed.
155 Only revision specifiers operating on changeset revisions are allowed.
156
156
157 fields
157 fields
158 (set of bytestring) Which data associated with changelog revisions to
158 (set of bytestring) Which data associated with changelog revisions to
159 fetch. The following values are recognized:
159 fetch. The following values are recognized:
160
160
161 bookmarks
161 bookmarks
162 Bookmarks associated with a revision.
162 Bookmarks associated with a revision.
163
163
164 parents
164 parents
165 Parent revisions.
165 Parent revisions.
166
166
167 phase
167 phase
168 The phase state of a revision.
168 The phase state of a revision.
169
169
170 revision
170 revision
171 The raw, revision data for the changelog entry. The hash of this data
171 The raw, revision data for the changelog entry. The hash of this data
172 will match the revision's node value.
172 will match the revision's node value.
173
173
174 The response bytestream starts with a CBOR map describing the data that follows.
174 The response bytestream starts with a CBOR map describing the data that follows.
175 This map has the following bytestring keys:
175 This map has the following bytestring keys:
176
176
177 totalitems
177 totalitems
178 (unsigned integer) Total number of changelog revisions whose data is being
178 (unsigned integer) Total number of changelog revisions whose data is being
179 transferred. This maps to the set of revisions in the requested node
179 transferred. This maps to the set of revisions in the requested node
180 range, not the total number of records that follow (see below for why).
180 range, not the total number of records that follow (see below for why).
181
181
182 Following the map header is a series of 0 or more CBOR values. If values
182 Following the map header is a series of 0 or more CBOR values. If values
183 are present, the first value will always be a map describing a single changeset
183 are present, the first value will always be a map describing a single changeset
184 revision.
184 revision.
185
185
186 If the ``fieldsfollowing`` key is present, the map will immediately be followed
186 If the ``fieldsfollowing`` key is present, the map will immediately be followed
187 by N CBOR bytestring values, where N is the number of elements in
187 by N CBOR bytestring values, where N is the number of elements in
188 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
188 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
189 by ``fieldsfollowing``.
189 by ``fieldsfollowing``.
190
190
191 Following the optional bytestring field values is the next revision descriptor
191 Following the optional bytestring field values is the next revision descriptor
192 map, or end of stream.
192 map, or end of stream.
193
193
194 Each revision descriptor map has the following bytestring keys:
194 Each revision descriptor map has the following bytestring keys:
195
195
196 node
196 node
197 (bytestring) The node value for this revision. This is the SHA-1 hash of
197 (bytestring) The node value for this revision. This is the SHA-1 hash of
198 the raw revision data.
198 the raw revision data.
199
199
200 bookmarks (optional)
200 bookmarks (optional)
201 (array of bytestrings) Bookmarks attached to this revision. Only present
201 (array of bytestrings) Bookmarks attached to this revision. Only present
202 if ``bookmarks`` data is being requested and the revision has bookmarks
202 if ``bookmarks`` data is being requested and the revision has bookmarks
203 attached.
203 attached.
204
204
205 fieldsfollowing (optional)
205 fieldsfollowing (optional)
206 (array of 2-array) Denotes what fields immediately follow this map. Each
206 (array of 2-array) Denotes what fields immediately follow this map. Each
207 value is an array with 2 elements: the bytestring field name and an unsigned
207 value is an array with 2 elements: the bytestring field name and an unsigned
208 integer describing the length of the data, in bytes.
208 integer describing the length of the data, in bytes.
209
209
210 If this key isn't present, no special fields will follow this map.
210 If this key isn't present, no special fields will follow this map.
211
211
212 The following fields may be present:
212 The following fields may be present:
213
213
214 revision
214 revision
215 Raw, revision data for the changelog entry. Contains a serialized form
215 Raw, revision data for the changelog entry. Contains a serialized form
216 of the changeset data, including the author, date, commit message, set
216 of the changeset data, including the author, date, commit message, set
217 of changed files, manifest node, and other metadata.
217 of changed files, manifest node, and other metadata.
218
218
219 Only present if the ``revision`` field was requested.
219 Only present if the ``revision`` field was requested.
220
220
221 parents (optional)
221 parents (optional)
222 (array of bytestrings) The nodes representing the parent revisions of this
222 (array of bytestrings) The nodes representing the parent revisions of this
223 revision. Only present if ``parents`` data is being requested.
223 revision. Only present if ``parents`` data is being requested.
224
224
225 phase (optional)
225 phase (optional)
226 (bytestring) The phase that a revision is in. Recognized values are
226 (bytestring) The phase that a revision is in. Recognized values are
227 ``secret``, ``draft``, and ``public``. Only present if ``phase`` data
227 ``secret``, ``draft``, and ``public``. Only present if ``phase`` data
228 is being requested.
228 is being requested.
229
229
230 The set of changeset revisions emitted may not match the exact set of
230 The set of changeset revisions emitted may not match the exact set of
231 changesets requested. Furthermore, the set of keys present on each
231 changesets requested. Furthermore, the set of keys present on each
232 map may vary. This is to facilitate emitting changeset updates as well
232 map may vary. This is to facilitate emitting changeset updates as well
233 as new revisions.
233 as new revisions.
234
234
235 For example, if the request wants ``phase`` and ``revision`` data,
235 For example, if the request wants ``phase`` and ``revision`` data,
236 the response may contain entries for each changeset in the common nodes
236 the response may contain entries for each changeset in the common nodes
237 set with the ``phase`` key and without the ``revision`` key in order
237 set with the ``phase`` key and without the ``revision`` key in order
238 to reflect a phase-only update.
238 to reflect a phase-only update.
239
239
240 TODO support different revision selection mechanisms (e.g. non-public, specific
240 TODO support different revision selection mechanisms (e.g. non-public, specific
241 revisions)
241 revisions)
242 TODO support different hash "namespaces" for revisions (e.g. sha-1 versus other)
242 TODO support different hash "namespaces" for revisions (e.g. sha-1 versus other)
243 TODO support emitting obsolescence data
243 TODO support emitting obsolescence data
244 TODO support filtering based on relevant paths (narrow clone)
244 TODO support filtering based on relevant paths (narrow clone)
245 TODO support hgtagsfnodes cache / tags data
245 TODO support hgtagsfnodes cache / tags data
246 TODO support branch heads cache
246 TODO support branch heads cache
247 TODO consider unify query mechanism. e.g. as an array of "query descriptors"
247 TODO consider unify query mechanism. e.g. as an array of "query descriptors"
248 rather than a set of top-level arguments that have semantics when combined.
248 rather than a set of top-level arguments that have semantics when combined.
249
249
250 filedata
250 filedata
251 --------
251 --------
252
252
253 Obtain various data related to an individual tracked file.
253 Obtain various data related to an individual tracked file.
254
254
255 The command accepts the following arguments:
255 The command accepts the following arguments:
256
256
257 fields
257 fields
258 (set of bytestring) Which data associated with a file to fetch.
258 (set of bytestring) Which data associated with a file to fetch.
259 The following values are recognized:
259 The following values are recognized:
260
260
261 linknode
262 The changeset node introducing this revision.
263
261 parents
264 parents
262 Parent nodes for the revision.
265 Parent nodes for the revision.
263
266
264 revision
267 revision
265 The raw revision data for a file.
268 The raw revision data for a file.
266
269
267 haveparents
270 haveparents
268 (bool) Whether the client has the parent revisions of all requested
271 (bool) Whether the client has the parent revisions of all requested
269 nodes. If set, the server may emit revision data as deltas against
272 nodes. If set, the server may emit revision data as deltas against
270 any parent revision. If not set, the server MUST only emit deltas for
273 any parent revision. If not set, the server MUST only emit deltas for
271 revisions previously emitted by this command.
274 revisions previously emitted by this command.
272
275
273 False is assumed in the absence of any value.
276 False is assumed in the absence of any value.
274
277
275 nodes
278 nodes
276 (array of bytestrings) File nodes whose data to retrieve.
279 (array of bytestrings) File nodes whose data to retrieve.
277
280
278 path
281 path
279 (bytestring) Path of the tracked file whose data to retrieve.
282 (bytestring) Path of the tracked file whose data to retrieve.
280
283
281 TODO allow specifying revisions via alternate means (such as from
284 TODO allow specifying revisions via alternate means (such as from
282 changeset revisions or ranges)
285 changeset revisions or ranges)
283
286
284 The response bytestream starts with a CBOR map describing the data that
287 The response bytestream starts with a CBOR map describing the data that
285 follows. It has the following bytestream keys:
288 follows. It has the following bytestream keys:
286
289
287 totalitems
290 totalitems
288 (unsigned integer) Total number of file revisions whose data is
291 (unsigned integer) Total number of file revisions whose data is
289 being returned.
292 being returned.
290
293
291 Following the map header is a series of 0 or more CBOR values. If values
294 Following the map header is a series of 0 or more CBOR values. If values
292 are present, the first value will always be a map describing a single changeset
295 are present, the first value will always be a map describing a single changeset
293 revision.
296 revision.
294
297
295 If the ``fieldsfollowing`` key is present, the map will immediately be followed
298 If the ``fieldsfollowing`` key is present, the map will immediately be followed
296 by N CBOR bytestring values, where N is the number of elements in
299 by N CBOR bytestring values, where N is the number of elements in
297 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
300 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
298 by ``fieldsfollowing``.
301 by ``fieldsfollowing``.
299
302
300 Following the optional bytestring field values is the next revision descriptor
303 Following the optional bytestring field values is the next revision descriptor
301 map, or end of stream.
304 map, or end of stream.
302
305
303 Each revision descriptor map has the following bytestring keys:
306 Each revision descriptor map has the following bytestring keys:
304
307
305 Each map has the following bytestring keys:
308 Each map has the following bytestring keys:
306
309
307 node
310 node
308 (bytestring) The node of the file revision whose data is represented.
311 (bytestring) The node of the file revision whose data is represented.
309
312
310 deltabasenode
313 deltabasenode
311 (bytestring) Node of the file revision the following delta is against.
314 (bytestring) Node of the file revision the following delta is against.
312
315
313 Only present if the ``revision`` field is requested and delta data
316 Only present if the ``revision`` field is requested and delta data
314 follows this map.
317 follows this map.
315
318
316 fieldsfollowing
319 fieldsfollowing
317 (array of 2-array) Denotes extra bytestring fields that following this map.
320 (array of 2-array) Denotes extra bytestring fields that following this map.
318 See the documentation for ``changesetdata`` for semantics.
321 See the documentation for ``changesetdata`` for semantics.
319
322
320 The following named fields may be present:
323 The following named fields may be present:
321
324
322 ``delta``
325 ``delta``
323 The delta data to use to construct the fulltext revision.
326 The delta data to use to construct the fulltext revision.
324
327
325 Only present if the ``revision`` field is requested and a delta is
328 Only present if the ``revision`` field is requested and a delta is
326 being emitted. The ``deltabasenode`` top-level key will also be
329 being emitted. The ``deltabasenode`` top-level key will also be
327 present if this field is being emitted.
330 present if this field is being emitted.
328
331
329 ``revision``
332 ``revision``
330 The fulltext revision data for this manifest. Only present if the
333 The fulltext revision data for this manifest. Only present if the
331 ``revision`` field is requested and a fulltext revision is being emitted.
334 ``revision`` field is requested and a fulltext revision is being emitted.
332
335
333 parents
336 parents
334 (array of bytestring) The nodes of the parents of this file revision.
337 (array of bytestring) The nodes of the parents of this file revision.
335
338
336 Only present if the ``parents`` field is requested.
339 Only present if the ``parents`` field is requested.
337
340
338 When ``revision`` data is requested, the server chooses to emit either fulltext
341 When ``revision`` data is requested, the server chooses to emit either fulltext
339 revision data or a delta. What the server decides can be inferred by looking
342 revision data or a delta. What the server decides can be inferred by looking
340 for the presence of the ``delta`` or ``revision`` keys in the
343 for the presence of the ``delta`` or ``revision`` keys in the
341 ``fieldsfollowing`` array.
344 ``fieldsfollowing`` array.
342
345
343 filesdata
346 filesdata
344 ---------
347 ---------
345
348
346 Obtain various data related to multiple tracked files for specific changesets.
349 Obtain various data related to multiple tracked files for specific changesets.
347
350
348 This command is similar to ``filedata`` with the main difference being that
351 This command is similar to ``filedata`` with the main difference being that
349 individual requests operate on multiple file paths. This allows clients to
352 individual requests operate on multiple file paths. This allows clients to
350 request data for multiple paths by issuing a single command.
353 request data for multiple paths by issuing a single command.
351
354
352 The command accepts the following arguments:
355 The command accepts the following arguments:
353
356
354 fields
357 fields
355 (set of bytestring) Which data associated with a file to fetch.
358 (set of bytestring) Which data associated with a file to fetch.
356 The following values are recognized:
359 The following values are recognized:
357
360
361 linknode
362 The changeset node introducing this revision.
363
358 parents
364 parents
359 Parent nodes for the revision.
365 Parent nodes for the revision.
360
366
361 revision
367 revision
362 The raw revision data for a file.
368 The raw revision data for a file.
363
369
364 haveparents
370 haveparents
365 (bool) Whether the client has the parent revisions of all requested
371 (bool) Whether the client has the parent revisions of all requested
366 nodes.
372 nodes.
367
373
368 pathfilter
374 pathfilter
369 (map) Defines a filter that determines what file paths are relevant.
375 (map) Defines a filter that determines what file paths are relevant.
370
376
371 See the *Path Filters* section for more.
377 See the *Path Filters* section for more.
372
378
373 If the argument is omitted, it is assumed that all paths are relevant.
379 If the argument is omitted, it is assumed that all paths are relevant.
374
380
375 revisions
381 revisions
376 (array of maps) Specifies revisions whose data is being requested. Each value
382 (array of maps) Specifies revisions whose data is being requested. Each value
377 in the array is a map describing revisions. See the *Revisions Specifiers*
383 in the array is a map describing revisions. See the *Revisions Specifiers*
378 section below for the format of this map.
384 section below for the format of this map.
379
385
380 Data will be sent for the union of all revisions resolved by all revision
386 Data will be sent for the union of all revisions resolved by all revision
381 specifiers.
387 specifiers.
382
388
383 Only revision specifiers operating on changeset revisions are allowed.
389 Only revision specifiers operating on changeset revisions are allowed.
384
390
385 The response bytestream starts with a CBOR map describing the data that
391 The response bytestream starts with a CBOR map describing the data that
386 follows. This map has the following bytestring keys:
392 follows. This map has the following bytestring keys:
387
393
388 totalpaths
394 totalpaths
389 (unsigned integer) Total number of paths whose data is being transferred.
395 (unsigned integer) Total number of paths whose data is being transferred.
390
396
391 totalitems
397 totalitems
392 (unsigned integer) Total number of file revisions whose data is being
398 (unsigned integer) Total number of file revisions whose data is being
393 transferred.
399 transferred.
394
400
395 Following the map header are 0 or more sequences of CBOR values. Each sequence
401 Following the map header are 0 or more sequences of CBOR values. Each sequence
396 represents data for a specific tracked path. Each sequence begins with a CBOR
402 represents data for a specific tracked path. Each sequence begins with a CBOR
397 map describing the file data that follows. Following that map is N CBOR values
403 map describing the file data that follows. Following that map is N CBOR values
398 describing file revision data. The format of this data is identical to that
404 describing file revision data. The format of this data is identical to that
399 returned by the ``filedata`` command.
405 returned by the ``filedata`` command.
400
406
401 Each sequence's map header has the following bytestring keys:
407 Each sequence's map header has the following bytestring keys:
402
408
403 path
409 path
404 (bytestring) The tracked file path whose data follows.
410 (bytestring) The tracked file path whose data follows.
405
411
406 totalitems
412 totalitems
407 (unsigned integer) Total number of file revisions whose data is being
413 (unsigned integer) Total number of file revisions whose data is being
408 transferred.
414 transferred.
409
415
410 The ``haveparents`` argument has significant implications on the data
416 The ``haveparents`` argument has significant implications on the data
411 transferred.
417 transferred.
412
418
413 When ``haveparents`` is true, the command MAY only emit data for file
419 When ``haveparents`` is true, the command MAY only emit data for file
414 revisions introduced by the set of changeset revisions whose data is being
420 revisions introduced by the set of changeset revisions whose data is being
415 requested. In other words, the command may assume that all file revisions
421 requested. In other words, the command may assume that all file revisions
416 for all relevant paths for ancestors of the requested changeset revisions
422 for all relevant paths for ancestors of the requested changeset revisions
417 are present on the receiver.
423 are present on the receiver.
418
424
419 When ``haveparents`` is false, the command MUST assume that the receiver
425 When ``haveparents`` is false, the command MUST assume that the receiver
420 has no file revisions data. This means that all referenced file revisions
426 has no file revisions data. This means that all referenced file revisions
421 in the queried set of changeset revisions will be sent.
427 in the queried set of changeset revisions will be sent.
422
428
423 TODO we'll probably want a more complicated mechanism for the client to
429 TODO we'll probably want a more complicated mechanism for the client to
424 specify which ancestor revisions are known.
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 heads
435 heads
427 -----
436 -----
428
437
429 Obtain DAG heads in the repository.
438 Obtain DAG heads in the repository.
430
439
431 The command accepts the following arguments:
440 The command accepts the following arguments:
432
441
433 publiconly (optional)
442 publiconly (optional)
434 (boolean) If set, operate on the DAG for public phase changesets only.
443 (boolean) If set, operate on the DAG for public phase changesets only.
435 Non-public (i.e. draft) phase DAG heads will not be returned.
444 Non-public (i.e. draft) phase DAG heads will not be returned.
436
445
437 The response is a CBOR array of bytestrings defining changeset nodes
446 The response is a CBOR array of bytestrings defining changeset nodes
438 of DAG heads. The array can be empty if the repository is empty or no
447 of DAG heads. The array can be empty if the repository is empty or no
439 changesets satisfied the request.
448 changesets satisfied the request.
440
449
441 TODO consider exposing phase of heads in response
450 TODO consider exposing phase of heads in response
442
451
443 known
452 known
444 -----
453 -----
445
454
446 Determine whether a series of changeset nodes is known to the server.
455 Determine whether a series of changeset nodes is known to the server.
447
456
448 The command accepts the following arguments:
457 The command accepts the following arguments:
449
458
450 nodes
459 nodes
451 (array of bytestrings) List of changeset nodes whose presence to
460 (array of bytestrings) List of changeset nodes whose presence to
452 query.
461 query.
453
462
454 The response is a bytestring where each byte contains a 0 or 1 for the
463 The response is a bytestring where each byte contains a 0 or 1 for the
455 corresponding requested node at the same index.
464 corresponding requested node at the same index.
456
465
457 TODO use a bit array for even more compact response
466 TODO use a bit array for even more compact response
458
467
459 listkeys
468 listkeys
460 --------
469 --------
461
470
462 List values in a specified ``pushkey`` namespace.
471 List values in a specified ``pushkey`` namespace.
463
472
464 The command receives the following arguments:
473 The command receives the following arguments:
465
474
466 namespace
475 namespace
467 (bytestring) Pushkey namespace to query.
476 (bytestring) Pushkey namespace to query.
468
477
469 The response is a map with bytestring keys and values.
478 The response is a map with bytestring keys and values.
470
479
471 TODO consider using binary to represent nodes in certain pushkey namespaces.
480 TODO consider using binary to represent nodes in certain pushkey namespaces.
472
481
473 lookup
482 lookup
474 ------
483 ------
475
484
476 Try to resolve a value to a changeset revision.
485 Try to resolve a value to a changeset revision.
477
486
478 Unlike ``known`` which operates on changeset nodes, lookup operates on
487 Unlike ``known`` which operates on changeset nodes, lookup operates on
479 node fragments and other names that a user may use.
488 node fragments and other names that a user may use.
480
489
481 The command receives the following arguments:
490 The command receives the following arguments:
482
491
483 key
492 key
484 (bytestring) Value to try to resolve.
493 (bytestring) Value to try to resolve.
485
494
486 On success, returns a bytestring containing the resolved node.
495 On success, returns a bytestring containing the resolved node.
487
496
488 manifestdata
497 manifestdata
489 ------------
498 ------------
490
499
491 Obtain various data related to manifests (which are lists of files in
500 Obtain various data related to manifests (which are lists of files in
492 a revision).
501 a revision).
493
502
494 The command accepts the following arguments:
503 The command accepts the following arguments:
495
504
496 fields
505 fields
497 (set of bytestring) Which data associated with manifests to fetch.
506 (set of bytestring) Which data associated with manifests to fetch.
498 The following values are recognized:
507 The following values are recognized:
499
508
500 parents
509 parents
501 Parent nodes for the manifest.
510 Parent nodes for the manifest.
502
511
503 revision
512 revision
504 The raw revision data for the manifest.
513 The raw revision data for the manifest.
505
514
506 haveparents
515 haveparents
507 (bool) Whether the client has the parent revisions of all requested
516 (bool) Whether the client has the parent revisions of all requested
508 nodes. If set, the server may emit revision data as deltas against
517 nodes. If set, the server may emit revision data as deltas against
509 any parent revision. If not set, the server MUST only emit deltas for
518 any parent revision. If not set, the server MUST only emit deltas for
510 revisions previously emitted by this command.
519 revisions previously emitted by this command.
511
520
512 False is assumed in the absence of any value.
521 False is assumed in the absence of any value.
513
522
514 nodes
523 nodes
515 (array of bytestring) Manifest nodes whose data to retrieve.
524 (array of bytestring) Manifest nodes whose data to retrieve.
516
525
517 tree
526 tree
518 (bytestring) Path to manifest to retrieve. The empty bytestring represents
527 (bytestring) Path to manifest to retrieve. The empty bytestring represents
519 the root manifest. All other values represent directories/trees within
528 the root manifest. All other values represent directories/trees within
520 the repository.
529 the repository.
521
530
522 TODO allow specifying revisions via alternate means (such as from changeset
531 TODO allow specifying revisions via alternate means (such as from changeset
523 revisions or ranges)
532 revisions or ranges)
524 TODO consider recursive expansion of manifests (with path filtering for
533 TODO consider recursive expansion of manifests (with path filtering for
525 narrow use cases)
534 narrow use cases)
526
535
527 The response bytestream starts with a CBOR map describing the data that
536 The response bytestream starts with a CBOR map describing the data that
528 follows. It has the following bytestring keys:
537 follows. It has the following bytestring keys:
529
538
530 totalitems
539 totalitems
531 (unsigned integer) Total number of manifest revisions whose data is
540 (unsigned integer) Total number of manifest revisions whose data is
532 being returned.
541 being returned.
533
542
534 Following the map header is a series of 0 or more CBOR values. If values
543 Following the map header is a series of 0 or more CBOR values. If values
535 are present, the first value will always be a map describing a single manifest
544 are present, the first value will always be a map describing a single manifest
536 revision.
545 revision.
537
546
538 If the ``fieldsfollowing`` key is present, the map will immediately be followed
547 If the ``fieldsfollowing`` key is present, the map will immediately be followed
539 by N CBOR bytestring values, where N is the number of elements in
548 by N CBOR bytestring values, where N is the number of elements in
540 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
549 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
541 by ``fieldsfollowing``.
550 by ``fieldsfollowing``.
542
551
543 Following the optional bytestring field values is the next revision descriptor
552 Following the optional bytestring field values is the next revision descriptor
544 map, or end of stream.
553 map, or end of stream.
545
554
546 Each revision descriptor map has the following bytestring keys:
555 Each revision descriptor map has the following bytestring keys:
547
556
548 node
557 node
549 (bytestring) The node of the manifest revision whose data is represented.
558 (bytestring) The node of the manifest revision whose data is represented.
550
559
551 deltabasenode
560 deltabasenode
552 (bytestring) The node that the delta representation of this revision is
561 (bytestring) The node that the delta representation of this revision is
553 computed against. Only present if the ``revision`` field is requested and
562 computed against. Only present if the ``revision`` field is requested and
554 a delta is being emitted.
563 a delta is being emitted.
555
564
556 fieldsfollowing
565 fieldsfollowing
557 (array of 2-array) Denotes extra bytestring fields that following this map.
566 (array of 2-array) Denotes extra bytestring fields that following this map.
558 See the documentation for ``changesetdata`` for semantics.
567 See the documentation for ``changesetdata`` for semantics.
559
568
560 The following named fields may be present:
569 The following named fields may be present:
561
570
562 ``delta``
571 ``delta``
563 The delta data to use to construct the fulltext revision.
572 The delta data to use to construct the fulltext revision.
564
573
565 Only present if the ``revision`` field is requested and a delta is
574 Only present if the ``revision`` field is requested and a delta is
566 being emitted. The ``deltabasenode`` top-level key will also be
575 being emitted. The ``deltabasenode`` top-level key will also be
567 present if this field is being emitted.
576 present if this field is being emitted.
568
577
569 ``revision``
578 ``revision``
570 The fulltext revision data for this manifest. Only present if the
579 The fulltext revision data for this manifest. Only present if the
571 ``revision`` field is requested and a fulltext revision is being emitted.
580 ``revision`` field is requested and a fulltext revision is being emitted.
572
581
573 parents
582 parents
574 (array of bytestring) The nodes of the parents of this manifest revision.
583 (array of bytestring) The nodes of the parents of this manifest revision.
575 Only present if the ``parents`` field is requested.
584 Only present if the ``parents`` field is requested.
576
585
577 When ``revision`` data is requested, the server chooses to emit either fulltext
586 When ``revision`` data is requested, the server chooses to emit either fulltext
578 revision data or a delta. What the server decides can be inferred by looking
587 revision data or a delta. What the server decides can be inferred by looking
579 for the presence of ``delta`` or ``revision`` in the ``fieldsfollowing`` array.
588 for the presence of ``delta`` or ``revision`` in the ``fieldsfollowing`` array.
580
589
581 Servers MAY advertise the following extra fields in the capabilities
590 Servers MAY advertise the following extra fields in the capabilities
582 descriptor for this command:
591 descriptor for this command:
583
592
584 recommendedbatchsize
593 recommendedbatchsize
585 (unsigned integer) Number of revisions the server recommends as a batch
594 (unsigned integer) Number of revisions the server recommends as a batch
586 query size. If defined, clients needing to issue multiple ``manifestdata``
595 query size. If defined, clients needing to issue multiple ``manifestdata``
587 commands to obtain needed data SHOULD construct their commands to have
596 commands to obtain needed data SHOULD construct their commands to have
588 this many revisions per request.
597 this many revisions per request.
589
598
590 pushkey
599 pushkey
591 -------
600 -------
592
601
593 Set a value using the ``pushkey`` protocol.
602 Set a value using the ``pushkey`` protocol.
594
603
595 The command receives the following arguments:
604 The command receives the following arguments:
596
605
597 namespace
606 namespace
598 (bytestring) Pushkey namespace to operate on.
607 (bytestring) Pushkey namespace to operate on.
599 key
608 key
600 (bytestring) The pushkey key to set.
609 (bytestring) The pushkey key to set.
601 old
610 old
602 (bytestring) Old value for this key.
611 (bytestring) Old value for this key.
603 new
612 new
604 (bytestring) New value for this key.
613 (bytestring) New value for this key.
605
614
606 TODO consider using binary to represent nodes is certain pushkey namespaces.
615 TODO consider using binary to represent nodes is certain pushkey namespaces.
607 TODO better define response type and meaning.
616 TODO better define response type and meaning.
608
617
609 rawstorefiledata
618 rawstorefiledata
610 ----------------
619 ----------------
611
620
612 Allows retrieving raw files used to store repository data.
621 Allows retrieving raw files used to store repository data.
613
622
614 The command accepts the following arguments:
623 The command accepts the following arguments:
615
624
616 files
625 files
617 (array of bytestring) Describes the files that should be retrieved.
626 (array of bytestring) Describes the files that should be retrieved.
618
627
619 The meaning of values in this array is dependent on the storage backend used
628 The meaning of values in this array is dependent on the storage backend used
620 by the server.
629 by the server.
621
630
622 The response bytestream starts with a CBOR map describing the data that follows.
631 The response bytestream starts with a CBOR map describing the data that follows.
623 This map has the following bytestring keys:
632 This map has the following bytestring keys:
624
633
625 filecount
634 filecount
626 (unsigned integer) Total number of files whose data is being transferred.
635 (unsigned integer) Total number of files whose data is being transferred.
627
636
628 totalsize
637 totalsize
629 (unsigned integer) Total size in bytes of files data that will be
638 (unsigned integer) Total size in bytes of files data that will be
630 transferred. This is file on-disk size and not wire size.
639 transferred. This is file on-disk size and not wire size.
631
640
632 Following the map header are N file segments. Each file segment consists of a
641 Following the map header are N file segments. Each file segment consists of a
633 CBOR map followed by an indefinite length bytestring. Each map has the following
642 CBOR map followed by an indefinite length bytestring. Each map has the following
634 bytestring keys:
643 bytestring keys:
635
644
636 location
645 location
637 (bytestring) Denotes the location in the repository where the file should be
646 (bytestring) Denotes the location in the repository where the file should be
638 written. Values map to vfs instances to use for the writing.
647 written. Values map to vfs instances to use for the writing.
639
648
640 path
649 path
641 (bytestring) Path of file being transferred. Path is the raw store
650 (bytestring) Path of file being transferred. Path is the raw store
642 path and can be any sequence of bytes that can be tracked in a Mercurial
651 path and can be any sequence of bytes that can be tracked in a Mercurial
643 manifest.
652 manifest.
644
653
645 size
654 size
646 (unsigned integer) Size of file data. This will be the final written
655 (unsigned integer) Size of file data. This will be the final written
647 file size. The total size of the data that follows the CBOR map
656 file size. The total size of the data that follows the CBOR map
648 will be greater due to encoding overhead of CBOR.
657 will be greater due to encoding overhead of CBOR.
649
658
650 TODO this command is woefully incomplete. If we are to move forward with a
659 TODO this command is woefully incomplete. If we are to move forward with a
651 stream clone analog, it needs a lot more metadata around how to describe what
660 stream clone analog, it needs a lot more metadata around how to describe what
652 files are available to retrieve, other semantics.
661 files are available to retrieve, other semantics.
653
662
654 Revision Specifiers
663 Revision Specifiers
655 ===================
664 ===================
656
665
657 A *revision specifier* is a map that evaluates to a set of revisions.
666 A *revision specifier* is a map that evaluates to a set of revisions.
658
667
659 A *revision specifier* has a ``type`` key that defines the revision
668 A *revision specifier* has a ``type`` key that defines the revision
660 selection type to perform. Other keys in the map are used in a
669 selection type to perform. Other keys in the map are used in a
661 type-specific manner.
670 type-specific manner.
662
671
663 The following types are defined:
672 The following types are defined:
664
673
665 changesetexplicit
674 changesetexplicit
666 An explicit set of enumerated changeset revisions.
675 An explicit set of enumerated changeset revisions.
667
676
668 The ``nodes`` key MUST contain an array of full binary nodes, expressed
677 The ``nodes`` key MUST contain an array of full binary nodes, expressed
669 as bytestrings.
678 as bytestrings.
670
679
671 changesetexplicitdepth
680 changesetexplicitdepth
672 Like ``changesetexplicit``, but contains a ``depth`` key defining the
681 Like ``changesetexplicit``, but contains a ``depth`` key defining the
673 unsigned integer number of ancestor revisions to also resolve. For each
682 unsigned integer number of ancestor revisions to also resolve. For each
674 value in ``nodes``, DAG ancestors will be walked until up to N total
683 value in ``nodes``, DAG ancestors will be walked until up to N total
675 revisions from that ancestry walk are present in the final resolved set.
684 revisions from that ancestry walk are present in the final resolved set.
676
685
677 changesetdagrange
686 changesetdagrange
678 Defines revisions via a DAG range of changesets on the changelog.
687 Defines revisions via a DAG range of changesets on the changelog.
679
688
680 The ``roots`` key MUST contain an array of full, binary node values
689 The ``roots`` key MUST contain an array of full, binary node values
681 representing the *root* revisions.
690 representing the *root* revisions.
682
691
683 The ``heads`` key MUST contain an array of full, binary nodes values
692 The ``heads`` key MUST contain an array of full, binary nodes values
684 representing the *head* revisions.
693 representing the *head* revisions.
685
694
686 The DAG range between ``roots`` and ``heads`` will be resolved and all
695 The DAG range between ``roots`` and ``heads`` will be resolved and all
687 revisions between will be used. Nodes in ``roots`` are not part of the
696 revisions between will be used. Nodes in ``roots`` are not part of the
688 resolved set. Nodes in ``heads`` are. The ``roots`` array may be empty.
697 resolved set. Nodes in ``heads`` are. The ``roots`` array may be empty.
689 The ``heads`` array MUST be defined.
698 The ``heads`` array MUST be defined.
690
699
691 Path Filters
700 Path Filters
692 ============
701 ============
693
702
694 Various commands accept a *path filter* argument that defines the set of file
703 Various commands accept a *path filter* argument that defines the set of file
695 paths relevant to the request.
704 paths relevant to the request.
696
705
697 A *path filter* is defined as a map with the bytestring keys ``include`` and
706 A *path filter* is defined as a map with the bytestring keys ``include`` and
698 ``exclude``. Each is an array of bytestring values. Each value defines a pattern
707 ``exclude``. Each is an array of bytestring values. Each value defines a pattern
699 rule (see :hg:`help patterns`) that is used to match file paths.
708 rule (see :hg:`help patterns`) that is used to match file paths.
700
709
701 A path matches the path filter if it is matched by a rule in the ``include``
710 A path matches the path filter if it is matched by a rule in the ``include``
702 set but doesn't match a rule in the ``exclude`` set. In other words, a path
711 set but doesn't match a rule in the ``exclude`` set. In other words, a path
703 matcher takes the union of all ``include`` patterns and then substracts the
712 matcher takes the union of all ``include`` patterns and then substracts the
704 union of all ``exclude`` patterns.
713 union of all ``exclude`` patterns.
705
714
706 Patterns MUST be prefixed with their pattern type. Only the following pattern
715 Patterns MUST be prefixed with their pattern type. Only the following pattern
707 types are allowed: ``path:``, ``rootfilesin:``.
716 types are allowed: ``path:``, ``rootfilesin:``.
708
717
709 If the ``include`` key is omitted, it is assumed that all paths are
718 If the ``include`` key is omitted, it is assumed that all paths are
710 relevant. The patterns from ``exclude`` will still be used, if defined.
719 relevant. The patterns from ``exclude`` will still be used, if defined.
711
720
712 An example value is ``path:tests/foo``, which would match a file named
721 An example value is ``path:tests/foo``, which would match a file named
713 ``tests/foo`` or a directory ``tests/foo`` and all files under it.
722 ``tests/foo`` or a directory ``tests/foo`` and all files under it.
@@ -1,1448 +1,1460 b''
1 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
1 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
2 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 #
3 #
4 # This software may be used and distributed according to the terms of the
4 # This software may be used and distributed according to the terms of the
5 # GNU General Public License version 2 or any later version.
5 # GNU General Public License version 2 or any later version.
6
6
7 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import collections
9 import collections
10 import contextlib
10 import contextlib
11 import hashlib
11 import hashlib
12
12
13 from .i18n import _
13 from .i18n import _
14 from .node import (
14 from .node import (
15 hex,
15 hex,
16 nullid,
16 nullid,
17 )
17 )
18 from . import (
18 from . import (
19 discovery,
19 discovery,
20 encoding,
20 encoding,
21 error,
21 error,
22 match as matchmod,
22 match as matchmod,
23 narrowspec,
23 narrowspec,
24 pycompat,
24 pycompat,
25 streamclone,
25 streamclone,
26 util,
26 util,
27 wireprotoframing,
27 wireprotoframing,
28 wireprototypes,
28 wireprototypes,
29 )
29 )
30 from .utils import (
30 from .utils import (
31 cborutil,
31 cborutil,
32 interfaceutil,
32 interfaceutil,
33 stringutil,
33 stringutil,
34 )
34 )
35
35
36 FRAMINGTYPE = b'application/mercurial-exp-framing-0006'
36 FRAMINGTYPE = b'application/mercurial-exp-framing-0006'
37
37
38 HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
38 HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
39
39
40 COMMANDS = wireprototypes.commanddict()
40 COMMANDS = wireprototypes.commanddict()
41
41
42 # Value inserted into cache key computation function. Change the value to
42 # Value inserted into cache key computation function. Change the value to
43 # force new cache keys for every command request. This should be done when
43 # force new cache keys for every command request. This should be done when
44 # there is a change to how caching works, etc.
44 # there is a change to how caching works, etc.
45 GLOBAL_CACHE_VERSION = 1
45 GLOBAL_CACHE_VERSION = 1
46
46
47 def handlehttpv2request(rctx, req, res, checkperm, urlparts):
47 def handlehttpv2request(rctx, req, res, checkperm, urlparts):
48 from .hgweb import common as hgwebcommon
48 from .hgweb import common as hgwebcommon
49
49
50 # URL space looks like: <permissions>/<command>, where <permission> can
50 # URL space looks like: <permissions>/<command>, where <permission> can
51 # be ``ro`` or ``rw`` to signal read-only or read-write, respectively.
51 # be ``ro`` or ``rw`` to signal read-only or read-write, respectively.
52
52
53 # Root URL does nothing meaningful... yet.
53 # Root URL does nothing meaningful... yet.
54 if not urlparts:
54 if not urlparts:
55 res.status = b'200 OK'
55 res.status = b'200 OK'
56 res.headers[b'Content-Type'] = b'text/plain'
56 res.headers[b'Content-Type'] = b'text/plain'
57 res.setbodybytes(_('HTTP version 2 API handler'))
57 res.setbodybytes(_('HTTP version 2 API handler'))
58 return
58 return
59
59
60 if len(urlparts) == 1:
60 if len(urlparts) == 1:
61 res.status = b'404 Not Found'
61 res.status = b'404 Not Found'
62 res.headers[b'Content-Type'] = b'text/plain'
62 res.headers[b'Content-Type'] = b'text/plain'
63 res.setbodybytes(_('do not know how to process %s\n') %
63 res.setbodybytes(_('do not know how to process %s\n') %
64 req.dispatchpath)
64 req.dispatchpath)
65 return
65 return
66
66
67 permission, command = urlparts[0:2]
67 permission, command = urlparts[0:2]
68
68
69 if permission not in (b'ro', b'rw'):
69 if permission not in (b'ro', b'rw'):
70 res.status = b'404 Not Found'
70 res.status = b'404 Not Found'
71 res.headers[b'Content-Type'] = b'text/plain'
71 res.headers[b'Content-Type'] = b'text/plain'
72 res.setbodybytes(_('unknown permission: %s') % permission)
72 res.setbodybytes(_('unknown permission: %s') % permission)
73 return
73 return
74
74
75 if req.method != 'POST':
75 if req.method != 'POST':
76 res.status = b'405 Method Not Allowed'
76 res.status = b'405 Method Not Allowed'
77 res.headers[b'Allow'] = b'POST'
77 res.headers[b'Allow'] = b'POST'
78 res.setbodybytes(_('commands require POST requests'))
78 res.setbodybytes(_('commands require POST requests'))
79 return
79 return
80
80
81 # At some point we'll want to use our own API instead of recycling the
81 # At some point we'll want to use our own API instead of recycling the
82 # behavior of version 1 of the wire protocol...
82 # behavior of version 1 of the wire protocol...
83 # TODO return reasonable responses - not responses that overload the
83 # TODO return reasonable responses - not responses that overload the
84 # HTTP status line message for error reporting.
84 # HTTP status line message for error reporting.
85 try:
85 try:
86 checkperm(rctx, req, 'pull' if permission == b'ro' else 'push')
86 checkperm(rctx, req, 'pull' if permission == b'ro' else 'push')
87 except hgwebcommon.ErrorResponse as e:
87 except hgwebcommon.ErrorResponse as e:
88 res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e))
88 res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e))
89 for k, v in e.headers:
89 for k, v in e.headers:
90 res.headers[k] = v
90 res.headers[k] = v
91 res.setbodybytes('permission denied')
91 res.setbodybytes('permission denied')
92 return
92 return
93
93
94 # We have a special endpoint to reflect the request back at the client.
94 # We have a special endpoint to reflect the request back at the client.
95 if command == b'debugreflect':
95 if command == b'debugreflect':
96 _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
96 _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
97 return
97 return
98
98
99 # Extra commands that we handle that aren't really wire protocol
99 # Extra commands that we handle that aren't really wire protocol
100 # commands. Think extra hard before making this hackery available to
100 # commands. Think extra hard before making this hackery available to
101 # extension.
101 # extension.
102 extracommands = {'multirequest'}
102 extracommands = {'multirequest'}
103
103
104 if command not in COMMANDS and command not in extracommands:
104 if command not in COMMANDS and command not in extracommands:
105 res.status = b'404 Not Found'
105 res.status = b'404 Not Found'
106 res.headers[b'Content-Type'] = b'text/plain'
106 res.headers[b'Content-Type'] = b'text/plain'
107 res.setbodybytes(_('unknown wire protocol command: %s\n') % command)
107 res.setbodybytes(_('unknown wire protocol command: %s\n') % command)
108 return
108 return
109
109
110 repo = rctx.repo
110 repo = rctx.repo
111 ui = repo.ui
111 ui = repo.ui
112
112
113 proto = httpv2protocolhandler(req, ui)
113 proto = httpv2protocolhandler(req, ui)
114
114
115 if (not COMMANDS.commandavailable(command, proto)
115 if (not COMMANDS.commandavailable(command, proto)
116 and command not in extracommands):
116 and command not in extracommands):
117 res.status = b'404 Not Found'
117 res.status = b'404 Not Found'
118 res.headers[b'Content-Type'] = b'text/plain'
118 res.headers[b'Content-Type'] = b'text/plain'
119 res.setbodybytes(_('invalid wire protocol command: %s') % command)
119 res.setbodybytes(_('invalid wire protocol command: %s') % command)
120 return
120 return
121
121
122 # TODO consider cases where proxies may add additional Accept headers.
122 # TODO consider cases where proxies may add additional Accept headers.
123 if req.headers.get(b'Accept') != FRAMINGTYPE:
123 if req.headers.get(b'Accept') != FRAMINGTYPE:
124 res.status = b'406 Not Acceptable'
124 res.status = b'406 Not Acceptable'
125 res.headers[b'Content-Type'] = b'text/plain'
125 res.headers[b'Content-Type'] = b'text/plain'
126 res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
126 res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
127 % FRAMINGTYPE)
127 % FRAMINGTYPE)
128 return
128 return
129
129
130 if req.headers.get(b'Content-Type') != FRAMINGTYPE:
130 if req.headers.get(b'Content-Type') != FRAMINGTYPE:
131 res.status = b'415 Unsupported Media Type'
131 res.status = b'415 Unsupported Media Type'
132 # TODO we should send a response with appropriate media type,
132 # TODO we should send a response with appropriate media type,
133 # since client does Accept it.
133 # since client does Accept it.
134 res.headers[b'Content-Type'] = b'text/plain'
134 res.headers[b'Content-Type'] = b'text/plain'
135 res.setbodybytes(_('client MUST send Content-Type header with '
135 res.setbodybytes(_('client MUST send Content-Type header with '
136 'value: %s\n') % FRAMINGTYPE)
136 'value: %s\n') % FRAMINGTYPE)
137 return
137 return
138
138
139 _processhttpv2request(ui, repo, req, res, permission, command, proto)
139 _processhttpv2request(ui, repo, req, res, permission, command, proto)
140
140
141 def _processhttpv2reflectrequest(ui, repo, req, res):
141 def _processhttpv2reflectrequest(ui, repo, req, res):
142 """Reads unified frame protocol request and dumps out state to client.
142 """Reads unified frame protocol request and dumps out state to client.
143
143
144 This special endpoint can be used to help debug the wire protocol.
144 This special endpoint can be used to help debug the wire protocol.
145
145
146 Instead of routing the request through the normal dispatch mechanism,
146 Instead of routing the request through the normal dispatch mechanism,
147 we instead read all frames, decode them, and feed them into our state
147 we instead read all frames, decode them, and feed them into our state
148 tracker. We then dump the log of all that activity back out to the
148 tracker. We then dump the log of all that activity back out to the
149 client.
149 client.
150 """
150 """
151 import json
151 import json
152
152
153 # Reflection APIs have a history of being abused, accidentally disclosing
153 # Reflection APIs have a history of being abused, accidentally disclosing
154 # sensitive data, etc. So we have a config knob.
154 # sensitive data, etc. So we have a config knob.
155 if not ui.configbool('experimental', 'web.api.debugreflect'):
155 if not ui.configbool('experimental', 'web.api.debugreflect'):
156 res.status = b'404 Not Found'
156 res.status = b'404 Not Found'
157 res.headers[b'Content-Type'] = b'text/plain'
157 res.headers[b'Content-Type'] = b'text/plain'
158 res.setbodybytes(_('debugreflect service not available'))
158 res.setbodybytes(_('debugreflect service not available'))
159 return
159 return
160
160
161 # We assume we have a unified framing protocol request body.
161 # We assume we have a unified framing protocol request body.
162
162
163 reactor = wireprotoframing.serverreactor(ui)
163 reactor = wireprotoframing.serverreactor(ui)
164 states = []
164 states = []
165
165
166 while True:
166 while True:
167 frame = wireprotoframing.readframe(req.bodyfh)
167 frame = wireprotoframing.readframe(req.bodyfh)
168
168
169 if not frame:
169 if not frame:
170 states.append(b'received: <no frame>')
170 states.append(b'received: <no frame>')
171 break
171 break
172
172
173 states.append(b'received: %d %d %d %s' % (frame.typeid, frame.flags,
173 states.append(b'received: %d %d %d %s' % (frame.typeid, frame.flags,
174 frame.requestid,
174 frame.requestid,
175 frame.payload))
175 frame.payload))
176
176
177 action, meta = reactor.onframerecv(frame)
177 action, meta = reactor.onframerecv(frame)
178 states.append(json.dumps((action, meta), sort_keys=True,
178 states.append(json.dumps((action, meta), sort_keys=True,
179 separators=(', ', ': ')))
179 separators=(', ', ': ')))
180
180
181 action, meta = reactor.oninputeof()
181 action, meta = reactor.oninputeof()
182 meta['action'] = action
182 meta['action'] = action
183 states.append(json.dumps(meta, sort_keys=True, separators=(', ',': ')))
183 states.append(json.dumps(meta, sort_keys=True, separators=(', ',': ')))
184
184
185 res.status = b'200 OK'
185 res.status = b'200 OK'
186 res.headers[b'Content-Type'] = b'text/plain'
186 res.headers[b'Content-Type'] = b'text/plain'
187 res.setbodybytes(b'\n'.join(states))
187 res.setbodybytes(b'\n'.join(states))
188
188
189 def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
189 def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
190 """Post-validation handler for HTTPv2 requests.
190 """Post-validation handler for HTTPv2 requests.
191
191
192 Called when the HTTP request contains unified frame-based protocol
192 Called when the HTTP request contains unified frame-based protocol
193 frames for evaluation.
193 frames for evaluation.
194 """
194 """
195 # TODO Some HTTP clients are full duplex and can receive data before
195 # TODO Some HTTP clients are full duplex and can receive data before
196 # the entire request is transmitted. Figure out a way to indicate support
196 # the entire request is transmitted. Figure out a way to indicate support
197 # for that so we can opt into full duplex mode.
197 # for that so we can opt into full duplex mode.
198 reactor = wireprotoframing.serverreactor(ui, deferoutput=True)
198 reactor = wireprotoframing.serverreactor(ui, deferoutput=True)
199 seencommand = False
199 seencommand = False
200
200
201 outstream = None
201 outstream = None
202
202
203 while True:
203 while True:
204 frame = wireprotoframing.readframe(req.bodyfh)
204 frame = wireprotoframing.readframe(req.bodyfh)
205 if not frame:
205 if not frame:
206 break
206 break
207
207
208 action, meta = reactor.onframerecv(frame)
208 action, meta = reactor.onframerecv(frame)
209
209
210 if action == 'wantframe':
210 if action == 'wantframe':
211 # Need more data before we can do anything.
211 # Need more data before we can do anything.
212 continue
212 continue
213 elif action == 'runcommand':
213 elif action == 'runcommand':
214 # Defer creating output stream because we need to wait for
214 # Defer creating output stream because we need to wait for
215 # protocol settings frames so proper encoding can be applied.
215 # protocol settings frames so proper encoding can be applied.
216 if not outstream:
216 if not outstream:
217 outstream = reactor.makeoutputstream()
217 outstream = reactor.makeoutputstream()
218
218
219 sentoutput = _httpv2runcommand(ui, repo, req, res, authedperm,
219 sentoutput = _httpv2runcommand(ui, repo, req, res, authedperm,
220 reqcommand, reactor, outstream,
220 reqcommand, reactor, outstream,
221 meta, issubsequent=seencommand)
221 meta, issubsequent=seencommand)
222
222
223 if sentoutput:
223 if sentoutput:
224 return
224 return
225
225
226 seencommand = True
226 seencommand = True
227
227
228 elif action == 'error':
228 elif action == 'error':
229 # TODO define proper error mechanism.
229 # TODO define proper error mechanism.
230 res.status = b'200 OK'
230 res.status = b'200 OK'
231 res.headers[b'Content-Type'] = b'text/plain'
231 res.headers[b'Content-Type'] = b'text/plain'
232 res.setbodybytes(meta['message'] + b'\n')
232 res.setbodybytes(meta['message'] + b'\n')
233 return
233 return
234 else:
234 else:
235 raise error.ProgrammingError(
235 raise error.ProgrammingError(
236 'unhandled action from frame processor: %s' % action)
236 'unhandled action from frame processor: %s' % action)
237
237
238 action, meta = reactor.oninputeof()
238 action, meta = reactor.oninputeof()
239 if action == 'sendframes':
239 if action == 'sendframes':
240 # We assume we haven't started sending the response yet. If we're
240 # We assume we haven't started sending the response yet. If we're
241 # wrong, the response type will raise an exception.
241 # wrong, the response type will raise an exception.
242 res.status = b'200 OK'
242 res.status = b'200 OK'
243 res.headers[b'Content-Type'] = FRAMINGTYPE
243 res.headers[b'Content-Type'] = FRAMINGTYPE
244 res.setbodygen(meta['framegen'])
244 res.setbodygen(meta['framegen'])
245 elif action == 'noop':
245 elif action == 'noop':
246 pass
246 pass
247 else:
247 else:
248 raise error.ProgrammingError('unhandled action from frame processor: %s'
248 raise error.ProgrammingError('unhandled action from frame processor: %s'
249 % action)
249 % action)
250
250
251 def _httpv2runcommand(ui, repo, req, res, authedperm, reqcommand, reactor,
251 def _httpv2runcommand(ui, repo, req, res, authedperm, reqcommand, reactor,
252 outstream, command, issubsequent):
252 outstream, command, issubsequent):
253 """Dispatch a wire protocol command made from HTTPv2 requests.
253 """Dispatch a wire protocol command made from HTTPv2 requests.
254
254
255 The authenticated permission (``authedperm``) along with the original
255 The authenticated permission (``authedperm``) along with the original
256 command from the URL (``reqcommand``) are passed in.
256 command from the URL (``reqcommand``) are passed in.
257 """
257 """
258 # We already validated that the session has permissions to perform the
258 # We already validated that the session has permissions to perform the
259 # actions in ``authedperm``. In the unified frame protocol, the canonical
259 # actions in ``authedperm``. In the unified frame protocol, the canonical
260 # command to run is expressed in a frame. However, the URL also requested
260 # command to run is expressed in a frame. However, the URL also requested
261 # to run a specific command. We need to be careful that the command we
261 # to run a specific command. We need to be careful that the command we
262 # run doesn't have permissions requirements greater than what was granted
262 # run doesn't have permissions requirements greater than what was granted
263 # by ``authedperm``.
263 # by ``authedperm``.
264 #
264 #
265 # Our rule for this is we only allow one command per HTTP request and
265 # Our rule for this is we only allow one command per HTTP request and
266 # that command must match the command in the URL. However, we make
266 # that command must match the command in the URL. However, we make
267 # an exception for the ``multirequest`` URL. This URL is allowed to
267 # an exception for the ``multirequest`` URL. This URL is allowed to
268 # execute multiple commands. We double check permissions of each command
268 # execute multiple commands. We double check permissions of each command
269 # as it is invoked to ensure there is no privilege escalation.
269 # as it is invoked to ensure there is no privilege escalation.
270 # TODO consider allowing multiple commands to regular command URLs
270 # TODO consider allowing multiple commands to regular command URLs
271 # iff each command is the same.
271 # iff each command is the same.
272
272
273 proto = httpv2protocolhandler(req, ui, args=command['args'])
273 proto = httpv2protocolhandler(req, ui, args=command['args'])
274
274
275 if reqcommand == b'multirequest':
275 if reqcommand == b'multirequest':
276 if not COMMANDS.commandavailable(command['command'], proto):
276 if not COMMANDS.commandavailable(command['command'], proto):
277 # TODO proper error mechanism
277 # TODO proper error mechanism
278 res.status = b'200 OK'
278 res.status = b'200 OK'
279 res.headers[b'Content-Type'] = b'text/plain'
279 res.headers[b'Content-Type'] = b'text/plain'
280 res.setbodybytes(_('wire protocol command not available: %s') %
280 res.setbodybytes(_('wire protocol command not available: %s') %
281 command['command'])
281 command['command'])
282 return True
282 return True
283
283
284 # TODO don't use assert here, since it may be elided by -O.
284 # TODO don't use assert here, since it may be elided by -O.
285 assert authedperm in (b'ro', b'rw')
285 assert authedperm in (b'ro', b'rw')
286 wirecommand = COMMANDS[command['command']]
286 wirecommand = COMMANDS[command['command']]
287 assert wirecommand.permission in ('push', 'pull')
287 assert wirecommand.permission in ('push', 'pull')
288
288
289 if authedperm == b'ro' and wirecommand.permission != 'pull':
289 if authedperm == b'ro' and wirecommand.permission != 'pull':
290 # TODO proper error mechanism
290 # TODO proper error mechanism
291 res.status = b'403 Forbidden'
291 res.status = b'403 Forbidden'
292 res.headers[b'Content-Type'] = b'text/plain'
292 res.headers[b'Content-Type'] = b'text/plain'
293 res.setbodybytes(_('insufficient permissions to execute '
293 res.setbodybytes(_('insufficient permissions to execute '
294 'command: %s') % command['command'])
294 'command: %s') % command['command'])
295 return True
295 return True
296
296
297 # TODO should we also call checkperm() here? Maybe not if we're going
297 # TODO should we also call checkperm() here? Maybe not if we're going
298 # to overhaul that API. The granted scope from the URL check should
298 # to overhaul that API. The granted scope from the URL check should
299 # be good enough.
299 # be good enough.
300
300
301 else:
301 else:
302 # Don't allow multiple commands outside of ``multirequest`` URL.
302 # Don't allow multiple commands outside of ``multirequest`` URL.
303 if issubsequent:
303 if issubsequent:
304 # TODO proper error mechanism
304 # TODO proper error mechanism
305 res.status = b'200 OK'
305 res.status = b'200 OK'
306 res.headers[b'Content-Type'] = b'text/plain'
306 res.headers[b'Content-Type'] = b'text/plain'
307 res.setbodybytes(_('multiple commands cannot be issued to this '
307 res.setbodybytes(_('multiple commands cannot be issued to this '
308 'URL'))
308 'URL'))
309 return True
309 return True
310
310
311 if reqcommand != command['command']:
311 if reqcommand != command['command']:
312 # TODO define proper error mechanism
312 # TODO define proper error mechanism
313 res.status = b'200 OK'
313 res.status = b'200 OK'
314 res.headers[b'Content-Type'] = b'text/plain'
314 res.headers[b'Content-Type'] = b'text/plain'
315 res.setbodybytes(_('command in frame must match command in URL'))
315 res.setbodybytes(_('command in frame must match command in URL'))
316 return True
316 return True
317
317
318 res.status = b'200 OK'
318 res.status = b'200 OK'
319 res.headers[b'Content-Type'] = FRAMINGTYPE
319 res.headers[b'Content-Type'] = FRAMINGTYPE
320
320
321 try:
321 try:
322 objs = dispatch(repo, proto, command['command'], command['redirect'])
322 objs = dispatch(repo, proto, command['command'], command['redirect'])
323
323
324 action, meta = reactor.oncommandresponsereadyobjects(
324 action, meta = reactor.oncommandresponsereadyobjects(
325 outstream, command['requestid'], objs)
325 outstream, command['requestid'], objs)
326
326
327 except error.WireprotoCommandError as e:
327 except error.WireprotoCommandError as e:
328 action, meta = reactor.oncommanderror(
328 action, meta = reactor.oncommanderror(
329 outstream, command['requestid'], e.message, e.messageargs)
329 outstream, command['requestid'], e.message, e.messageargs)
330
330
331 except Exception as e:
331 except Exception as e:
332 action, meta = reactor.onservererror(
332 action, meta = reactor.onservererror(
333 outstream, command['requestid'],
333 outstream, command['requestid'],
334 _('exception when invoking command: %s') %
334 _('exception when invoking command: %s') %
335 stringutil.forcebytestr(e))
335 stringutil.forcebytestr(e))
336
336
337 if action == 'sendframes':
337 if action == 'sendframes':
338 res.setbodygen(meta['framegen'])
338 res.setbodygen(meta['framegen'])
339 return True
339 return True
340 elif action == 'noop':
340 elif action == 'noop':
341 return False
341 return False
342 else:
342 else:
343 raise error.ProgrammingError('unhandled event from reactor: %s' %
343 raise error.ProgrammingError('unhandled event from reactor: %s' %
344 action)
344 action)
345
345
346 def getdispatchrepo(repo, proto, command):
346 def getdispatchrepo(repo, proto, command):
347 return repo.filtered('served')
347 return repo.filtered('served')
348
348
349 def dispatch(repo, proto, command, redirect):
349 def dispatch(repo, proto, command, redirect):
350 """Run a wire protocol command.
350 """Run a wire protocol command.
351
351
352 Returns an iterable of objects that will be sent to the client.
352 Returns an iterable of objects that will be sent to the client.
353 """
353 """
354 repo = getdispatchrepo(repo, proto, command)
354 repo = getdispatchrepo(repo, proto, command)
355
355
356 entry = COMMANDS[command]
356 entry = COMMANDS[command]
357 func = entry.func
357 func = entry.func
358 spec = entry.args
358 spec = entry.args
359
359
360 args = proto.getargs(spec)
360 args = proto.getargs(spec)
361
361
362 # There is some duplicate boilerplate code here for calling the command and
362 # There is some duplicate boilerplate code here for calling the command and
363 # emitting objects. It is either that or a lot of indented code that looks
363 # emitting objects. It is either that or a lot of indented code that looks
364 # like a pyramid (since there are a lot of code paths that result in not
364 # like a pyramid (since there are a lot of code paths that result in not
365 # using the cacher).
365 # using the cacher).
366 callcommand = lambda: func(repo, proto, **pycompat.strkwargs(args))
366 callcommand = lambda: func(repo, proto, **pycompat.strkwargs(args))
367
367
368 # Request is not cacheable. Don't bother instantiating a cacher.
368 # Request is not cacheable. Don't bother instantiating a cacher.
369 if not entry.cachekeyfn:
369 if not entry.cachekeyfn:
370 for o in callcommand():
370 for o in callcommand():
371 yield o
371 yield o
372 return
372 return
373
373
374 if redirect:
374 if redirect:
375 redirecttargets = redirect[b'targets']
375 redirecttargets = redirect[b'targets']
376 redirecthashes = redirect[b'hashes']
376 redirecthashes = redirect[b'hashes']
377 else:
377 else:
378 redirecttargets = []
378 redirecttargets = []
379 redirecthashes = []
379 redirecthashes = []
380
380
381 cacher = makeresponsecacher(repo, proto, command, args,
381 cacher = makeresponsecacher(repo, proto, command, args,
382 cborutil.streamencode,
382 cborutil.streamencode,
383 redirecttargets=redirecttargets,
383 redirecttargets=redirecttargets,
384 redirecthashes=redirecthashes)
384 redirecthashes=redirecthashes)
385
385
386 # But we have no cacher. Do default handling.
386 # But we have no cacher. Do default handling.
387 if not cacher:
387 if not cacher:
388 for o in callcommand():
388 for o in callcommand():
389 yield o
389 yield o
390 return
390 return
391
391
392 with cacher:
392 with cacher:
393 cachekey = entry.cachekeyfn(repo, proto, cacher, **args)
393 cachekey = entry.cachekeyfn(repo, proto, cacher, **args)
394
394
395 # No cache key or the cacher doesn't like it. Do default handling.
395 # No cache key or the cacher doesn't like it. Do default handling.
396 if cachekey is None or not cacher.setcachekey(cachekey):
396 if cachekey is None or not cacher.setcachekey(cachekey):
397 for o in callcommand():
397 for o in callcommand():
398 yield o
398 yield o
399 return
399 return
400
400
401 # Serve it from the cache, if possible.
401 # Serve it from the cache, if possible.
402 cached = cacher.lookup()
402 cached = cacher.lookup()
403
403
404 if cached:
404 if cached:
405 for o in cached['objs']:
405 for o in cached['objs']:
406 yield o
406 yield o
407 return
407 return
408
408
409 # Else call the command and feed its output into the cacher, allowing
409 # Else call the command and feed its output into the cacher, allowing
410 # the cacher to buffer/mutate objects as it desires.
410 # the cacher to buffer/mutate objects as it desires.
411 for o in callcommand():
411 for o in callcommand():
412 for o in cacher.onobject(o):
412 for o in cacher.onobject(o):
413 yield o
413 yield o
414
414
415 for o in cacher.onfinished():
415 for o in cacher.onfinished():
416 yield o
416 yield o
417
417
418 @interfaceutil.implementer(wireprototypes.baseprotocolhandler)
418 @interfaceutil.implementer(wireprototypes.baseprotocolhandler)
419 class httpv2protocolhandler(object):
419 class httpv2protocolhandler(object):
420 def __init__(self, req, ui, args=None):
420 def __init__(self, req, ui, args=None):
421 self._req = req
421 self._req = req
422 self._ui = ui
422 self._ui = ui
423 self._args = args
423 self._args = args
424
424
425 @property
425 @property
426 def name(self):
426 def name(self):
427 return HTTP_WIREPROTO_V2
427 return HTTP_WIREPROTO_V2
428
428
429 def getargs(self, args):
429 def getargs(self, args):
430 # First look for args that were passed but aren't registered on this
430 # First look for args that were passed but aren't registered on this
431 # command.
431 # command.
432 extra = set(self._args) - set(args)
432 extra = set(self._args) - set(args)
433 if extra:
433 if extra:
434 raise error.WireprotoCommandError(
434 raise error.WireprotoCommandError(
435 'unsupported argument to command: %s' %
435 'unsupported argument to command: %s' %
436 ', '.join(sorted(extra)))
436 ', '.join(sorted(extra)))
437
437
438 # And look for required arguments that are missing.
438 # And look for required arguments that are missing.
439 missing = {a for a in args if args[a]['required']} - set(self._args)
439 missing = {a for a in args if args[a]['required']} - set(self._args)
440
440
441 if missing:
441 if missing:
442 raise error.WireprotoCommandError(
442 raise error.WireprotoCommandError(
443 'missing required arguments: %s' % ', '.join(sorted(missing)))
443 'missing required arguments: %s' % ', '.join(sorted(missing)))
444
444
445 # Now derive the arguments to pass to the command, taking into
445 # Now derive the arguments to pass to the command, taking into
446 # account the arguments specified by the client.
446 # account the arguments specified by the client.
447 data = {}
447 data = {}
448 for k, meta in sorted(args.items()):
448 for k, meta in sorted(args.items()):
449 # This argument wasn't passed by the client.
449 # This argument wasn't passed by the client.
450 if k not in self._args:
450 if k not in self._args:
451 data[k] = meta['default']()
451 data[k] = meta['default']()
452 continue
452 continue
453
453
454 v = self._args[k]
454 v = self._args[k]
455
455
456 # Sets may be expressed as lists. Silently normalize.
456 # Sets may be expressed as lists. Silently normalize.
457 if meta['type'] == 'set' and isinstance(v, list):
457 if meta['type'] == 'set' and isinstance(v, list):
458 v = set(v)
458 v = set(v)
459
459
460 # TODO consider more/stronger type validation.
460 # TODO consider more/stronger type validation.
461
461
462 data[k] = v
462 data[k] = v
463
463
464 return data
464 return data
465
465
466 def getprotocaps(self):
466 def getprotocaps(self):
467 # Protocol capabilities are currently not implemented for HTTP V2.
467 # Protocol capabilities are currently not implemented for HTTP V2.
468 return set()
468 return set()
469
469
470 def getpayload(self):
470 def getpayload(self):
471 raise NotImplementedError
471 raise NotImplementedError
472
472
473 @contextlib.contextmanager
473 @contextlib.contextmanager
474 def mayberedirectstdio(self):
474 def mayberedirectstdio(self):
475 raise NotImplementedError
475 raise NotImplementedError
476
476
477 def client(self):
477 def client(self):
478 raise NotImplementedError
478 raise NotImplementedError
479
479
480 def addcapabilities(self, repo, caps):
480 def addcapabilities(self, repo, caps):
481 return caps
481 return caps
482
482
483 def checkperm(self, perm):
483 def checkperm(self, perm):
484 raise NotImplementedError
484 raise NotImplementedError
485
485
486 def httpv2apidescriptor(req, repo):
486 def httpv2apidescriptor(req, repo):
487 proto = httpv2protocolhandler(req, repo.ui)
487 proto = httpv2protocolhandler(req, repo.ui)
488
488
489 return _capabilitiesv2(repo, proto)
489 return _capabilitiesv2(repo, proto)
490
490
491 def _capabilitiesv2(repo, proto):
491 def _capabilitiesv2(repo, proto):
492 """Obtain the set of capabilities for version 2 transports.
492 """Obtain the set of capabilities for version 2 transports.
493
493
494 These capabilities are distinct from the capabilities for version 1
494 These capabilities are distinct from the capabilities for version 1
495 transports.
495 transports.
496 """
496 """
497 caps = {
497 caps = {
498 'commands': {},
498 'commands': {},
499 'framingmediatypes': [FRAMINGTYPE],
499 'framingmediatypes': [FRAMINGTYPE],
500 'pathfilterprefixes': set(narrowspec.VALID_PREFIXES),
500 'pathfilterprefixes': set(narrowspec.VALID_PREFIXES),
501 }
501 }
502
502
503 for command, entry in COMMANDS.items():
503 for command, entry in COMMANDS.items():
504 args = {}
504 args = {}
505
505
506 for arg, meta in entry.args.items():
506 for arg, meta in entry.args.items():
507 args[arg] = {
507 args[arg] = {
508 # TODO should this be a normalized type using CBOR's
508 # TODO should this be a normalized type using CBOR's
509 # terminology?
509 # terminology?
510 b'type': meta['type'],
510 b'type': meta['type'],
511 b'required': meta['required'],
511 b'required': meta['required'],
512 }
512 }
513
513
514 if not meta['required']:
514 if not meta['required']:
515 args[arg][b'default'] = meta['default']()
515 args[arg][b'default'] = meta['default']()
516
516
517 if meta['validvalues']:
517 if meta['validvalues']:
518 args[arg][b'validvalues'] = meta['validvalues']
518 args[arg][b'validvalues'] = meta['validvalues']
519
519
520 # TODO this type of check should be defined in a per-command callback.
520 # TODO this type of check should be defined in a per-command callback.
521 if (command == b'rawstorefiledata'
521 if (command == b'rawstorefiledata'
522 and not streamclone.allowservergeneration(repo)):
522 and not streamclone.allowservergeneration(repo)):
523 continue
523 continue
524
524
525 caps['commands'][command] = {
525 caps['commands'][command] = {
526 'args': args,
526 'args': args,
527 'permissions': [entry.permission],
527 'permissions': [entry.permission],
528 }
528 }
529
529
530 if entry.extracapabilitiesfn:
530 if entry.extracapabilitiesfn:
531 extracaps = entry.extracapabilitiesfn(repo, proto)
531 extracaps = entry.extracapabilitiesfn(repo, proto)
532 caps['commands'][command].update(extracaps)
532 caps['commands'][command].update(extracaps)
533
533
534 caps['rawrepoformats'] = sorted(repo.requirements &
534 caps['rawrepoformats'] = sorted(repo.requirements &
535 repo.supportedformats)
535 repo.supportedformats)
536
536
537 targets = getadvertisedredirecttargets(repo, proto)
537 targets = getadvertisedredirecttargets(repo, proto)
538 if targets:
538 if targets:
539 caps[b'redirect'] = {
539 caps[b'redirect'] = {
540 b'targets': [],
540 b'targets': [],
541 b'hashes': [b'sha256', b'sha1'],
541 b'hashes': [b'sha256', b'sha1'],
542 }
542 }
543
543
544 for target in targets:
544 for target in targets:
545 entry = {
545 entry = {
546 b'name': target['name'],
546 b'name': target['name'],
547 b'protocol': target['protocol'],
547 b'protocol': target['protocol'],
548 b'uris': target['uris'],
548 b'uris': target['uris'],
549 }
549 }
550
550
551 for key in ('snirequired', 'tlsversions'):
551 for key in ('snirequired', 'tlsversions'):
552 if key in target:
552 if key in target:
553 entry[key] = target[key]
553 entry[key] = target[key]
554
554
555 caps[b'redirect'][b'targets'].append(entry)
555 caps[b'redirect'][b'targets'].append(entry)
556
556
557 return proto.addcapabilities(repo, caps)
557 return proto.addcapabilities(repo, caps)
558
558
559 def getadvertisedredirecttargets(repo, proto):
559 def getadvertisedredirecttargets(repo, proto):
560 """Obtain a list of content redirect targets.
560 """Obtain a list of content redirect targets.
561
561
562 Returns a list containing potential redirect targets that will be
562 Returns a list containing potential redirect targets that will be
563 advertised in capabilities data. Each dict MUST have the following
563 advertised in capabilities data. Each dict MUST have the following
564 keys:
564 keys:
565
565
566 name
566 name
567 The name of this redirect target. This is the identifier clients use
567 The name of this redirect target. This is the identifier clients use
568 to refer to a target. It is transferred as part of every command
568 to refer to a target. It is transferred as part of every command
569 request.
569 request.
570
570
571 protocol
571 protocol
572 Network protocol used by this target. Typically this is the string
572 Network protocol used by this target. Typically this is the string
573 in front of the ``://`` in a URL. e.g. ``https``.
573 in front of the ``://`` in a URL. e.g. ``https``.
574
574
575 uris
575 uris
576 List of representative URIs for this target. Clients can use the
576 List of representative URIs for this target. Clients can use the
577 URIs to test parsing for compatibility or for ordering preference
577 URIs to test parsing for compatibility or for ordering preference
578 for which target to use.
578 for which target to use.
579
579
580 The following optional keys are recognized:
580 The following optional keys are recognized:
581
581
582 snirequired
582 snirequired
583 Bool indicating if Server Name Indication (SNI) is required to
583 Bool indicating if Server Name Indication (SNI) is required to
584 connect to this target.
584 connect to this target.
585
585
586 tlsversions
586 tlsversions
587 List of bytes indicating which TLS versions are supported by this
587 List of bytes indicating which TLS versions are supported by this
588 target.
588 target.
589
589
590 By default, clients reflect the target order advertised by servers
590 By default, clients reflect the target order advertised by servers
591 and servers will use the first client-advertised target when picking
591 and servers will use the first client-advertised target when picking
592 a redirect target. So targets should be advertised in the order the
592 a redirect target. So targets should be advertised in the order the
593 server prefers they be used.
593 server prefers they be used.
594 """
594 """
595 return []
595 return []
596
596
597 def wireprotocommand(name, args=None, permission='push', cachekeyfn=None,
597 def wireprotocommand(name, args=None, permission='push', cachekeyfn=None,
598 extracapabilitiesfn=None):
598 extracapabilitiesfn=None):
599 """Decorator to declare a wire protocol command.
599 """Decorator to declare a wire protocol command.
600
600
601 ``name`` is the name of the wire protocol command being provided.
601 ``name`` is the name of the wire protocol command being provided.
602
602
603 ``args`` is a dict defining arguments accepted by the command. Keys are
603 ``args`` is a dict defining arguments accepted by the command. Keys are
604 the argument name. Values are dicts with the following keys:
604 the argument name. Values are dicts with the following keys:
605
605
606 ``type``
606 ``type``
607 The argument data type. Must be one of the following string
607 The argument data type. Must be one of the following string
608 literals: ``bytes``, ``int``, ``list``, ``dict``, ``set``,
608 literals: ``bytes``, ``int``, ``list``, ``dict``, ``set``,
609 or ``bool``.
609 or ``bool``.
610
610
611 ``default``
611 ``default``
612 A callable returning the default value for this argument. If not
612 A callable returning the default value for this argument. If not
613 specified, ``None`` will be the default value.
613 specified, ``None`` will be the default value.
614
614
615 ``example``
615 ``example``
616 An example value for this argument.
616 An example value for this argument.
617
617
618 ``validvalues``
618 ``validvalues``
619 Set of recognized values for this argument.
619 Set of recognized values for this argument.
620
620
621 ``permission`` defines the permission type needed to run this command.
621 ``permission`` defines the permission type needed to run this command.
622 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
622 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
623 respectively. Default is to assume command requires ``push`` permissions
623 respectively. Default is to assume command requires ``push`` permissions
624 because otherwise commands not declaring their permissions could modify
624 because otherwise commands not declaring their permissions could modify
625 a repository that is supposed to be read-only.
625 a repository that is supposed to be read-only.
626
626
627 ``cachekeyfn`` defines an optional callable that can derive the
627 ``cachekeyfn`` defines an optional callable that can derive the
628 cache key for this request.
628 cache key for this request.
629
629
630 ``extracapabilitiesfn`` defines an optional callable that defines extra
630 ``extracapabilitiesfn`` defines an optional callable that defines extra
631 command capabilities/parameters that are advertised next to the command
631 command capabilities/parameters that are advertised next to the command
632 in the capabilities data structure describing the server. The callable
632 in the capabilities data structure describing the server. The callable
633 receives as arguments the repository and protocol objects. It returns
633 receives as arguments the repository and protocol objects. It returns
634 a dict of extra fields to add to the command descriptor.
634 a dict of extra fields to add to the command descriptor.
635
635
636 Wire protocol commands are generators of objects to be serialized and
636 Wire protocol commands are generators of objects to be serialized and
637 sent to the client.
637 sent to the client.
638
638
639 If a command raises an uncaught exception, this will be translated into
639 If a command raises an uncaught exception, this will be translated into
640 a command error.
640 a command error.
641
641
642 All commands can opt in to being cacheable by defining a function
642 All commands can opt in to being cacheable by defining a function
643 (``cachekeyfn``) that is called to derive a cache key. This function
643 (``cachekeyfn``) that is called to derive a cache key. This function
644 receives the same arguments as the command itself plus a ``cacher``
644 receives the same arguments as the command itself plus a ``cacher``
645 argument containing the active cacher for the request and returns a bytes
645 argument containing the active cacher for the request and returns a bytes
646 containing the key in a cache the response to this command may be cached
646 containing the key in a cache the response to this command may be cached
647 under.
647 under.
648 """
648 """
649 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
649 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
650 if v['version'] == 2}
650 if v['version'] == 2}
651
651
652 if permission not in ('push', 'pull'):
652 if permission not in ('push', 'pull'):
653 raise error.ProgrammingError('invalid wire protocol permission; '
653 raise error.ProgrammingError('invalid wire protocol permission; '
654 'got %s; expected "push" or "pull"' %
654 'got %s; expected "push" or "pull"' %
655 permission)
655 permission)
656
656
657 if args is None:
657 if args is None:
658 args = {}
658 args = {}
659
659
660 if not isinstance(args, dict):
660 if not isinstance(args, dict):
661 raise error.ProgrammingError('arguments for version 2 commands '
661 raise error.ProgrammingError('arguments for version 2 commands '
662 'must be declared as dicts')
662 'must be declared as dicts')
663
663
664 for arg, meta in args.items():
664 for arg, meta in args.items():
665 if arg == '*':
665 if arg == '*':
666 raise error.ProgrammingError('* argument name not allowed on '
666 raise error.ProgrammingError('* argument name not allowed on '
667 'version 2 commands')
667 'version 2 commands')
668
668
669 if not isinstance(meta, dict):
669 if not isinstance(meta, dict):
670 raise error.ProgrammingError('arguments for version 2 commands '
670 raise error.ProgrammingError('arguments for version 2 commands '
671 'must declare metadata as a dict')
671 'must declare metadata as a dict')
672
672
673 if 'type' not in meta:
673 if 'type' not in meta:
674 raise error.ProgrammingError('%s argument for command %s does not '
674 raise error.ProgrammingError('%s argument for command %s does not '
675 'declare type field' % (arg, name))
675 'declare type field' % (arg, name))
676
676
677 if meta['type'] not in ('bytes', 'int', 'list', 'dict', 'set', 'bool'):
677 if meta['type'] not in ('bytes', 'int', 'list', 'dict', 'set', 'bool'):
678 raise error.ProgrammingError('%s argument for command %s has '
678 raise error.ProgrammingError('%s argument for command %s has '
679 'illegal type: %s' % (arg, name,
679 'illegal type: %s' % (arg, name,
680 meta['type']))
680 meta['type']))
681
681
682 if 'example' not in meta:
682 if 'example' not in meta:
683 raise error.ProgrammingError('%s argument for command %s does not '
683 raise error.ProgrammingError('%s argument for command %s does not '
684 'declare example field' % (arg, name))
684 'declare example field' % (arg, name))
685
685
686 meta['required'] = 'default' not in meta
686 meta['required'] = 'default' not in meta
687
687
688 meta.setdefault('default', lambda: None)
688 meta.setdefault('default', lambda: None)
689 meta.setdefault('validvalues', None)
689 meta.setdefault('validvalues', None)
690
690
691 def register(func):
691 def register(func):
692 if name in COMMANDS:
692 if name in COMMANDS:
693 raise error.ProgrammingError('%s command already registered '
693 raise error.ProgrammingError('%s command already registered '
694 'for version 2' % name)
694 'for version 2' % name)
695
695
696 COMMANDS[name] = wireprototypes.commandentry(
696 COMMANDS[name] = wireprototypes.commandentry(
697 func, args=args, transports=transports, permission=permission,
697 func, args=args, transports=transports, permission=permission,
698 cachekeyfn=cachekeyfn, extracapabilitiesfn=extracapabilitiesfn)
698 cachekeyfn=cachekeyfn, extracapabilitiesfn=extracapabilitiesfn)
699
699
700 return func
700 return func
701
701
702 return register
702 return register
703
703
704 def makecommandcachekeyfn(command, localversion=None, allargs=False):
704 def makecommandcachekeyfn(command, localversion=None, allargs=False):
705 """Construct a cache key derivation function with common features.
705 """Construct a cache key derivation function with common features.
706
706
707 By default, the cache key is a hash of:
707 By default, the cache key is a hash of:
708
708
709 * The command name.
709 * The command name.
710 * A global cache version number.
710 * A global cache version number.
711 * A local cache version number (passed via ``localversion``).
711 * A local cache version number (passed via ``localversion``).
712 * All the arguments passed to the command.
712 * All the arguments passed to the command.
713 * The media type used.
713 * The media type used.
714 * Wire protocol version string.
714 * Wire protocol version string.
715 * The repository path.
715 * The repository path.
716 """
716 """
717 if not allargs:
717 if not allargs:
718 raise error.ProgrammingError('only allargs=True is currently supported')
718 raise error.ProgrammingError('only allargs=True is currently supported')
719
719
720 if localversion is None:
720 if localversion is None:
721 raise error.ProgrammingError('must set localversion argument value')
721 raise error.ProgrammingError('must set localversion argument value')
722
722
723 def cachekeyfn(repo, proto, cacher, **args):
723 def cachekeyfn(repo, proto, cacher, **args):
724 spec = COMMANDS[command]
724 spec = COMMANDS[command]
725
725
726 # Commands that mutate the repo can not be cached.
726 # Commands that mutate the repo can not be cached.
727 if spec.permission == 'push':
727 if spec.permission == 'push':
728 return None
728 return None
729
729
730 # TODO config option to disable caching.
730 # TODO config option to disable caching.
731
731
732 # Our key derivation strategy is to construct a data structure
732 # Our key derivation strategy is to construct a data structure
733 # holding everything that could influence cacheability and to hash
733 # holding everything that could influence cacheability and to hash
734 # the CBOR representation of that. Using CBOR seems like it might
734 # the CBOR representation of that. Using CBOR seems like it might
735 # be overkill. However, simpler hashing mechanisms are prone to
735 # be overkill. However, simpler hashing mechanisms are prone to
736 # duplicate input issues. e.g. if you just concatenate two values,
736 # duplicate input issues. e.g. if you just concatenate two values,
737 # "foo"+"bar" is identical to "fo"+"obar". Using CBOR provides
737 # "foo"+"bar" is identical to "fo"+"obar". Using CBOR provides
738 # "padding" between values and prevents these problems.
738 # "padding" between values and prevents these problems.
739
739
740 # Seed the hash with various data.
740 # Seed the hash with various data.
741 state = {
741 state = {
742 # To invalidate all cache keys.
742 # To invalidate all cache keys.
743 b'globalversion': GLOBAL_CACHE_VERSION,
743 b'globalversion': GLOBAL_CACHE_VERSION,
744 # More granular cache key invalidation.
744 # More granular cache key invalidation.
745 b'localversion': localversion,
745 b'localversion': localversion,
746 # Cache keys are segmented by command.
746 # Cache keys are segmented by command.
747 b'command': pycompat.sysbytes(command),
747 b'command': pycompat.sysbytes(command),
748 # Throw in the media type and API version strings so changes
748 # Throw in the media type and API version strings so changes
749 # to exchange semantics invalid cache.
749 # to exchange semantics invalid cache.
750 b'mediatype': FRAMINGTYPE,
750 b'mediatype': FRAMINGTYPE,
751 b'version': HTTP_WIREPROTO_V2,
751 b'version': HTTP_WIREPROTO_V2,
752 # So same requests for different repos don't share cache keys.
752 # So same requests for different repos don't share cache keys.
753 b'repo': repo.root,
753 b'repo': repo.root,
754 }
754 }
755
755
756 # The arguments passed to us will have already been normalized.
756 # The arguments passed to us will have already been normalized.
757 # Default values will be set, etc. This is important because it
757 # Default values will be set, etc. This is important because it
758 # means that it doesn't matter if clients send an explicit argument
758 # means that it doesn't matter if clients send an explicit argument
759 # or rely on the default value: it will all normalize to the same
759 # or rely on the default value: it will all normalize to the same
760 # set of arguments on the server and therefore the same cache key.
760 # set of arguments on the server and therefore the same cache key.
761 #
761 #
762 # Arguments by their very nature must support being encoded to CBOR.
762 # Arguments by their very nature must support being encoded to CBOR.
763 # And the CBOR encoder is deterministic. So we hash the arguments
763 # And the CBOR encoder is deterministic. So we hash the arguments
764 # by feeding the CBOR of their representation into the hasher.
764 # by feeding the CBOR of their representation into the hasher.
765 if allargs:
765 if allargs:
766 state[b'args'] = pycompat.byteskwargs(args)
766 state[b'args'] = pycompat.byteskwargs(args)
767
767
768 cacher.adjustcachekeystate(state)
768 cacher.adjustcachekeystate(state)
769
769
770 hasher = hashlib.sha1()
770 hasher = hashlib.sha1()
771 for chunk in cborutil.streamencode(state):
771 for chunk in cborutil.streamencode(state):
772 hasher.update(chunk)
772 hasher.update(chunk)
773
773
774 return pycompat.sysbytes(hasher.hexdigest())
774 return pycompat.sysbytes(hasher.hexdigest())
775
775
776 return cachekeyfn
776 return cachekeyfn
777
777
778 def makeresponsecacher(repo, proto, command, args, objencoderfn,
778 def makeresponsecacher(repo, proto, command, args, objencoderfn,
779 redirecttargets, redirecthashes):
779 redirecttargets, redirecthashes):
780 """Construct a cacher for a cacheable command.
780 """Construct a cacher for a cacheable command.
781
781
782 Returns an ``iwireprotocolcommandcacher`` instance.
782 Returns an ``iwireprotocolcommandcacher`` instance.
783
783
784 Extensions can monkeypatch this function to provide custom caching
784 Extensions can monkeypatch this function to provide custom caching
785 backends.
785 backends.
786 """
786 """
787 return None
787 return None
788
788
789 def resolvenodes(repo, revisions):
789 def resolvenodes(repo, revisions):
790 """Resolve nodes from a revisions specifier data structure."""
790 """Resolve nodes from a revisions specifier data structure."""
791 cl = repo.changelog
791 cl = repo.changelog
792 clhasnode = cl.hasnode
792 clhasnode = cl.hasnode
793
793
794 seen = set()
794 seen = set()
795 nodes = []
795 nodes = []
796
796
797 if not isinstance(revisions, list):
797 if not isinstance(revisions, list):
798 raise error.WireprotoCommandError('revisions must be defined as an '
798 raise error.WireprotoCommandError('revisions must be defined as an '
799 'array')
799 'array')
800
800
801 for spec in revisions:
801 for spec in revisions:
802 if b'type' not in spec:
802 if b'type' not in spec:
803 raise error.WireprotoCommandError(
803 raise error.WireprotoCommandError(
804 'type key not present in revision specifier')
804 'type key not present in revision specifier')
805
805
806 typ = spec[b'type']
806 typ = spec[b'type']
807
807
808 if typ == b'changesetexplicit':
808 if typ == b'changesetexplicit':
809 if b'nodes' not in spec:
809 if b'nodes' not in spec:
810 raise error.WireprotoCommandError(
810 raise error.WireprotoCommandError(
811 'nodes key not present in changesetexplicit revision '
811 'nodes key not present in changesetexplicit revision '
812 'specifier')
812 'specifier')
813
813
814 for node in spec[b'nodes']:
814 for node in spec[b'nodes']:
815 if node not in seen:
815 if node not in seen:
816 nodes.append(node)
816 nodes.append(node)
817 seen.add(node)
817 seen.add(node)
818
818
819 elif typ == b'changesetexplicitdepth':
819 elif typ == b'changesetexplicitdepth':
820 for key in (b'nodes', b'depth'):
820 for key in (b'nodes', b'depth'):
821 if key not in spec:
821 if key not in spec:
822 raise error.WireprotoCommandError(
822 raise error.WireprotoCommandError(
823 '%s key not present in changesetexplicitdepth revision '
823 '%s key not present in changesetexplicitdepth revision '
824 'specifier', (key,))
824 'specifier', (key,))
825
825
826 for rev in repo.revs(b'ancestors(%ln, %d)', spec[b'nodes'],
826 for rev in repo.revs(b'ancestors(%ln, %d)', spec[b'nodes'],
827 spec[b'depth'] - 1):
827 spec[b'depth'] - 1):
828 node = cl.node(rev)
828 node = cl.node(rev)
829
829
830 if node not in seen:
830 if node not in seen:
831 nodes.append(node)
831 nodes.append(node)
832 seen.add(node)
832 seen.add(node)
833
833
834 elif typ == b'changesetdagrange':
834 elif typ == b'changesetdagrange':
835 for key in (b'roots', b'heads'):
835 for key in (b'roots', b'heads'):
836 if key not in spec:
836 if key not in spec:
837 raise error.WireprotoCommandError(
837 raise error.WireprotoCommandError(
838 '%s key not present in changesetdagrange revision '
838 '%s key not present in changesetdagrange revision '
839 'specifier', (key,))
839 'specifier', (key,))
840
840
841 if not spec[b'heads']:
841 if not spec[b'heads']:
842 raise error.WireprotoCommandError(
842 raise error.WireprotoCommandError(
843 'heads key in changesetdagrange cannot be empty')
843 'heads key in changesetdagrange cannot be empty')
844
844
845 if spec[b'roots']:
845 if spec[b'roots']:
846 common = [n for n in spec[b'roots'] if clhasnode(n)]
846 common = [n for n in spec[b'roots'] if clhasnode(n)]
847 else:
847 else:
848 common = [nullid]
848 common = [nullid]
849
849
850 for n in discovery.outgoing(repo, common, spec[b'heads']).missing:
850 for n in discovery.outgoing(repo, common, spec[b'heads']).missing:
851 if n not in seen:
851 if n not in seen:
852 nodes.append(n)
852 nodes.append(n)
853 seen.add(n)
853 seen.add(n)
854
854
855 else:
855 else:
856 raise error.WireprotoCommandError(
856 raise error.WireprotoCommandError(
857 'unknown revision specifier type: %s', (typ,))
857 'unknown revision specifier type: %s', (typ,))
858
858
859 return nodes
859 return nodes
860
860
861 @wireprotocommand('branchmap', permission='pull')
861 @wireprotocommand('branchmap', permission='pull')
862 def branchmapv2(repo, proto):
862 def branchmapv2(repo, proto):
863 yield {encoding.fromlocal(k): v
863 yield {encoding.fromlocal(k): v
864 for k, v in repo.branchmap().iteritems()}
864 for k, v in repo.branchmap().iteritems()}
865
865
866 @wireprotocommand('capabilities', permission='pull')
866 @wireprotocommand('capabilities', permission='pull')
867 def capabilitiesv2(repo, proto):
867 def capabilitiesv2(repo, proto):
868 yield _capabilitiesv2(repo, proto)
868 yield _capabilitiesv2(repo, proto)
869
869
870 @wireprotocommand(
870 @wireprotocommand(
871 'changesetdata',
871 'changesetdata',
872 args={
872 args={
873 'revisions': {
873 'revisions': {
874 'type': 'list',
874 'type': 'list',
875 'example': [{
875 'example': [{
876 b'type': b'changesetexplicit',
876 b'type': b'changesetexplicit',
877 b'nodes': [b'abcdef...'],
877 b'nodes': [b'abcdef...'],
878 }],
878 }],
879 },
879 },
880 'fields': {
880 'fields': {
881 'type': 'set',
881 'type': 'set',
882 'default': set,
882 'default': set,
883 'example': {b'parents', b'revision'},
883 'example': {b'parents', b'revision'},
884 'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
884 'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
885 },
885 },
886 },
886 },
887 permission='pull')
887 permission='pull')
888 def changesetdata(repo, proto, revisions, fields):
888 def changesetdata(repo, proto, revisions, fields):
889 # TODO look for unknown fields and abort when they can't be serviced.
889 # TODO look for unknown fields and abort when they can't be serviced.
890 # This could probably be validated by dispatcher using validvalues.
890 # This could probably be validated by dispatcher using validvalues.
891
891
892 cl = repo.changelog
892 cl = repo.changelog
893 outgoing = resolvenodes(repo, revisions)
893 outgoing = resolvenodes(repo, revisions)
894 publishing = repo.publishing()
894 publishing = repo.publishing()
895
895
896 if outgoing:
896 if outgoing:
897 repo.hook('preoutgoing', throw=True, source='serve')
897 repo.hook('preoutgoing', throw=True, source='serve')
898
898
899 yield {
899 yield {
900 b'totalitems': len(outgoing),
900 b'totalitems': len(outgoing),
901 }
901 }
902
902
903 # The phases of nodes already transferred to the client may have changed
903 # The phases of nodes already transferred to the client may have changed
904 # since the client last requested data. We send phase-only records
904 # since the client last requested data. We send phase-only records
905 # for these revisions, if requested.
905 # for these revisions, if requested.
906 # TODO actually do this. We'll probably want to emit phase heads
906 # TODO actually do this. We'll probably want to emit phase heads
907 # in the ancestry set of the outgoing revisions. This will ensure
907 # in the ancestry set of the outgoing revisions. This will ensure
908 # that phase updates within that set are seen.
908 # that phase updates within that set are seen.
909 if b'phase' in fields:
909 if b'phase' in fields:
910 pass
910 pass
911
911
912 nodebookmarks = {}
912 nodebookmarks = {}
913 for mark, node in repo._bookmarks.items():
913 for mark, node in repo._bookmarks.items():
914 nodebookmarks.setdefault(node, set()).add(mark)
914 nodebookmarks.setdefault(node, set()).add(mark)
915
915
916 # It is already topologically sorted by revision number.
916 # It is already topologically sorted by revision number.
917 for node in outgoing:
917 for node in outgoing:
918 d = {
918 d = {
919 b'node': node,
919 b'node': node,
920 }
920 }
921
921
922 if b'parents' in fields:
922 if b'parents' in fields:
923 d[b'parents'] = cl.parents(node)
923 d[b'parents'] = cl.parents(node)
924
924
925 if b'phase' in fields:
925 if b'phase' in fields:
926 if publishing:
926 if publishing:
927 d[b'phase'] = b'public'
927 d[b'phase'] = b'public'
928 else:
928 else:
929 ctx = repo[node]
929 ctx = repo[node]
930 d[b'phase'] = ctx.phasestr()
930 d[b'phase'] = ctx.phasestr()
931
931
932 if b'bookmarks' in fields and node in nodebookmarks:
932 if b'bookmarks' in fields and node in nodebookmarks:
933 d[b'bookmarks'] = sorted(nodebookmarks[node])
933 d[b'bookmarks'] = sorted(nodebookmarks[node])
934 del nodebookmarks[node]
934 del nodebookmarks[node]
935
935
936 followingmeta = []
936 followingmeta = []
937 followingdata = []
937 followingdata = []
938
938
939 if b'revision' in fields:
939 if b'revision' in fields:
940 revisiondata = cl.revision(node, raw=True)
940 revisiondata = cl.revision(node, raw=True)
941 followingmeta.append((b'revision', len(revisiondata)))
941 followingmeta.append((b'revision', len(revisiondata)))
942 followingdata.append(revisiondata)
942 followingdata.append(revisiondata)
943
943
944 # TODO make it possible for extensions to wrap a function or register
944 # TODO make it possible for extensions to wrap a function or register
945 # a handler to service custom fields.
945 # a handler to service custom fields.
946
946
947 if followingmeta:
947 if followingmeta:
948 d[b'fieldsfollowing'] = followingmeta
948 d[b'fieldsfollowing'] = followingmeta
949
949
950 yield d
950 yield d
951
951
952 for extra in followingdata:
952 for extra in followingdata:
953 yield extra
953 yield extra
954
954
955 # If requested, send bookmarks from nodes that didn't have revision
955 # If requested, send bookmarks from nodes that didn't have revision
956 # data sent so receiver is aware of any bookmark updates.
956 # data sent so receiver is aware of any bookmark updates.
957 if b'bookmarks' in fields:
957 if b'bookmarks' in fields:
958 for node, marks in sorted(nodebookmarks.iteritems()):
958 for node, marks in sorted(nodebookmarks.iteritems()):
959 yield {
959 yield {
960 b'node': node,
960 b'node': node,
961 b'bookmarks': sorted(marks),
961 b'bookmarks': sorted(marks),
962 }
962 }
963
963
964 class FileAccessError(Exception):
964 class FileAccessError(Exception):
965 """Represents an error accessing a specific file."""
965 """Represents an error accessing a specific file."""
966
966
967 def __init__(self, path, msg, args):
967 def __init__(self, path, msg, args):
968 self.path = path
968 self.path = path
969 self.msg = msg
969 self.msg = msg
970 self.args = args
970 self.args = args
971
971
972 def getfilestore(repo, proto, path):
972 def getfilestore(repo, proto, path):
973 """Obtain a file storage object for use with wire protocol.
973 """Obtain a file storage object for use with wire protocol.
974
974
975 Exists as a standalone function so extensions can monkeypatch to add
975 Exists as a standalone function so extensions can monkeypatch to add
976 access control.
976 access control.
977 """
977 """
978 # This seems to work even if the file doesn't exist. So catch
978 # This seems to work even if the file doesn't exist. So catch
979 # "empty" files and return an error.
979 # "empty" files and return an error.
980 fl = repo.file(path)
980 fl = repo.file(path)
981
981
982 if not len(fl):
982 if not len(fl):
983 raise FileAccessError(path, 'unknown file: %s', (path,))
983 raise FileAccessError(path, 'unknown file: %s', (path,))
984
984
985 return fl
985 return fl
986
986
987 def emitfilerevisions(revisions, fields):
987 def emitfilerevisions(repo, path, revisions, fields):
988 clnode = repo.changelog.node
989
988 for revision in revisions:
990 for revision in revisions:
989 d = {
991 d = {
990 b'node': revision.node,
992 b'node': revision.node,
991 }
993 }
992
994
993 if b'parents' in fields:
995 if b'parents' in fields:
994 d[b'parents'] = [revision.p1node, revision.p2node]
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 followingmeta = []
1007 followingmeta = []
997 followingdata = []
1008 followingdata = []
998
1009
999 if b'revision' in fields:
1010 if b'revision' in fields:
1000 if revision.revision is not None:
1011 if revision.revision is not None:
1001 followingmeta.append((b'revision', len(revision.revision)))
1012 followingmeta.append((b'revision', len(revision.revision)))
1002 followingdata.append(revision.revision)
1013 followingdata.append(revision.revision)
1003 else:
1014 else:
1004 d[b'deltabasenode'] = revision.basenode
1015 d[b'deltabasenode'] = revision.basenode
1005 followingmeta.append((b'delta', len(revision.delta)))
1016 followingmeta.append((b'delta', len(revision.delta)))
1006 followingdata.append(revision.delta)
1017 followingdata.append(revision.delta)
1007
1018
1008 if followingmeta:
1019 if followingmeta:
1009 d[b'fieldsfollowing'] = followingmeta
1020 d[b'fieldsfollowing'] = followingmeta
1010
1021
1011 yield d
1022 yield d
1012
1023
1013 for extra in followingdata:
1024 for extra in followingdata:
1014 yield extra
1025 yield extra
1015
1026
1016 def makefilematcher(repo, pathfilter):
1027 def makefilematcher(repo, pathfilter):
1017 """Construct a matcher from a path filter dict."""
1028 """Construct a matcher from a path filter dict."""
1018
1029
1019 # Validate values.
1030 # Validate values.
1020 if pathfilter:
1031 if pathfilter:
1021 for key in (b'include', b'exclude'):
1032 for key in (b'include', b'exclude'):
1022 for pattern in pathfilter.get(key, []):
1033 for pattern in pathfilter.get(key, []):
1023 if not pattern.startswith((b'path:', b'rootfilesin:')):
1034 if not pattern.startswith((b'path:', b'rootfilesin:')):
1024 raise error.WireprotoCommandError(
1035 raise error.WireprotoCommandError(
1025 '%s pattern must begin with `path:` or `rootfilesin:`; '
1036 '%s pattern must begin with `path:` or `rootfilesin:`; '
1026 'got %s', (key, pattern))
1037 'got %s', (key, pattern))
1027
1038
1028 if pathfilter:
1039 if pathfilter:
1029 matcher = matchmod.match(repo.root, b'',
1040 matcher = matchmod.match(repo.root, b'',
1030 include=pathfilter.get(b'include', []),
1041 include=pathfilter.get(b'include', []),
1031 exclude=pathfilter.get(b'exclude', []))
1042 exclude=pathfilter.get(b'exclude', []))
1032 else:
1043 else:
1033 matcher = matchmod.match(repo.root, b'')
1044 matcher = matchmod.match(repo.root, b'')
1034
1045
1035 # Requested patterns could include files not in the local store. So
1046 # Requested patterns could include files not in the local store. So
1036 # filter those out.
1047 # filter those out.
1037 return matchmod.intersectmatchers(repo.narrowmatch(), matcher)
1048 return matchmod.intersectmatchers(repo.narrowmatch(), matcher)
1038
1049
1039 @wireprotocommand(
1050 @wireprotocommand(
1040 'filedata',
1051 'filedata',
1041 args={
1052 args={
1042 'haveparents': {
1053 'haveparents': {
1043 'type': 'bool',
1054 'type': 'bool',
1044 'default': lambda: False,
1055 'default': lambda: False,
1045 'example': True,
1056 'example': True,
1046 },
1057 },
1047 'nodes': {
1058 'nodes': {
1048 'type': 'list',
1059 'type': 'list',
1049 'example': [b'0123456...'],
1060 'example': [b'0123456...'],
1050 },
1061 },
1051 'fields': {
1062 'fields': {
1052 'type': 'set',
1063 'type': 'set',
1053 'default': set,
1064 'default': set,
1054 'example': {b'parents', b'revision'},
1065 'example': {b'parents', b'revision'},
1055 'validvalues': {b'parents', b'revision'},
1066 'validvalues': {b'parents', b'revision', b'linknode'},
1056 },
1067 },
1057 'path': {
1068 'path': {
1058 'type': 'bytes',
1069 'type': 'bytes',
1059 'example': b'foo.txt',
1070 'example': b'foo.txt',
1060 }
1071 }
1061 },
1072 },
1062 permission='pull',
1073 permission='pull',
1063 # TODO censoring a file revision won't invalidate the cache.
1074 # TODO censoring a file revision won't invalidate the cache.
1064 # Figure out a way to take censoring into account when deriving
1075 # Figure out a way to take censoring into account when deriving
1065 # the cache key.
1076 # the cache key.
1066 cachekeyfn=makecommandcachekeyfn('filedata', 1, allargs=True))
1077 cachekeyfn=makecommandcachekeyfn('filedata', 1, allargs=True))
1067 def filedata(repo, proto, haveparents, nodes, fields, path):
1078 def filedata(repo, proto, haveparents, nodes, fields, path):
1068 # TODO this API allows access to file revisions that are attached to
1079 # TODO this API allows access to file revisions that are attached to
1069 # secret changesets. filesdata does not have this problem. Maybe this
1080 # secret changesets. filesdata does not have this problem. Maybe this
1070 # API should be deleted?
1081 # API should be deleted?
1071
1082
1072 try:
1083 try:
1073 # Extensions may wish to access the protocol handler.
1084 # Extensions may wish to access the protocol handler.
1074 store = getfilestore(repo, proto, path)
1085 store = getfilestore(repo, proto, path)
1075 except FileAccessError as e:
1086 except FileAccessError as e:
1076 raise error.WireprotoCommandError(e.msg, e.args)
1087 raise error.WireprotoCommandError(e.msg, e.args)
1077
1088
1078 # Validate requested nodes.
1089 # Validate requested nodes.
1079 for node in nodes:
1090 for node in nodes:
1080 try:
1091 try:
1081 store.rev(node)
1092 store.rev(node)
1082 except error.LookupError:
1093 except error.LookupError:
1083 raise error.WireprotoCommandError('unknown file node: %s',
1094 raise error.WireprotoCommandError('unknown file node: %s',
1084 (hex(node),))
1095 (hex(node),))
1085
1096
1086 revisions = store.emitrevisions(nodes,
1097 revisions = store.emitrevisions(nodes,
1087 revisiondata=b'revision' in fields,
1098 revisiondata=b'revision' in fields,
1088 assumehaveparentrevisions=haveparents)
1099 assumehaveparentrevisions=haveparents)
1089
1100
1090 yield {
1101 yield {
1091 b'totalitems': len(nodes),
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 yield o
1106 yield o
1096
1107
1097 def filesdatacapabilities(repo, proto):
1108 def filesdatacapabilities(repo, proto):
1098 batchsize = repo.ui.configint(
1109 batchsize = repo.ui.configint(
1099 b'experimental', b'server.filesdata.recommended-batch-size')
1110 b'experimental', b'server.filesdata.recommended-batch-size')
1100 return {
1111 return {
1101 b'recommendedbatchsize': batchsize,
1112 b'recommendedbatchsize': batchsize,
1102 }
1113 }
1103
1114
1104 @wireprotocommand(
1115 @wireprotocommand(
1105 'filesdata',
1116 'filesdata',
1106 args={
1117 args={
1107 'haveparents': {
1118 'haveparents': {
1108 'type': 'bool',
1119 'type': 'bool',
1109 'default': lambda: False,
1120 'default': lambda: False,
1110 'example': True,
1121 'example': True,
1111 },
1122 },
1112 'fields': {
1123 'fields': {
1113 'type': 'set',
1124 'type': 'set',
1114 'default': set,
1125 'default': set,
1115 'example': {b'parents', b'revision'},
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 'pathfilter': {
1130 'pathfilter': {
1119 'type': 'dict',
1131 'type': 'dict',
1120 'default': lambda: None,
1132 'default': lambda: None,
1121 'example': {b'include': [b'path:tests']},
1133 'example': {b'include': [b'path:tests']},
1122 },
1134 },
1123 'revisions': {
1135 'revisions': {
1124 'type': 'list',
1136 'type': 'list',
1125 'example': [{
1137 'example': [{
1126 b'type': b'changesetexplicit',
1138 b'type': b'changesetexplicit',
1127 b'nodes': [b'abcdef...'],
1139 b'nodes': [b'abcdef...'],
1128 }],
1140 }],
1129 },
1141 },
1130 },
1142 },
1131 permission='pull',
1143 permission='pull',
1132 # TODO censoring a file revision won't invalidate the cache.
1144 # TODO censoring a file revision won't invalidate the cache.
1133 # Figure out a way to take censoring into account when deriving
1145 # Figure out a way to take censoring into account when deriving
1134 # the cache key.
1146 # the cache key.
1135 cachekeyfn=makecommandcachekeyfn('filesdata', 1, allargs=True),
1147 cachekeyfn=makecommandcachekeyfn('filesdata', 1, allargs=True),
1136 extracapabilitiesfn=filesdatacapabilities)
1148 extracapabilitiesfn=filesdatacapabilities)
1137 def filesdata(repo, proto, haveparents, fields, pathfilter, revisions):
1149 def filesdata(repo, proto, haveparents, fields, pathfilter, revisions):
1138 # TODO This should operate on a repo that exposes obsolete changesets. There
1150 # TODO This should operate on a repo that exposes obsolete changesets. There
1139 # is a race between a client making a push that obsoletes a changeset and
1151 # is a race between a client making a push that obsoletes a changeset and
1140 # another client fetching files data for that changeset. If a client has a
1152 # another client fetching files data for that changeset. If a client has a
1141 # changeset, it should probably be allowed to access files data for that
1153 # changeset, it should probably be allowed to access files data for that
1142 # changeset.
1154 # changeset.
1143
1155
1144 cl = repo.changelog
1156 cl = repo.changelog
1145 outgoing = resolvenodes(repo, revisions)
1157 outgoing = resolvenodes(repo, revisions)
1146 filematcher = makefilematcher(repo, pathfilter)
1158 filematcher = makefilematcher(repo, pathfilter)
1147
1159
1148 # Figure out what needs to be emitted.
1160 # Figure out what needs to be emitted.
1149 changedpaths = set()
1161 changedpaths = set()
1150 fnodes = collections.defaultdict(set)
1162 fnodes = collections.defaultdict(set)
1151
1163
1152 for node in outgoing:
1164 for node in outgoing:
1153 ctx = repo[node]
1165 ctx = repo[node]
1154 changedpaths.update(ctx.files())
1166 changedpaths.update(ctx.files())
1155
1167
1156 changedpaths = sorted(p for p in changedpaths if filematcher(p))
1168 changedpaths = sorted(p for p in changedpaths if filematcher(p))
1157
1169
1158 # If ancestors are known, we send file revisions having a linkrev in the
1170 # If ancestors are known, we send file revisions having a linkrev in the
1159 # outgoing set of changeset revisions.
1171 # outgoing set of changeset revisions.
1160 if haveparents:
1172 if haveparents:
1161 outgoingclrevs = set(cl.rev(n) for n in outgoing)
1173 outgoingclrevs = set(cl.rev(n) for n in outgoing)
1162
1174
1163 for path in changedpaths:
1175 for path in changedpaths:
1164 try:
1176 try:
1165 store = getfilestore(repo, proto, path)
1177 store = getfilestore(repo, proto, path)
1166 except FileAccessError as e:
1178 except FileAccessError as e:
1167 raise error.WireprotoCommandError(e.msg, e.args)
1179 raise error.WireprotoCommandError(e.msg, e.args)
1168
1180
1169 for rev in store:
1181 for rev in store:
1170 linkrev = store.linkrev(rev)
1182 linkrev = store.linkrev(rev)
1171
1183
1172 if linkrev in outgoingclrevs:
1184 if linkrev in outgoingclrevs:
1173 fnodes[path].add(store.node(rev))
1185 fnodes[path].add(store.node(rev))
1174
1186
1175 # If ancestors aren't known, we walk the manifests and send all
1187 # If ancestors aren't known, we walk the manifests and send all
1176 # encountered file revisions.
1188 # encountered file revisions.
1177 else:
1189 else:
1178 for node in outgoing:
1190 for node in outgoing:
1179 mctx = repo[node].manifestctx()
1191 mctx = repo[node].manifestctx()
1180
1192
1181 for path, fnode in mctx.read().items():
1193 for path, fnode in mctx.read().items():
1182 if filematcher(path):
1194 if filematcher(path):
1183 fnodes[path].add(fnode)
1195 fnodes[path].add(fnode)
1184
1196
1185 yield {
1197 yield {
1186 b'totalpaths': len(fnodes),
1198 b'totalpaths': len(fnodes),
1187 b'totalitems': sum(len(v) for v in fnodes.values())
1199 b'totalitems': sum(len(v) for v in fnodes.values())
1188 }
1200 }
1189
1201
1190 for path, filenodes in sorted(fnodes.items()):
1202 for path, filenodes in sorted(fnodes.items()):
1191 try:
1203 try:
1192 store = getfilestore(repo, proto, path)
1204 store = getfilestore(repo, proto, path)
1193 except FileAccessError as e:
1205 except FileAccessError as e:
1194 raise error.WireprotoCommandError(e.msg, e.args)
1206 raise error.WireprotoCommandError(e.msg, e.args)
1195
1207
1196 yield {
1208 yield {
1197 b'path': path,
1209 b'path': path,
1198 b'totalitems': len(filenodes),
1210 b'totalitems': len(filenodes),
1199 }
1211 }
1200
1212
1201 revisions = store.emitrevisions(filenodes,
1213 revisions = store.emitrevisions(filenodes,
1202 revisiondata=b'revision' in fields,
1214 revisiondata=b'revision' in fields,
1203 assumehaveparentrevisions=haveparents)
1215 assumehaveparentrevisions=haveparents)
1204
1216
1205 for o in emitfilerevisions(revisions, fields):
1217 for o in emitfilerevisions(repo, path, revisions, fields):
1206 yield o
1218 yield o
1207
1219
1208 @wireprotocommand(
1220 @wireprotocommand(
1209 'heads',
1221 'heads',
1210 args={
1222 args={
1211 'publiconly': {
1223 'publiconly': {
1212 'type': 'bool',
1224 'type': 'bool',
1213 'default': lambda: False,
1225 'default': lambda: False,
1214 'example': False,
1226 'example': False,
1215 },
1227 },
1216 },
1228 },
1217 permission='pull')
1229 permission='pull')
1218 def headsv2(repo, proto, publiconly):
1230 def headsv2(repo, proto, publiconly):
1219 if publiconly:
1231 if publiconly:
1220 repo = repo.filtered('immutable')
1232 repo = repo.filtered('immutable')
1221
1233
1222 yield repo.heads()
1234 yield repo.heads()
1223
1235
1224 @wireprotocommand(
1236 @wireprotocommand(
1225 'known',
1237 'known',
1226 args={
1238 args={
1227 'nodes': {
1239 'nodes': {
1228 'type': 'list',
1240 'type': 'list',
1229 'default': list,
1241 'default': list,
1230 'example': [b'deadbeef'],
1242 'example': [b'deadbeef'],
1231 },
1243 },
1232 },
1244 },
1233 permission='pull')
1245 permission='pull')
1234 def knownv2(repo, proto, nodes):
1246 def knownv2(repo, proto, nodes):
1235 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
1247 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
1236 yield result
1248 yield result
1237
1249
1238 @wireprotocommand(
1250 @wireprotocommand(
1239 'listkeys',
1251 'listkeys',
1240 args={
1252 args={
1241 'namespace': {
1253 'namespace': {
1242 'type': 'bytes',
1254 'type': 'bytes',
1243 'example': b'ns',
1255 'example': b'ns',
1244 },
1256 },
1245 },
1257 },
1246 permission='pull')
1258 permission='pull')
1247 def listkeysv2(repo, proto, namespace):
1259 def listkeysv2(repo, proto, namespace):
1248 keys = repo.listkeys(encoding.tolocal(namespace))
1260 keys = repo.listkeys(encoding.tolocal(namespace))
1249 keys = {encoding.fromlocal(k): encoding.fromlocal(v)
1261 keys = {encoding.fromlocal(k): encoding.fromlocal(v)
1250 for k, v in keys.iteritems()}
1262 for k, v in keys.iteritems()}
1251
1263
1252 yield keys
1264 yield keys
1253
1265
1254 @wireprotocommand(
1266 @wireprotocommand(
1255 'lookup',
1267 'lookup',
1256 args={
1268 args={
1257 'key': {
1269 'key': {
1258 'type': 'bytes',
1270 'type': 'bytes',
1259 'example': b'foo',
1271 'example': b'foo',
1260 },
1272 },
1261 },
1273 },
1262 permission='pull')
1274 permission='pull')
1263 def lookupv2(repo, proto, key):
1275 def lookupv2(repo, proto, key):
1264 key = encoding.tolocal(key)
1276 key = encoding.tolocal(key)
1265
1277
1266 # TODO handle exception.
1278 # TODO handle exception.
1267 node = repo.lookup(key)
1279 node = repo.lookup(key)
1268
1280
1269 yield node
1281 yield node
1270
1282
1271 def manifestdatacapabilities(repo, proto):
1283 def manifestdatacapabilities(repo, proto):
1272 batchsize = repo.ui.configint(
1284 batchsize = repo.ui.configint(
1273 b'experimental', b'server.manifestdata.recommended-batch-size')
1285 b'experimental', b'server.manifestdata.recommended-batch-size')
1274
1286
1275 return {
1287 return {
1276 b'recommendedbatchsize': batchsize,
1288 b'recommendedbatchsize': batchsize,
1277 }
1289 }
1278
1290
1279 @wireprotocommand(
1291 @wireprotocommand(
1280 'manifestdata',
1292 'manifestdata',
1281 args={
1293 args={
1282 'nodes': {
1294 'nodes': {
1283 'type': 'list',
1295 'type': 'list',
1284 'example': [b'0123456...'],
1296 'example': [b'0123456...'],
1285 },
1297 },
1286 'haveparents': {
1298 'haveparents': {
1287 'type': 'bool',
1299 'type': 'bool',
1288 'default': lambda: False,
1300 'default': lambda: False,
1289 'example': True,
1301 'example': True,
1290 },
1302 },
1291 'fields': {
1303 'fields': {
1292 'type': 'set',
1304 'type': 'set',
1293 'default': set,
1305 'default': set,
1294 'example': {b'parents', b'revision'},
1306 'example': {b'parents', b'revision'},
1295 'validvalues': {b'parents', b'revision'},
1307 'validvalues': {b'parents', b'revision'},
1296 },
1308 },
1297 'tree': {
1309 'tree': {
1298 'type': 'bytes',
1310 'type': 'bytes',
1299 'example': b'',
1311 'example': b'',
1300 },
1312 },
1301 },
1313 },
1302 permission='pull',
1314 permission='pull',
1303 cachekeyfn=makecommandcachekeyfn('manifestdata', 1, allargs=True),
1315 cachekeyfn=makecommandcachekeyfn('manifestdata', 1, allargs=True),
1304 extracapabilitiesfn=manifestdatacapabilities)
1316 extracapabilitiesfn=manifestdatacapabilities)
1305 def manifestdata(repo, proto, haveparents, nodes, fields, tree):
1317 def manifestdata(repo, proto, haveparents, nodes, fields, tree):
1306 store = repo.manifestlog.getstorage(tree)
1318 store = repo.manifestlog.getstorage(tree)
1307
1319
1308 # Validate the node is known and abort on unknown revisions.
1320 # Validate the node is known and abort on unknown revisions.
1309 for node in nodes:
1321 for node in nodes:
1310 try:
1322 try:
1311 store.rev(node)
1323 store.rev(node)
1312 except error.LookupError:
1324 except error.LookupError:
1313 raise error.WireprotoCommandError(
1325 raise error.WireprotoCommandError(
1314 'unknown node: %s', (node,))
1326 'unknown node: %s', (node,))
1315
1327
1316 revisions = store.emitrevisions(nodes,
1328 revisions = store.emitrevisions(nodes,
1317 revisiondata=b'revision' in fields,
1329 revisiondata=b'revision' in fields,
1318 assumehaveparentrevisions=haveparents)
1330 assumehaveparentrevisions=haveparents)
1319
1331
1320 yield {
1332 yield {
1321 b'totalitems': len(nodes),
1333 b'totalitems': len(nodes),
1322 }
1334 }
1323
1335
1324 for revision in revisions:
1336 for revision in revisions:
1325 d = {
1337 d = {
1326 b'node': revision.node,
1338 b'node': revision.node,
1327 }
1339 }
1328
1340
1329 if b'parents' in fields:
1341 if b'parents' in fields:
1330 d[b'parents'] = [revision.p1node, revision.p2node]
1342 d[b'parents'] = [revision.p1node, revision.p2node]
1331
1343
1332 followingmeta = []
1344 followingmeta = []
1333 followingdata = []
1345 followingdata = []
1334
1346
1335 if b'revision' in fields:
1347 if b'revision' in fields:
1336 if revision.revision is not None:
1348 if revision.revision is not None:
1337 followingmeta.append((b'revision', len(revision.revision)))
1349 followingmeta.append((b'revision', len(revision.revision)))
1338 followingdata.append(revision.revision)
1350 followingdata.append(revision.revision)
1339 else:
1351 else:
1340 d[b'deltabasenode'] = revision.basenode
1352 d[b'deltabasenode'] = revision.basenode
1341 followingmeta.append((b'delta', len(revision.delta)))
1353 followingmeta.append((b'delta', len(revision.delta)))
1342 followingdata.append(revision.delta)
1354 followingdata.append(revision.delta)
1343
1355
1344 if followingmeta:
1356 if followingmeta:
1345 d[b'fieldsfollowing'] = followingmeta
1357 d[b'fieldsfollowing'] = followingmeta
1346
1358
1347 yield d
1359 yield d
1348
1360
1349 for extra in followingdata:
1361 for extra in followingdata:
1350 yield extra
1362 yield extra
1351
1363
1352 @wireprotocommand(
1364 @wireprotocommand(
1353 'pushkey',
1365 'pushkey',
1354 args={
1366 args={
1355 'namespace': {
1367 'namespace': {
1356 'type': 'bytes',
1368 'type': 'bytes',
1357 'example': b'ns',
1369 'example': b'ns',
1358 },
1370 },
1359 'key': {
1371 'key': {
1360 'type': 'bytes',
1372 'type': 'bytes',
1361 'example': b'key',
1373 'example': b'key',
1362 },
1374 },
1363 'old': {
1375 'old': {
1364 'type': 'bytes',
1376 'type': 'bytes',
1365 'example': b'old',
1377 'example': b'old',
1366 },
1378 },
1367 'new': {
1379 'new': {
1368 'type': 'bytes',
1380 'type': 'bytes',
1369 'example': 'new',
1381 'example': 'new',
1370 },
1382 },
1371 },
1383 },
1372 permission='push')
1384 permission='push')
1373 def pushkeyv2(repo, proto, namespace, key, old, new):
1385 def pushkeyv2(repo, proto, namespace, key, old, new):
1374 # TODO handle ui output redirection
1386 # TODO handle ui output redirection
1375 yield repo.pushkey(encoding.tolocal(namespace),
1387 yield repo.pushkey(encoding.tolocal(namespace),
1376 encoding.tolocal(key),
1388 encoding.tolocal(key),
1377 encoding.tolocal(old),
1389 encoding.tolocal(old),
1378 encoding.tolocal(new))
1390 encoding.tolocal(new))
1379
1391
1380
1392
1381 @wireprotocommand(
1393 @wireprotocommand(
1382 'rawstorefiledata',
1394 'rawstorefiledata',
1383 args={
1395 args={
1384 'files': {
1396 'files': {
1385 'type': 'list',
1397 'type': 'list',
1386 'example': [b'changelog', b'manifestlog'],
1398 'example': [b'changelog', b'manifestlog'],
1387 },
1399 },
1388 'pathfilter': {
1400 'pathfilter': {
1389 'type': 'list',
1401 'type': 'list',
1390 'default': lambda: None,
1402 'default': lambda: None,
1391 'example': {b'include': [b'path:tests']},
1403 'example': {b'include': [b'path:tests']},
1392 },
1404 },
1393 },
1405 },
1394 permission='pull')
1406 permission='pull')
1395 def rawstorefiledata(repo, proto, files, pathfilter):
1407 def rawstorefiledata(repo, proto, files, pathfilter):
1396 if not streamclone.allowservergeneration(repo):
1408 if not streamclone.allowservergeneration(repo):
1397 raise error.WireprotoCommandError(b'stream clone is disabled')
1409 raise error.WireprotoCommandError(b'stream clone is disabled')
1398
1410
1399 # TODO support dynamically advertising what store files "sets" are
1411 # TODO support dynamically advertising what store files "sets" are
1400 # available. For now, we support changelog, manifestlog, and files.
1412 # available. For now, we support changelog, manifestlog, and files.
1401 files = set(files)
1413 files = set(files)
1402 allowedfiles = {b'changelog', b'manifestlog'}
1414 allowedfiles = {b'changelog', b'manifestlog'}
1403
1415
1404 unsupported = files - allowedfiles
1416 unsupported = files - allowedfiles
1405 if unsupported:
1417 if unsupported:
1406 raise error.WireprotoCommandError(b'unknown file type: %s',
1418 raise error.WireprotoCommandError(b'unknown file type: %s',
1407 (b', '.join(sorted(unsupported)),))
1419 (b', '.join(sorted(unsupported)),))
1408
1420
1409 with repo.lock():
1421 with repo.lock():
1410 topfiles = list(repo.store.topfiles())
1422 topfiles = list(repo.store.topfiles())
1411
1423
1412 sendfiles = []
1424 sendfiles = []
1413 totalsize = 0
1425 totalsize = 0
1414
1426
1415 # TODO this is a bunch of storage layer interface abstractions because
1427 # TODO this is a bunch of storage layer interface abstractions because
1416 # it assumes revlogs.
1428 # it assumes revlogs.
1417 for name, encodedname, size in topfiles:
1429 for name, encodedname, size in topfiles:
1418 if b'changelog' in files and name.startswith(b'00changelog'):
1430 if b'changelog' in files and name.startswith(b'00changelog'):
1419 pass
1431 pass
1420 elif b'manifestlog' in files and name.startswith(b'00manifest'):
1432 elif b'manifestlog' in files and name.startswith(b'00manifest'):
1421 pass
1433 pass
1422 else:
1434 else:
1423 continue
1435 continue
1424
1436
1425 sendfiles.append((b'store', name, size))
1437 sendfiles.append((b'store', name, size))
1426 totalsize += size
1438 totalsize += size
1427
1439
1428 yield {
1440 yield {
1429 b'filecount': len(sendfiles),
1441 b'filecount': len(sendfiles),
1430 b'totalsize': totalsize,
1442 b'totalsize': totalsize,
1431 }
1443 }
1432
1444
1433 for location, name, size in sendfiles:
1445 for location, name, size in sendfiles:
1434 yield {
1446 yield {
1435 b'location': location,
1447 b'location': location,
1436 b'path': name,
1448 b'path': name,
1437 b'size': size,
1449 b'size': size,
1438 }
1450 }
1439
1451
1440 # We have to use a closure for this to ensure the context manager is
1452 # We have to use a closure for this to ensure the context manager is
1441 # closed only after sending the final chunk.
1453 # closed only after sending the final chunk.
1442 def getfiledata():
1454 def getfiledata():
1443 with repo.svfs(name, 'rb', auditpath=False) as fh:
1455 with repo.svfs(name, 'rb', auditpath=False) as fh:
1444 for chunk in util.filechunkiter(fh, limit=size):
1456 for chunk in util.filechunkiter(fh, limit=size):
1445 yield chunk
1457 yield chunk
1446
1458
1447 yield wireprototypes.indefinitebytestringresponse(
1459 yield wireprototypes.indefinitebytestringresponse(
1448 getfiledata())
1460 getfiledata())
@@ -1,759 +1,759 b''
1 #require no-chg
1 #require no-chg
2
2
3 $ . $TESTDIR/wireprotohelpers.sh
3 $ . $TESTDIR/wireprotohelpers.sh
4
4
5 $ cat >> $HGRCPATH << EOF
5 $ cat >> $HGRCPATH << EOF
6 > [web]
6 > [web]
7 > push_ssl = false
7 > push_ssl = false
8 > allow_push = *
8 > allow_push = *
9 > EOF
9 > EOF
10
10
11 $ hg init server
11 $ hg init server
12 $ cd server
12 $ cd server
13 $ touch a
13 $ touch a
14 $ hg -q commit -A -m initial
14 $ hg -q commit -A -m initial
15 $ cd ..
15 $ cd ..
16
16
17 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
17 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
18 $ cat hg.pid >> $DAEMON_PIDS
18 $ cat hg.pid >> $DAEMON_PIDS
19
19
20 compression formats are advertised in compression capability
20 compression formats are advertised in compression capability
21
21
22 #if zstd
22 #if zstd
23 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zstd,zlib$' > /dev/null
23 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zstd,zlib$' > /dev/null
24 #else
24 #else
25 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zlib$' > /dev/null
25 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zlib$' > /dev/null
26 #endif
26 #endif
27
27
28 $ killdaemons.py
28 $ killdaemons.py
29
29
30 server.compressionengines can replace engines list wholesale
30 server.compressionengines can replace engines list wholesale
31
31
32 $ hg serve --config server.compressionengines=none -R server -p $HGPORT -d --pid-file hg.pid
32 $ hg serve --config server.compressionengines=none -R server -p $HGPORT -d --pid-file hg.pid
33 $ cat hg.pid > $DAEMON_PIDS
33 $ cat hg.pid > $DAEMON_PIDS
34 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none$' > /dev/null
34 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none$' > /dev/null
35
35
36 $ killdaemons.py
36 $ killdaemons.py
37
37
38 Order of engines can also change
38 Order of engines can also change
39
39
40 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
40 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
41 $ cat hg.pid > $DAEMON_PIDS
41 $ cat hg.pid > $DAEMON_PIDS
42 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none,zlib$' > /dev/null
42 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none,zlib$' > /dev/null
43
43
44 $ killdaemons.py
44 $ killdaemons.py
45
45
46 Start a default server again
46 Start a default server again
47
47
48 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
48 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
49 $ cat hg.pid > $DAEMON_PIDS
49 $ cat hg.pid > $DAEMON_PIDS
50
50
51 Server should send application/mercurial-0.1 to clients if no Accept is used
51 Server should send application/mercurial-0.1 to clients if no Accept is used
52
52
53 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
53 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
54 200 Script output follows
54 200 Script output follows
55 content-type: application/mercurial-0.1
55 content-type: application/mercurial-0.1
56 date: $HTTP_DATE$
56 date: $HTTP_DATE$
57 server: testing stub value
57 server: testing stub value
58 transfer-encoding: chunked
58 transfer-encoding: chunked
59
59
60 Server should send application/mercurial-0.1 when client says it wants it
60 Server should send application/mercurial-0.1 when client says it wants it
61
61
62 $ get-with-headers.py --hgproto '0.1' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
62 $ get-with-headers.py --hgproto '0.1' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
63 200 Script output follows
63 200 Script output follows
64 content-type: application/mercurial-0.1
64 content-type: application/mercurial-0.1
65 date: $HTTP_DATE$
65 date: $HTTP_DATE$
66 server: testing stub value
66 server: testing stub value
67 transfer-encoding: chunked
67 transfer-encoding: chunked
68
68
69 Server should send application/mercurial-0.2 when client says it wants it
69 Server should send application/mercurial-0.2 when client says it wants it
70
70
71 $ get-with-headers.py --hgproto '0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
71 $ get-with-headers.py --hgproto '0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
72 200 Script output follows
72 200 Script output follows
73 content-type: application/mercurial-0.2
73 content-type: application/mercurial-0.2
74 date: $HTTP_DATE$
74 date: $HTTP_DATE$
75 server: testing stub value
75 server: testing stub value
76 transfer-encoding: chunked
76 transfer-encoding: chunked
77
77
78 $ get-with-headers.py --hgproto '0.1 0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
78 $ get-with-headers.py --hgproto '0.1 0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
79 200 Script output follows
79 200 Script output follows
80 content-type: application/mercurial-0.2
80 content-type: application/mercurial-0.2
81 date: $HTTP_DATE$
81 date: $HTTP_DATE$
82 server: testing stub value
82 server: testing stub value
83 transfer-encoding: chunked
83 transfer-encoding: chunked
84
84
85 Requesting a compression format that server doesn't support results will fall back to 0.1
85 Requesting a compression format that server doesn't support results will fall back to 0.1
86
86
87 $ get-with-headers.py --hgproto '0.2 comp=aa' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
87 $ get-with-headers.py --hgproto '0.2 comp=aa' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
88 200 Script output follows
88 200 Script output follows
89 content-type: application/mercurial-0.1
89 content-type: application/mercurial-0.1
90 date: $HTTP_DATE$
90 date: $HTTP_DATE$
91 server: testing stub value
91 server: testing stub value
92 transfer-encoding: chunked
92 transfer-encoding: chunked
93
93
94 #if zstd
94 #if zstd
95 zstd is used if available
95 zstd is used if available
96
96
97 $ get-with-headers.py --hgproto '0.2 comp=zstd' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
97 $ get-with-headers.py --hgproto '0.2 comp=zstd' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
98 $ f --size --hexdump --bytes 36 --sha1 resp
98 $ f --size --hexdump --bytes 36 --sha1 resp
99 resp: size=248, sha1=4d8d8f87fb82bd542ce52881fdc94f850748
99 resp: size=248, sha1=4d8d8f87fb82bd542ce52881fdc94f850748
100 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
100 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
101 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 73 74 64 |t follows...zstd|
101 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 73 74 64 |t follows...zstd|
102 0020: 28 b5 2f fd |(./.|
102 0020: 28 b5 2f fd |(./.|
103
103
104 #endif
104 #endif
105
105
106 application/mercurial-0.2 is not yet used on non-streaming responses
106 application/mercurial-0.2 is not yet used on non-streaming responses
107
107
108 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=heads' -
108 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=heads' -
109 200 Script output follows
109 200 Script output follows
110 content-length: 41
110 content-length: 41
111 content-type: application/mercurial-0.1
111 content-type: application/mercurial-0.1
112 date: $HTTP_DATE$
112 date: $HTTP_DATE$
113 server: testing stub value
113 server: testing stub value
114
114
115 e93700bd72895c5addab234c56d4024b487a362f
115 e93700bd72895c5addab234c56d4024b487a362f
116
116
117 Now test protocol preference usage
117 Now test protocol preference usage
118
118
119 $ killdaemons.py
119 $ killdaemons.py
120 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
120 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
121 $ cat hg.pid > $DAEMON_PIDS
121 $ cat hg.pid > $DAEMON_PIDS
122
122
123 No Accept will send 0.1+zlib, even though "none" is preferred b/c "none" isn't supported on 0.1
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 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' Content-Type
125 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' Content-Type
126 200 Script output follows
126 200 Script output follows
127 content-type: application/mercurial-0.1
127 content-type: application/mercurial-0.1
128
128
129 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
129 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
130 $ f --size --hexdump --bytes 28 --sha1 resp
130 $ f --size --hexdump --bytes 28 --sha1 resp
131 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
131 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
132 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
132 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
133 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
133 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
134
134
135 Explicit 0.1 will send zlib because "none" isn't supported on 0.1
135 Explicit 0.1 will send zlib because "none" isn't supported on 0.1
136
136
137 $ get-with-headers.py --hgproto '0.1' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
137 $ get-with-headers.py --hgproto '0.1' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
138 $ f --size --hexdump --bytes 28 --sha1 resp
138 $ f --size --hexdump --bytes 28 --sha1 resp
139 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
139 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
140 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
140 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
141 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
141 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
142
142
143 0.2 with no compression will get "none" because that is server's preference
143 0.2 with no compression will get "none" because that is server's preference
144 (spec says ZL and UN are implicitly supported)
144 (spec says ZL and UN are implicitly supported)
145
145
146 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
146 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
147 $ f --size --hexdump --bytes 32 --sha1 resp
147 $ f --size --hexdump --bytes 32 --sha1 resp
148 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
148 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
149 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
149 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
150 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
150 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
151
151
152 Client receives server preference even if local order doesn't match
152 Client receives server preference even if local order doesn't match
153
153
154 $ get-with-headers.py --hgproto '0.2 comp=zlib,none' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
154 $ get-with-headers.py --hgproto '0.2 comp=zlib,none' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
155 $ f --size --hexdump --bytes 32 --sha1 resp
155 $ f --size --hexdump --bytes 32 --sha1 resp
156 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
156 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
157 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
157 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
158 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
158 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
159
159
160 Client receives only supported format even if not server preferred format
160 Client receives only supported format even if not server preferred format
161
161
162 $ get-with-headers.py --hgproto '0.2 comp=zlib' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
162 $ get-with-headers.py --hgproto '0.2 comp=zlib' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
163 $ f --size --hexdump --bytes 33 --sha1 resp
163 $ f --size --hexdump --bytes 33 --sha1 resp
164 resp: size=232, sha1=a1c727f0c9693ca15742a75c30419bc36
164 resp: size=232, sha1=a1c727f0c9693ca15742a75c30419bc36
165 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
165 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
166 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib|
166 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib|
167 0020: 78 |x|
167 0020: 78 |x|
168
168
169 $ killdaemons.py
169 $ killdaemons.py
170 $ cd ..
170 $ cd ..
171
171
172 Test listkeys for listing namespaces
172 Test listkeys for listing namespaces
173
173
174 $ hg init empty
174 $ hg init empty
175 $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
175 $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
176 $ cat hg.pid > $DAEMON_PIDS
176 $ cat hg.pid > $DAEMON_PIDS
177
177
178 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
178 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
179 > command listkeys
179 > command listkeys
180 > namespace namespaces
180 > namespace namespaces
181 > EOF
181 > EOF
182 s> GET /?cmd=capabilities HTTP/1.1\r\n
182 s> GET /?cmd=capabilities HTTP/1.1\r\n
183 s> Accept-Encoding: identity\r\n
183 s> Accept-Encoding: identity\r\n
184 s> accept: application/mercurial-0.1\r\n
184 s> accept: application/mercurial-0.1\r\n
185 s> host: $LOCALIP:$HGPORT\r\n (glob)
185 s> host: $LOCALIP:$HGPORT\r\n (glob)
186 s> user-agent: Mercurial debugwireproto\r\n
186 s> user-agent: Mercurial debugwireproto\r\n
187 s> \r\n
187 s> \r\n
188 s> makefile('rb', None)
188 s> makefile('rb', None)
189 s> HTTP/1.1 200 Script output follows\r\n
189 s> HTTP/1.1 200 Script output follows\r\n
190 s> Server: testing stub value\r\n
190 s> Server: testing stub value\r\n
191 s> Date: $HTTP_DATE$\r\n
191 s> Date: $HTTP_DATE$\r\n
192 s> Content-Type: application/mercurial-0.1\r\n
192 s> Content-Type: application/mercurial-0.1\r\n
193 s> Content-Length: *\r\n (glob)
193 s> Content-Length: *\r\n (glob)
194 s> \r\n
194 s> \r\n
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
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 sending listkeys command
196 sending listkeys command
197 s> GET /?cmd=listkeys HTTP/1.1\r\n
197 s> GET /?cmd=listkeys HTTP/1.1\r\n
198 s> Accept-Encoding: identity\r\n
198 s> Accept-Encoding: identity\r\n
199 s> vary: X-HgArg-1,X-HgProto-1\r\n
199 s> vary: X-HgArg-1,X-HgProto-1\r\n
200 s> x-hgarg-1: namespace=namespaces\r\n
200 s> x-hgarg-1: namespace=namespaces\r\n
201 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
201 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
202 s> accept: application/mercurial-0.1\r\n
202 s> accept: application/mercurial-0.1\r\n
203 s> host: $LOCALIP:$HGPORT\r\n (glob)
203 s> host: $LOCALIP:$HGPORT\r\n (glob)
204 s> user-agent: Mercurial debugwireproto\r\n
204 s> user-agent: Mercurial debugwireproto\r\n
205 s> \r\n
205 s> \r\n
206 s> makefile('rb', None)
206 s> makefile('rb', None)
207 s> HTTP/1.1 200 Script output follows\r\n
207 s> HTTP/1.1 200 Script output follows\r\n
208 s> Server: testing stub value\r\n
208 s> Server: testing stub value\r\n
209 s> Date: $HTTP_DATE$\r\n
209 s> Date: $HTTP_DATE$\r\n
210 s> Content-Type: application/mercurial-0.1\r\n
210 s> Content-Type: application/mercurial-0.1\r\n
211 s> Content-Length: 30\r\n
211 s> Content-Length: 30\r\n
212 s> \r\n
212 s> \r\n
213 s> bookmarks\t\n
213 s> bookmarks\t\n
214 s> namespaces\t\n
214 s> namespaces\t\n
215 s> phases\t
215 s> phases\t
216 response: {
216 response: {
217 b'bookmarks': b'',
217 b'bookmarks': b'',
218 b'namespaces': b'',
218 b'namespaces': b'',
219 b'phases': b''
219 b'phases': b''
220 }
220 }
221 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
221 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
222
222
223 Same thing, but with "httprequest" command
223 Same thing, but with "httprequest" command
224
224
225 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
225 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
226 > httprequest GET ?cmd=listkeys
226 > httprequest GET ?cmd=listkeys
227 > user-agent: test
227 > user-agent: test
228 > x-hgarg-1: namespace=namespaces
228 > x-hgarg-1: namespace=namespaces
229 > EOF
229 > EOF
230 using raw connection to peer
230 using raw connection to peer
231 s> GET /?cmd=listkeys HTTP/1.1\r\n
231 s> GET /?cmd=listkeys HTTP/1.1\r\n
232 s> Accept-Encoding: identity\r\n
232 s> Accept-Encoding: identity\r\n
233 s> user-agent: test\r\n
233 s> user-agent: test\r\n
234 s> x-hgarg-1: namespace=namespaces\r\n
234 s> x-hgarg-1: namespace=namespaces\r\n
235 s> host: $LOCALIP:$HGPORT\r\n (glob)
235 s> host: $LOCALIP:$HGPORT\r\n (glob)
236 s> \r\n
236 s> \r\n
237 s> makefile('rb', None)
237 s> makefile('rb', None)
238 s> HTTP/1.1 200 Script output follows\r\n
238 s> HTTP/1.1 200 Script output follows\r\n
239 s> Server: testing stub value\r\n
239 s> Server: testing stub value\r\n
240 s> Date: $HTTP_DATE$\r\n
240 s> Date: $HTTP_DATE$\r\n
241 s> Content-Type: application/mercurial-0.1\r\n
241 s> Content-Type: application/mercurial-0.1\r\n
242 s> Content-Length: 30\r\n
242 s> Content-Length: 30\r\n
243 s> \r\n
243 s> \r\n
244 s> bookmarks\t\n
244 s> bookmarks\t\n
245 s> namespaces\t\n
245 s> namespaces\t\n
246 s> phases\t
246 s> phases\t
247
247
248 Client with HTTPv2 enabled advertises that and gets old capabilities response from old server
248 Client with HTTPv2 enabled advertises that and gets old capabilities response from old server
249
249
250 $ hg --config experimental.httppeer.advertise-v2=true --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
250 $ hg --config experimental.httppeer.advertise-v2=true --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
251 > command heads
251 > command heads
252 > EOF
252 > EOF
253 s> GET /?cmd=capabilities HTTP/1.1\r\n
253 s> GET /?cmd=capabilities HTTP/1.1\r\n
254 s> Accept-Encoding: identity\r\n
254 s> Accept-Encoding: identity\r\n
255 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
255 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
256 s> x-hgproto-1: cbor\r\n
256 s> x-hgproto-1: cbor\r\n
257 s> x-hgupgrade-1: exp-http-v2-0003\r\n
257 s> x-hgupgrade-1: exp-http-v2-0003\r\n
258 s> accept: application/mercurial-0.1\r\n
258 s> accept: application/mercurial-0.1\r\n
259 s> host: $LOCALIP:$HGPORT\r\n (glob)
259 s> host: $LOCALIP:$HGPORT\r\n (glob)
260 s> user-agent: Mercurial debugwireproto\r\n
260 s> user-agent: Mercurial debugwireproto\r\n
261 s> \r\n
261 s> \r\n
262 s> makefile('rb', None)
262 s> makefile('rb', None)
263 s> HTTP/1.1 200 Script output follows\r\n
263 s> HTTP/1.1 200 Script output follows\r\n
264 s> Server: testing stub value\r\n
264 s> Server: testing stub value\r\n
265 s> Date: $HTTP_DATE$\r\n
265 s> Date: $HTTP_DATE$\r\n
266 s> Content-Type: application/mercurial-0.1\r\n
266 s> Content-Type: application/mercurial-0.1\r\n
267 s> Content-Length: *\r\n (glob)
267 s> Content-Length: *\r\n (glob)
268 s> \r\n
268 s> \r\n
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
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 sending heads command
270 sending heads command
271 s> GET /?cmd=heads HTTP/1.1\r\n
271 s> GET /?cmd=heads HTTP/1.1\r\n
272 s> Accept-Encoding: identity\r\n
272 s> Accept-Encoding: identity\r\n
273 s> vary: X-HgProto-1\r\n
273 s> vary: X-HgProto-1\r\n
274 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
274 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
275 s> accept: application/mercurial-0.1\r\n
275 s> accept: application/mercurial-0.1\r\n
276 s> host: $LOCALIP:$HGPORT\r\n (glob)
276 s> host: $LOCALIP:$HGPORT\r\n (glob)
277 s> user-agent: Mercurial debugwireproto\r\n
277 s> user-agent: Mercurial debugwireproto\r\n
278 s> \r\n
278 s> \r\n
279 s> makefile('rb', None)
279 s> makefile('rb', None)
280 s> HTTP/1.1 200 Script output follows\r\n
280 s> HTTP/1.1 200 Script output follows\r\n
281 s> Server: testing stub value\r\n
281 s> Server: testing stub value\r\n
282 s> Date: $HTTP_DATE$\r\n
282 s> Date: $HTTP_DATE$\r\n
283 s> Content-Type: application/mercurial-0.1\r\n
283 s> Content-Type: application/mercurial-0.1\r\n
284 s> Content-Length: 41\r\n
284 s> Content-Length: 41\r\n
285 s> \r\n
285 s> \r\n
286 s> 0000000000000000000000000000000000000000\n
286 s> 0000000000000000000000000000000000000000\n
287 response: [
287 response: [
288 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
290 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
291
291
292 $ killdaemons.py
292 $ killdaemons.py
293 $ enablehttpv2 empty
293 $ enablehttpv2 empty
294 $ hg --config server.compressionengines=zlib -R empty serve -p $HGPORT -d --pid-file hg.pid
294 $ hg --config server.compressionengines=zlib -R empty serve -p $HGPORT -d --pid-file hg.pid
295 $ cat hg.pid > $DAEMON_PIDS
295 $ cat hg.pid > $DAEMON_PIDS
296
296
297 Client with HTTPv2 enabled automatically upgrades if the server supports it
297 Client with HTTPv2 enabled automatically upgrades if the server supports it
298
298
299 $ hg --config experimental.httppeer.advertise-v2=true --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
299 $ hg --config experimental.httppeer.advertise-v2=true --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
300 > command heads
300 > command heads
301 > EOF
301 > EOF
302 s> GET /?cmd=capabilities HTTP/1.1\r\n
302 s> GET /?cmd=capabilities HTTP/1.1\r\n
303 s> Accept-Encoding: identity\r\n
303 s> Accept-Encoding: identity\r\n
304 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
304 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
305 s> x-hgproto-1: cbor\r\n
305 s> x-hgproto-1: cbor\r\n
306 s> x-hgupgrade-1: exp-http-v2-0003\r\n
306 s> x-hgupgrade-1: exp-http-v2-0003\r\n
307 s> accept: application/mercurial-0.1\r\n
307 s> accept: application/mercurial-0.1\r\n
308 s> host: $LOCALIP:$HGPORT\r\n (glob)
308 s> host: $LOCALIP:$HGPORT\r\n (glob)
309 s> user-agent: Mercurial debugwireproto\r\n
309 s> user-agent: Mercurial debugwireproto\r\n
310 s> \r\n
310 s> \r\n
311 s> makefile('rb', None)
311 s> makefile('rb', None)
312 s> HTTP/1.1 200 OK\r\n
312 s> HTTP/1.1 200 OK\r\n
313 s> Server: testing stub value\r\n
313 s> Server: testing stub value\r\n
314 s> Date: $HTTP_DATE$\r\n
314 s> Date: $HTTP_DATE$\r\n
315 s> Content-Type: application/mercurial-cbor\r\n
315 s> Content-Type: application/mercurial-cbor\r\n
316 s> Content-Length: *\r\n (glob)
316 s> Content-Length: *\r\n (glob)
317 s> \r\n
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 sending heads command
319 sending heads command
320 s> POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n
320 s> POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n
321 s> Accept-Encoding: identity\r\n
321 s> Accept-Encoding: identity\r\n
322 s> accept: application/mercurial-exp-framing-0006\r\n
322 s> accept: application/mercurial-exp-framing-0006\r\n
323 s> content-type: application/mercurial-exp-framing-0006\r\n
323 s> content-type: application/mercurial-exp-framing-0006\r\n
324 s> content-length: 56\r\n
324 s> content-length: 56\r\n
325 s> host: $LOCALIP:$HGPORT\r\n (glob)
325 s> host: $LOCALIP:$HGPORT\r\n (glob)
326 s> user-agent: Mercurial debugwireproto\r\n
326 s> user-agent: Mercurial debugwireproto\r\n
327 s> \r\n
327 s> \r\n
328 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads
328 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads
329 s> makefile('rb', None)
329 s> makefile('rb', None)
330 s> HTTP/1.1 200 OK\r\n
330 s> HTTP/1.1 200 OK\r\n
331 s> Server: testing stub value\r\n
331 s> Server: testing stub value\r\n
332 s> Date: $HTTP_DATE$\r\n
332 s> Date: $HTTP_DATE$\r\n
333 s> Content-Type: application/mercurial-exp-framing-0006\r\n
333 s> Content-Type: application/mercurial-exp-framing-0006\r\n
334 s> Transfer-Encoding: chunked\r\n
334 s> Transfer-Encoding: chunked\r\n
335 s> \r\n
335 s> \r\n
336 s> 11\r\n
336 s> 11\r\n
337 s> \t\x00\x00\x01\x00\x02\x01\x92
337 s> \t\x00\x00\x01\x00\x02\x01\x92
338 s> Hidentity
338 s> Hidentity
339 s> \r\n
339 s> \r\n
340 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
340 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
341 s> 13\r\n
341 s> 13\r\n
342 s> \x0b\x00\x00\x01\x00\x02\x041
342 s> \x0b\x00\x00\x01\x00\x02\x041
343 s> \xa1FstatusBok
343 s> \xa1FstatusBok
344 s> \r\n
344 s> \r\n
345 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
345 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
346 s> 1e\r\n
346 s> 1e\r\n
347 s> \x16\x00\x00\x01\x00\x02\x041
347 s> \x16\x00\x00\x01\x00\x02\x041
348 s> \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
348 s> \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
349 s> \r\n
349 s> \r\n
350 received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
350 received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
351 s> 8\r\n
351 s> 8\r\n
352 s> \x00\x00\x00\x01\x00\x02\x002
352 s> \x00\x00\x00\x01\x00\x02\x002
353 s> \r\n
353 s> \r\n
354 s> 0\r\n
354 s> 0\r\n
355 s> \r\n
355 s> \r\n
356 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
356 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
357 response: [
357 response: [
358 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
360 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
361
361
362 $ killdaemons.py
362 $ killdaemons.py
363
363
364 HTTP client follows HTTP redirect on handshake to new repo
364 HTTP client follows HTTP redirect on handshake to new repo
365
365
366 $ cd $TESTTMP
366 $ cd $TESTTMP
367
367
368 $ hg init redirector
368 $ hg init redirector
369 $ hg init redirected
369 $ hg init redirected
370 $ cd redirected
370 $ cd redirected
371 $ touch foo
371 $ touch foo
372 $ hg -q commit -A -m initial
372 $ hg -q commit -A -m initial
373 $ cd ..
373 $ cd ..
374
374
375 $ cat > paths.conf << EOF
375 $ cat > paths.conf << EOF
376 > [paths]
376 > [paths]
377 > / = $TESTTMP/*
377 > / = $TESTTMP/*
378 > EOF
378 > EOF
379
379
380 $ cat > redirectext.py << EOF
380 $ cat > redirectext.py << EOF
381 > from mercurial import extensions, wireprotoserver
381 > from mercurial import extensions, wireprotoserver
382 > def wrappedcallhttp(orig, repo, req, res, proto, cmd):
382 > def wrappedcallhttp(orig, repo, req, res, proto, cmd):
383 > path = req.advertisedurl[len(req.advertisedbaseurl):]
383 > path = req.advertisedurl[len(req.advertisedbaseurl):]
384 > if not path.startswith(b'/redirector'):
384 > if not path.startswith(b'/redirector'):
385 > return orig(repo, req, res, proto, cmd)
385 > return orig(repo, req, res, proto, cmd)
386 > relpath = path[len(b'/redirector'):]
386 > relpath = path[len(b'/redirector'):]
387 > res.status = b'301 Redirect'
387 > res.status = b'301 Redirect'
388 > newurl = b'%s/redirected%s' % (req.baseurl, relpath)
388 > newurl = b'%s/redirected%s' % (req.baseurl, relpath)
389 > if not repo.ui.configbool('testing', 'redirectqs', True) and b'?' in newurl:
389 > if not repo.ui.configbool('testing', 'redirectqs', True) and b'?' in newurl:
390 > newurl = newurl[0:newurl.index(b'?')]
390 > newurl = newurl[0:newurl.index(b'?')]
391 > res.headers[b'Location'] = newurl
391 > res.headers[b'Location'] = newurl
392 > res.headers[b'Content-Type'] = b'text/plain'
392 > res.headers[b'Content-Type'] = b'text/plain'
393 > res.setbodybytes(b'redirected')
393 > res.setbodybytes(b'redirected')
394 > return True
394 > return True
395 >
395 >
396 > extensions.wrapfunction(wireprotoserver, '_callhttp', wrappedcallhttp)
396 > extensions.wrapfunction(wireprotoserver, '_callhttp', wrappedcallhttp)
397 > EOF
397 > EOF
398
398
399 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
399 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
400 > --config server.compressionengines=zlib \
400 > --config server.compressionengines=zlib \
401 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
401 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
402 $ cat hg.pid > $DAEMON_PIDS
402 $ cat hg.pid > $DAEMON_PIDS
403
403
404 Verify our HTTP 301 is served properly
404 Verify our HTTP 301 is served properly
405
405
406 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
406 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
407 > httprequest GET /redirector?cmd=capabilities
407 > httprequest GET /redirector?cmd=capabilities
408 > user-agent: test
408 > user-agent: test
409 > EOF
409 > EOF
410 using raw connection to peer
410 using raw connection to peer
411 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
411 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
412 s> Accept-Encoding: identity\r\n
412 s> Accept-Encoding: identity\r\n
413 s> user-agent: test\r\n
413 s> user-agent: test\r\n
414 s> host: $LOCALIP:$HGPORT\r\n (glob)
414 s> host: $LOCALIP:$HGPORT\r\n (glob)
415 s> \r\n
415 s> \r\n
416 s> makefile('rb', None)
416 s> makefile('rb', None)
417 s> HTTP/1.1 301 Redirect\r\n
417 s> HTTP/1.1 301 Redirect\r\n
418 s> Server: testing stub value\r\n
418 s> Server: testing stub value\r\n
419 s> Date: $HTTP_DATE$\r\n
419 s> Date: $HTTP_DATE$\r\n
420 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
420 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
421 s> Content-Type: text/plain\r\n
421 s> Content-Type: text/plain\r\n
422 s> Content-Length: 10\r\n
422 s> Content-Length: 10\r\n
423 s> \r\n
423 s> \r\n
424 s> redirected
424 s> redirected
425 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
425 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
426 s> Accept-Encoding: identity\r\n
426 s> Accept-Encoding: identity\r\n
427 s> user-agent: test\r\n
427 s> user-agent: test\r\n
428 s> host: $LOCALIP:$HGPORT\r\n (glob)
428 s> host: $LOCALIP:$HGPORT\r\n (glob)
429 s> \r\n
429 s> \r\n
430 s> makefile('rb', None)
430 s> makefile('rb', None)
431 s> HTTP/1.1 200 Script output follows\r\n
431 s> HTTP/1.1 200 Script output follows\r\n
432 s> Server: testing stub value\r\n
432 s> Server: testing stub value\r\n
433 s> Date: $HTTP_DATE$\r\n
433 s> Date: $HTTP_DATE$\r\n
434 s> Content-Type: application/mercurial-0.1\r\n
434 s> Content-Type: application/mercurial-0.1\r\n
435 s> Content-Length: 467\r\n
435 s> Content-Length: 467\r\n
436 s> \r\n
436 s> \r\n
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
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 Test with the HTTP peer
439 Test with the HTTP peer
440
440
441 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
441 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
442 > command heads
442 > command heads
443 > EOF
443 > EOF
444 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
444 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
445 s> Accept-Encoding: identity\r\n
445 s> Accept-Encoding: identity\r\n
446 s> accept: application/mercurial-0.1\r\n
446 s> accept: application/mercurial-0.1\r\n
447 s> host: $LOCALIP:$HGPORT\r\n (glob)
447 s> host: $LOCALIP:$HGPORT\r\n (glob)
448 s> user-agent: Mercurial debugwireproto\r\n
448 s> user-agent: Mercurial debugwireproto\r\n
449 s> \r\n
449 s> \r\n
450 s> makefile('rb', None)
450 s> makefile('rb', None)
451 s> HTTP/1.1 301 Redirect\r\n
451 s> HTTP/1.1 301 Redirect\r\n
452 s> Server: testing stub value\r\n
452 s> Server: testing stub value\r\n
453 s> Date: $HTTP_DATE$\r\n
453 s> Date: $HTTP_DATE$\r\n
454 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
454 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
455 s> Content-Type: text/plain\r\n
455 s> Content-Type: text/plain\r\n
456 s> Content-Length: 10\r\n
456 s> Content-Length: 10\r\n
457 s> \r\n
457 s> \r\n
458 s> redirected
458 s> redirected
459 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
459 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
460 s> Accept-Encoding: identity\r\n
460 s> Accept-Encoding: identity\r\n
461 s> accept: application/mercurial-0.1\r\n
461 s> accept: application/mercurial-0.1\r\n
462 s> host: $LOCALIP:$HGPORT\r\n (glob)
462 s> host: $LOCALIP:$HGPORT\r\n (glob)
463 s> user-agent: Mercurial debugwireproto\r\n
463 s> user-agent: Mercurial debugwireproto\r\n
464 s> \r\n
464 s> \r\n
465 s> makefile('rb', None)
465 s> makefile('rb', None)
466 s> HTTP/1.1 200 Script output follows\r\n
466 s> HTTP/1.1 200 Script output follows\r\n
467 s> Server: testing stub value\r\n
467 s> Server: testing stub value\r\n
468 s> Date: $HTTP_DATE$\r\n
468 s> Date: $HTTP_DATE$\r\n
469 s> Content-Type: application/mercurial-0.1\r\n
469 s> Content-Type: application/mercurial-0.1\r\n
470 s> Content-Length: 467\r\n
470 s> Content-Length: 467\r\n
471 s> \r\n
471 s> \r\n
472 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
472 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
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
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 sending heads command
474 sending heads command
475 s> GET /redirected?cmd=heads HTTP/1.1\r\n
475 s> GET /redirected?cmd=heads HTTP/1.1\r\n
476 s> Accept-Encoding: identity\r\n
476 s> Accept-Encoding: identity\r\n
477 s> vary: X-HgProto-1\r\n
477 s> vary: X-HgProto-1\r\n
478 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
478 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
479 s> accept: application/mercurial-0.1\r\n
479 s> accept: application/mercurial-0.1\r\n
480 s> host: $LOCALIP:$HGPORT\r\n (glob)
480 s> host: $LOCALIP:$HGPORT\r\n (glob)
481 s> user-agent: Mercurial debugwireproto\r\n
481 s> user-agent: Mercurial debugwireproto\r\n
482 s> \r\n
482 s> \r\n
483 s> makefile('rb', None)
483 s> makefile('rb', None)
484 s> HTTP/1.1 200 Script output follows\r\n
484 s> HTTP/1.1 200 Script output follows\r\n
485 s> Server: testing stub value\r\n
485 s> Server: testing stub value\r\n
486 s> Date: $HTTP_DATE$\r\n
486 s> Date: $HTTP_DATE$\r\n
487 s> Content-Type: application/mercurial-0.1\r\n
487 s> Content-Type: application/mercurial-0.1\r\n
488 s> Content-Length: 41\r\n
488 s> Content-Length: 41\r\n
489 s> \r\n
489 s> \r\n
490 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
490 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
491 response: [
491 response: [
492 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
492 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
493 ]
493 ]
494 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
494 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
495
495
496 $ killdaemons.py
496 $ killdaemons.py
497
497
498 Now test a variation where we strip the query string from the redirect URL.
498 Now test a variation where we strip the query string from the redirect URL.
499 (SCM Manager apparently did this and clients would recover from it)
499 (SCM Manager apparently did this and clients would recover from it)
500
500
501 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
501 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
502 > --config server.compressionengines=zlib \
502 > --config server.compressionengines=zlib \
503 > --config testing.redirectqs=false \
503 > --config testing.redirectqs=false \
504 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
504 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
505 $ cat hg.pid > $DAEMON_PIDS
505 $ cat hg.pid > $DAEMON_PIDS
506
506
507 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
507 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
508 > httprequest GET /redirector?cmd=capabilities
508 > httprequest GET /redirector?cmd=capabilities
509 > user-agent: test
509 > user-agent: test
510 > EOF
510 > EOF
511 using raw connection to peer
511 using raw connection to peer
512 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
512 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
513 s> Accept-Encoding: identity\r\n
513 s> Accept-Encoding: identity\r\n
514 s> user-agent: test\r\n
514 s> user-agent: test\r\n
515 s> host: $LOCALIP:$HGPORT\r\n (glob)
515 s> host: $LOCALIP:$HGPORT\r\n (glob)
516 s> \r\n
516 s> \r\n
517 s> makefile('rb', None)
517 s> makefile('rb', None)
518 s> HTTP/1.1 301 Redirect\r\n
518 s> HTTP/1.1 301 Redirect\r\n
519 s> Server: testing stub value\r\n
519 s> Server: testing stub value\r\n
520 s> Date: $HTTP_DATE$\r\n
520 s> Date: $HTTP_DATE$\r\n
521 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
521 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
522 s> Content-Type: text/plain\r\n
522 s> Content-Type: text/plain\r\n
523 s> Content-Length: 10\r\n
523 s> Content-Length: 10\r\n
524 s> \r\n
524 s> \r\n
525 s> redirected
525 s> redirected
526 s> GET /redirected HTTP/1.1\r\n
526 s> GET /redirected HTTP/1.1\r\n
527 s> Accept-Encoding: identity\r\n
527 s> Accept-Encoding: identity\r\n
528 s> user-agent: test\r\n
528 s> user-agent: test\r\n
529 s> host: $LOCALIP:$HGPORT\r\n (glob)
529 s> host: $LOCALIP:$HGPORT\r\n (glob)
530 s> \r\n
530 s> \r\n
531 s> makefile('rb', None)
531 s> makefile('rb', None)
532 s> HTTP/1.1 200 Script output follows\r\n
532 s> HTTP/1.1 200 Script output follows\r\n
533 s> Server: testing stub value\r\n
533 s> Server: testing stub value\r\n
534 s> Date: $HTTP_DATE$\r\n
534 s> Date: $HTTP_DATE$\r\n
535 s> ETag: W/"*"\r\n (glob)
535 s> ETag: W/"*"\r\n (glob)
536 s> Content-Type: text/html; charset=ascii\r\n
536 s> Content-Type: text/html; charset=ascii\r\n
537 s> Transfer-Encoding: chunked\r\n
537 s> Transfer-Encoding: chunked\r\n
538 s> \r\n
538 s> \r\n
539 s> 414\r\n
539 s> 414\r\n
540 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
540 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
541 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
541 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
542 s> <head>\n
542 s> <head>\n
543 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
543 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
544 s> <meta name="robots" content="index, nofollow" />\n
544 s> <meta name="robots" content="index, nofollow" />\n
545 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
545 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
546 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
546 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
547 s> \n
547 s> \n
548 s> <title>redirected: log</title>\n
548 s> <title>redirected: log</title>\n
549 s> <link rel="alternate" type="application/atom+xml"\n
549 s> <link rel="alternate" type="application/atom+xml"\n
550 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
550 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
551 s> <link rel="alternate" type="application/rss+xml"\n
551 s> <link rel="alternate" type="application/rss+xml"\n
552 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
552 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
553 s> </head>\n
553 s> </head>\n
554 s> <body>\n
554 s> <body>\n
555 s> \n
555 s> \n
556 s> <div class="container">\n
556 s> <div class="container">\n
557 s> <div class="menu">\n
557 s> <div class="menu">\n
558 s> <div class="logo">\n
558 s> <div class="logo">\n
559 s> <a href="https://mercurial-scm.org/">\n
559 s> <a href="https://mercurial-scm.org/">\n
560 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
560 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
561 s> </div>\n
561 s> </div>\n
562 s> <ul>\n
562 s> <ul>\n
563 s> <li class="active">log</li>\n
563 s> <li class="active">log</li>\n
564 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
564 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
565 s> <li><a href="/redirected/tags">tags</a></li>\n
565 s> <li><a href="/redirected/tags">tags</a></li>\n
566 s> <li><a href="
566 s> <li><a href="
567 s> \r\n
567 s> \r\n
568 s> 810\r\n
568 s> 810\r\n
569 s> /redirected/bookmarks">bookmarks</a></li>\n
569 s> /redirected/bookmarks">bookmarks</a></li>\n
570 s> <li><a href="/redirected/branches">branches</a></li>\n
570 s> <li><a href="/redirected/branches">branches</a></li>\n
571 s> </ul>\n
571 s> </ul>\n
572 s> <ul>\n
572 s> <ul>\n
573 s> <li><a href="/redirected/rev/tip">changeset</a></li>\n
573 s> <li><a href="/redirected/rev/tip">changeset</a></li>\n
574 s> <li><a href="/redirected/file/tip">browse</a></li>\n
574 s> <li><a href="/redirected/file/tip">browse</a></li>\n
575 s> </ul>\n
575 s> </ul>\n
576 s> <ul>\n
576 s> <ul>\n
577 s> \n
577 s> \n
578 s> </ul>\n
578 s> </ul>\n
579 s> <ul>\n
579 s> <ul>\n
580 s> <li><a href="/redirected/help">help</a></li>\n
580 s> <li><a href="/redirected/help">help</a></li>\n
581 s> </ul>\n
581 s> </ul>\n
582 s> <div class="atom-logo">\n
582 s> <div class="atom-logo">\n
583 s> <a href="/redirected/atom-log" title="subscribe to atom feed">\n
583 s> <a href="/redirected/atom-log" title="subscribe to atom feed">\n
584 s> <img class="atom-logo" src="/redirected/static/feed-icon-14x14.png" alt="atom feed" />\n
584 s> <img class="atom-logo" src="/redirected/static/feed-icon-14x14.png" alt="atom feed" />\n
585 s> </a>\n
585 s> </a>\n
586 s> </div>\n
586 s> </div>\n
587 s> </div>\n
587 s> </div>\n
588 s> \n
588 s> \n
589 s> <div class="main">\n
589 s> <div class="main">\n
590 s> <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/redirected">redirected</a> </h2>\n
590 s> <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/redirected">redirected</a> </h2>\n
591 s> <h3>log</h3>\n
591 s> <h3>log</h3>\n
592 s> \n
592 s> \n
593 s> \n
593 s> \n
594 s> <form class="search" action="/redirected/log">\n
594 s> <form class="search" action="/redirected/log">\n
595 s> \n
595 s> \n
596 s> <p><input name="rev" id="search1" type="text" size="30" value="" /></p>\n
596 s> <p><input name="rev" id="search1" type="text" size="30" value="" /></p>\n
597 s> <div id="hint">Find changesets by keywords (author, files, the commit message), revision\n
597 s> <div id="hint">Find changesets by keywords (author, files, the commit message), revision\n
598 s> number or hash, or <a href="/redirected/help/revsets">revset expression</a>.</div>\n
598 s> number or hash, or <a href="/redirected/help/revsets">revset expression</a>.</div>\n
599 s> </form>\n
599 s> </form>\n
600 s> \n
600 s> \n
601 s> <div class="navigate">\n
601 s> <div class="navigate">\n
602 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
602 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
603 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
603 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
604 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
604 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
605 s> </div>\n
605 s> </div>\n
606 s> \n
606 s> \n
607 s> <table class="bigtable">\n
607 s> <table class="bigtable">\n
608 s> <thead>\n
608 s> <thead>\n
609 s> <tr>\n
609 s> <tr>\n
610 s> <th class="age">age</th>\n
610 s> <th class="age">age</th>\n
611 s> <th class="author">author</th>\n
611 s> <th class="author">author</th>\n
612 s> <th class="description">description</th>\n
612 s> <th class="description">description</th>\n
613 s> </tr>\n
613 s> </tr>\n
614 s> </thead>\n
614 s> </thead>\n
615 s> <tbody class="stripes2">\n
615 s> <tbody class="stripes2">\n
616 s> <tr>\n
616 s> <tr>\n
617 s> <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>\n
617 s> <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>\n
618 s> <td class="author">test</td>\n
618 s> <td class="author">test</td>\n
619 s> <td class="description">\n
619 s> <td class="description">\n
620 s> <a href="/redirected/rev/96ee1d7354c4">initial</a>\n
620 s> <a href="/redirected/rev/96ee1d7354c4">initial</a>\n
621 s> <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span> \n
621 s> <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span> \n
622 s> </td>\n
622 s> </td>\n
623 s> </tr>\n
623 s> </tr>\n
624 s> \n
624 s> \n
625 s> </tbody>\n
625 s> </tbody>\n
626 s> </table>\n
626 s> </table>\n
627 s> \n
627 s> \n
628 s> <div class="navigate">\n
628 s> <div class="navigate">\n
629 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
629 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
630 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
630 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
631 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
631 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
632 s> </div>\n
632 s> </div>\n
633 s> \n
633 s> \n
634 s> <script type="text/javascript">\n
634 s> <script type="text/javascript">\n
635 s> ajaxScrollInit(\n
635 s> ajaxScrollInit(\n
636 s> \'/redirected/shortlog/%next%\',\n
636 s> \'/redirected/shortlog/%next%\',\n
637 s> \'\', <!-- NEXTHASH\n
637 s> \'\', <!-- NEXTHASH\n
638 s> function (htmlText) {
638 s> function (htmlText) {
639 s> \r\n
639 s> \r\n
640 s> 14a\r\n
640 s> 14a\r\n
641 s> \n
641 s> \n
642 s> var m = htmlText.match(/\'(\\w+)\', <!-- NEXTHASH/);\n
642 s> var m = htmlText.match(/\'(\\w+)\', <!-- NEXTHASH/);\n
643 s> return m ? m[1] : null;\n
643 s> return m ? m[1] : null;\n
644 s> },\n
644 s> },\n
645 s> \'.bigtable > tbody\',\n
645 s> \'.bigtable > tbody\',\n
646 s> \'<tr class="%class%">\\\n
646 s> \'<tr class="%class%">\\\n
647 s> <td colspan="3" style="text-align: center;">%text%</td>\\\n
647 s> <td colspan="3" style="text-align: center;">%text%</td>\\\n
648 s> </tr>\'\n
648 s> </tr>\'\n
649 s> );\n
649 s> );\n
650 s> </script>\n
650 s> </script>\n
651 s> \n
651 s> \n
652 s> </div>\n
652 s> </div>\n
653 s> </div>\n
653 s> </div>\n
654 s> \n
654 s> \n
655 s> \n
655 s> \n
656 s> \n
656 s> \n
657 s> </body>\n
657 s> </body>\n
658 s> </html>\n
658 s> </html>\n
659 s> \n
659 s> \n
660 s> \r\n
660 s> \r\n
661 s> 0\r\n
661 s> 0\r\n
662 s> \r\n
662 s> \r\n
663
663
664 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
664 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
665 > command heads
665 > command heads
666 > EOF
666 > EOF
667 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
667 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
668 s> Accept-Encoding: identity\r\n
668 s> Accept-Encoding: identity\r\n
669 s> accept: application/mercurial-0.1\r\n
669 s> accept: application/mercurial-0.1\r\n
670 s> host: $LOCALIP:$HGPORT\r\n (glob)
670 s> host: $LOCALIP:$HGPORT\r\n (glob)
671 s> user-agent: Mercurial debugwireproto\r\n
671 s> user-agent: Mercurial debugwireproto\r\n
672 s> \r\n
672 s> \r\n
673 s> makefile('rb', None)
673 s> makefile('rb', None)
674 s> HTTP/1.1 301 Redirect\r\n
674 s> HTTP/1.1 301 Redirect\r\n
675 s> Server: testing stub value\r\n
675 s> Server: testing stub value\r\n
676 s> Date: $HTTP_DATE$\r\n
676 s> Date: $HTTP_DATE$\r\n
677 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
677 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
678 s> Content-Type: text/plain\r\n
678 s> Content-Type: text/plain\r\n
679 s> Content-Length: 10\r\n
679 s> Content-Length: 10\r\n
680 s> \r\n
680 s> \r\n
681 s> redirected
681 s> redirected
682 s> GET /redirected HTTP/1.1\r\n
682 s> GET /redirected HTTP/1.1\r\n
683 s> Accept-Encoding: identity\r\n
683 s> Accept-Encoding: identity\r\n
684 s> accept: application/mercurial-0.1\r\n
684 s> accept: application/mercurial-0.1\r\n
685 s> host: $LOCALIP:$HGPORT\r\n (glob)
685 s> host: $LOCALIP:$HGPORT\r\n (glob)
686 s> user-agent: Mercurial debugwireproto\r\n
686 s> user-agent: Mercurial debugwireproto\r\n
687 s> \r\n
687 s> \r\n
688 s> makefile('rb', None)
688 s> makefile('rb', None)
689 s> HTTP/1.1 200 Script output follows\r\n
689 s> HTTP/1.1 200 Script output follows\r\n
690 s> Server: testing stub value\r\n
690 s> Server: testing stub value\r\n
691 s> Date: $HTTP_DATE$\r\n
691 s> Date: $HTTP_DATE$\r\n
692 s> ETag: W/"*"\r\n (glob)
692 s> ETag: W/"*"\r\n (glob)
693 s> Content-Type: text/html; charset=ascii\r\n
693 s> Content-Type: text/html; charset=ascii\r\n
694 s> Transfer-Encoding: chunked\r\n
694 s> Transfer-Encoding: chunked\r\n
695 s> \r\n
695 s> \r\n
696 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
696 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
697 s> 414\r\n
697 s> 414\r\n
698 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
698 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
699 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
699 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
700 s> <head>\n
700 s> <head>\n
701 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
701 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
702 s> <meta name="robots" content="index, nofollow" />\n
702 s> <meta name="robots" content="index, nofollow" />\n
703 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
703 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
704 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
704 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
705 s> \n
705 s> \n
706 s> <title>redirected: log</title>\n
706 s> <title>redirected: log</title>\n
707 s> <link rel="alternate" type="application/atom+xml"\n
707 s> <link rel="alternate" type="application/atom+xml"\n
708 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
708 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
709 s> <link rel="alternate" type="application/rss+xml"\n
709 s> <link rel="alternate" type="application/rss+xml"\n
710 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
710 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
711 s> </head>\n
711 s> </head>\n
712 s> <body>\n
712 s> <body>\n
713 s> \n
713 s> \n
714 s> <div class="container">\n
714 s> <div class="container">\n
715 s> <div class="menu">\n
715 s> <div class="menu">\n
716 s> <div class="logo">\n
716 s> <div class="logo">\n
717 s> <a href="https://mercurial-scm.org/">\n
717 s> <a href="https://mercurial-scm.org/">\n
718 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
718 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
719 s> </div>\n
719 s> </div>\n
720 s> <ul>\n
720 s> <ul>\n
721 s> <li class="active">log</li>\n
721 s> <li class="active">log</li>\n
722 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
722 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
723 s> <li><a href="/redirected/tags">tags</a
723 s> <li><a href="/redirected/tags">tags</a
724 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
724 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
725 s> Accept-Encoding: identity\r\n
725 s> Accept-Encoding: identity\r\n
726 s> accept: application/mercurial-0.1\r\n
726 s> accept: application/mercurial-0.1\r\n
727 s> host: $LOCALIP:$HGPORT\r\n (glob)
727 s> host: $LOCALIP:$HGPORT\r\n (glob)
728 s> user-agent: Mercurial debugwireproto\r\n
728 s> user-agent: Mercurial debugwireproto\r\n
729 s> \r\n
729 s> \r\n
730 s> makefile('rb', None)
730 s> makefile('rb', None)
731 s> HTTP/1.1 200 Script output follows\r\n
731 s> HTTP/1.1 200 Script output follows\r\n
732 s> Server: testing stub value\r\n
732 s> Server: testing stub value\r\n
733 s> Date: $HTTP_DATE$\r\n
733 s> Date: $HTTP_DATE$\r\n
734 s> Content-Type: application/mercurial-0.1\r\n
734 s> Content-Type: application/mercurial-0.1\r\n
735 s> Content-Length: 467\r\n
735 s> Content-Length: 467\r\n
736 s> \r\n
736 s> \r\n
737 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
737 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
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
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 sending heads command
739 sending heads command
740 s> GET /redirected?cmd=heads HTTP/1.1\r\n
740 s> GET /redirected?cmd=heads HTTP/1.1\r\n
741 s> Accept-Encoding: identity\r\n
741 s> Accept-Encoding: identity\r\n
742 s> vary: X-HgProto-1\r\n
742 s> vary: X-HgProto-1\r\n
743 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
743 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
744 s> accept: application/mercurial-0.1\r\n
744 s> accept: application/mercurial-0.1\r\n
745 s> host: $LOCALIP:$HGPORT\r\n (glob)
745 s> host: $LOCALIP:$HGPORT\r\n (glob)
746 s> user-agent: Mercurial debugwireproto\r\n
746 s> user-agent: Mercurial debugwireproto\r\n
747 s> \r\n
747 s> \r\n
748 s> makefile('rb', None)
748 s> makefile('rb', None)
749 s> HTTP/1.1 200 Script output follows\r\n
749 s> HTTP/1.1 200 Script output follows\r\n
750 s> Server: testing stub value\r\n
750 s> Server: testing stub value\r\n
751 s> Date: $HTTP_DATE$\r\n
751 s> Date: $HTTP_DATE$\r\n
752 s> Content-Type: application/mercurial-0.1\r\n
752 s> Content-Type: application/mercurial-0.1\r\n
753 s> Content-Length: 41\r\n
753 s> Content-Length: 41\r\n
754 s> \r\n
754 s> \r\n
755 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
755 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
756 response: [
756 response: [
757 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
757 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
758 ]
758 ]
759 (sent 4 HTTP requests and * bytes; received * bytes in responses) (glob)
759 (sent 4 HTTP requests and * bytes; received * bytes in responses) (glob)
@@ -1,460 +1,462 b''
1 $ . $TESTDIR/wireprotohelpers.sh
1 $ . $TESTDIR/wireprotohelpers.sh
2 $ cat >> $HGRCPATH << EOF
2 $ cat >> $HGRCPATH << EOF
3 > [extensions]
3 > [extensions]
4 > blackbox =
4 > blackbox =
5 > [blackbox]
5 > [blackbox]
6 > track = simplecache
6 > track = simplecache
7 > EOF
7 > EOF
8 $ hg init server
8 $ hg init server
9 $ enablehttpv2 server
9 $ enablehttpv2 server
10 $ cd server
10 $ cd server
11 $ cat >> .hg/hgrc << EOF
11 $ cat >> .hg/hgrc << EOF
12 > [extensions]
12 > [extensions]
13 > simplecache = $TESTDIR/wireprotosimplecache.py
13 > simplecache = $TESTDIR/wireprotosimplecache.py
14 > EOF
14 > EOF
15
15
16 $ echo a0 > a
16 $ echo a0 > a
17 $ echo b0 > b
17 $ echo b0 > b
18 $ hg -q commit -A -m 'commit 0'
18 $ hg -q commit -A -m 'commit 0'
19 $ echo a1 > a
19 $ echo a1 > a
20 $ hg commit -m 'commit 1'
20 $ hg commit -m 'commit 1'
21 $ echo b1 > b
21 $ echo b1 > b
22 $ hg commit -m 'commit 2'
22 $ hg commit -m 'commit 2'
23 $ echo a2 > a
23 $ echo a2 > a
24 $ echo b2 > b
24 $ echo b2 > b
25 $ hg commit -m 'commit 3'
25 $ hg commit -m 'commit 3'
26
26
27 $ hg log -G -T '{rev}:{node} {desc}'
27 $ hg log -G -T '{rev}:{node} {desc}'
28 @ 3:50590a86f3ff5d1e9a1624a7a6957884565cc8e8 commit 3
28 @ 3:50590a86f3ff5d1e9a1624a7a6957884565cc8e8 commit 3
29 |
29 |
30 o 2:4d01eda50c6ac5f7e89cbe1880143a32f559c302 commit 2
30 o 2:4d01eda50c6ac5f7e89cbe1880143a32f559c302 commit 2
31 |
31 |
32 o 1:4432d83626e8a98655f062ec1f2a43b07f7fbbb0 commit 1
32 o 1:4432d83626e8a98655f062ec1f2a43b07f7fbbb0 commit 1
33 |
33 |
34 o 0:3390ef850073fbc2f0dfff2244342c8e9229013a commit 0
34 o 0:3390ef850073fbc2f0dfff2244342c8e9229013a commit 0
35
35
36
36
37 $ hg --debug debugindex -m
37 $ hg --debug debugindex -m
38 rev linkrev nodeid p1 p2
38 rev linkrev nodeid p1 p2
39 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
39 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
40 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
40 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
41 2 2 a8853dafacfca6fc807055a660d8b835141a3bb4 a988fb43583e871d1ed5750ee074c6d840bbbfc8 0000000000000000000000000000000000000000
41 2 2 a8853dafacfca6fc807055a660d8b835141a3bb4 a988fb43583e871d1ed5750ee074c6d840bbbfc8 0000000000000000000000000000000000000000
42 3 3 3fe11dfbb13645782b0addafbe75a87c210ffddc a8853dafacfca6fc807055a660d8b835141a3bb4 0000000000000000000000000000000000000000
42 3 3 3fe11dfbb13645782b0addafbe75a87c210ffddc a8853dafacfca6fc807055a660d8b835141a3bb4 0000000000000000000000000000000000000000
43
43
44 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
44 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
45 $ cat hg.pid > $DAEMON_PIDS
45 $ cat hg.pid > $DAEMON_PIDS
46
46
47 Performing the same request should result in same result, with 2nd response
47 Performing the same request should result in same result, with 2nd response
48 coming from cache.
48 coming from cache.
49
49
50 $ sendhttpv2peer << EOF
50 $ sendhttpv2peer << EOF
51 > command manifestdata
51 > command manifestdata
52 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
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 > tree eval:b''
53 > tree eval:b''
54 > fields eval:[b'parents']
54 > fields eval:[b'parents']
55 > EOF
55 > EOF
56 creating http peer for wire protocol version 2
56 creating http peer for wire protocol version 2
57 sending manifestdata command
57 sending manifestdata command
58 response: gen[
58 response: gen[
59 {
59 {
60 b'totalitems': 1
60 b'totalitems': 1
61 },
61 },
62 {
62 {
63 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
63 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
64 b'parents': [
64 b'parents': [
65 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
65 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
66 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 $ sendhttpv2peer << EOF
71 $ sendhttpv2peer << EOF
72 > command manifestdata
72 > command manifestdata
73 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
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 > tree eval:b''
74 > tree eval:b''
75 > fields eval:[b'parents']
75 > fields eval:[b'parents']
76 > EOF
76 > EOF
77 creating http peer for wire protocol version 2
77 creating http peer for wire protocol version 2
78 sending manifestdata command
78 sending manifestdata command
79 response: gen[
79 response: gen[
80 {
80 {
81 b'totalitems': 1
81 b'totalitems': 1
82 },
82 },
83 {
83 {
84 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
84 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
85 b'parents': [
85 b'parents': [
86 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
86 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
87 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 Sending different request doesn't yield cache hit.
92 Sending different request doesn't yield cache hit.
93
93
94 $ sendhttpv2peer << EOF
94 $ sendhttpv2peer << EOF
95 > command manifestdata
95 > command manifestdata
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']
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 > tree eval:b''
97 > tree eval:b''
98 > fields eval:[b'parents']
98 > fields eval:[b'parents']
99 > EOF
99 > EOF
100 creating http peer for wire protocol version 2
100 creating http peer for wire protocol version 2
101 sending manifestdata command
101 sending manifestdata command
102 response: gen[
102 response: gen[
103 {
103 {
104 b'totalitems': 2
104 b'totalitems': 2
105 },
105 },
106 {
106 {
107 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
107 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
108 b'parents': [
108 b'parents': [
109 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
109 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
110 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 b'node': b'\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8',
114 b'node': b'\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8',
115 b'parents': [
115 b'parents': [
116 b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
116 b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
117 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 $ cat .hg/blackbox.log
122 $ cat .hg/blackbox.log
123 *> cacher constructed for manifestdata (glob)
123 *> cacher constructed for manifestdata (glob)
124 *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
124 *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
125 *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
125 *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
126 *> cacher constructed for manifestdata (glob)
126 *> cacher constructed for manifestdata (glob)
127 *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
127 *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
128 *> cacher constructed for manifestdata (glob)
128 *> cacher constructed for manifestdata (glob)
129 *> cache miss for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob)
129 *> cache miss for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob)
130 *> storing cache entry for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob)
130 *> storing cache entry for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob)
131
131
132 $ cat error.log
132 $ cat error.log
133
133
134 $ killdaemons.py
134 $ killdaemons.py
135 $ rm .hg/blackbox.log
135 $ rm .hg/blackbox.log
136
136
137 Try with object caching mode
137 Try with object caching mode
138
138
139 $ cat >> .hg/hgrc << EOF
139 $ cat >> .hg/hgrc << EOF
140 > [simplecache]
140 > [simplecache]
141 > cacheobjects = true
141 > cacheobjects = true
142 > EOF
142 > EOF
143
143
144 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
144 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
145 $ cat hg.pid > $DAEMON_PIDS
145 $ cat hg.pid > $DAEMON_PIDS
146
146
147 $ sendhttpv2peer << EOF
147 $ sendhttpv2peer << EOF
148 > command manifestdata
148 > command manifestdata
149 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
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 > tree eval:b''
150 > tree eval:b''
151 > fields eval:[b'parents']
151 > fields eval:[b'parents']
152 > EOF
152 > EOF
153 creating http peer for wire protocol version 2
153 creating http peer for wire protocol version 2
154 sending manifestdata command
154 sending manifestdata command
155 response: gen[
155 response: gen[
156 {
156 {
157 b'totalitems': 1
157 b'totalitems': 1
158 },
158 },
159 {
159 {
160 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
160 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
161 b'parents': [
161 b'parents': [
162 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
162 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
163 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 $ sendhttpv2peer << EOF
168 $ sendhttpv2peer << EOF
169 > command manifestdata
169 > command manifestdata
170 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
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 > tree eval:b''
171 > tree eval:b''
172 > fields eval:[b'parents']
172 > fields eval:[b'parents']
173 > EOF
173 > EOF
174 creating http peer for wire protocol version 2
174 creating http peer for wire protocol version 2
175 sending manifestdata command
175 sending manifestdata command
176 response: gen[
176 response: gen[
177 {
177 {
178 b'totalitems': 1
178 b'totalitems': 1
179 },
179 },
180 {
180 {
181 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
181 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
182 b'parents': [
182 b'parents': [
183 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
183 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
184 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 $ cat .hg/blackbox.log
189 $ cat .hg/blackbox.log
190 *> cacher constructed for manifestdata (glob)
190 *> cacher constructed for manifestdata (glob)
191 *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
191 *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
192 *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
192 *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
193 *> cacher constructed for manifestdata (glob)
193 *> cacher constructed for manifestdata (glob)
194 *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
194 *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
195
195
196 $ cat error.log
196 $ cat error.log
197
197
198 $ killdaemons.py
198 $ killdaemons.py
199 $ rm .hg/blackbox.log
199 $ rm .hg/blackbox.log
200
200
201 A non-cacheable command does not instantiate cacher
201 A non-cacheable command does not instantiate cacher
202
202
203 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
203 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
204 $ cat hg.pid > $DAEMON_PIDS
204 $ cat hg.pid > $DAEMON_PIDS
205 $ sendhttpv2peer << EOF
205 $ sendhttpv2peer << EOF
206 > command capabilities
206 > command capabilities
207 > EOF
207 > EOF
208 creating http peer for wire protocol version 2
208 creating http peer for wire protocol version 2
209 sending capabilities command
209 sending capabilities command
210 response: gen[
210 response: gen[
211 {
211 {
212 b'commands': {
212 b'commands': {
213 b'branchmap': {
213 b'branchmap': {
214 b'args': {},
214 b'args': {},
215 b'permissions': [
215 b'permissions': [
216 b'pull'
216 b'pull'
217 ]
217 ]
218 },
218 },
219 b'capabilities': {
219 b'capabilities': {
220 b'args': {},
220 b'args': {},
221 b'permissions': [
221 b'permissions': [
222 b'pull'
222 b'pull'
223 ]
223 ]
224 },
224 },
225 b'changesetdata': {
225 b'changesetdata': {
226 b'args': {
226 b'args': {
227 b'fields': {
227 b'fields': {
228 b'default': set([]),
228 b'default': set([]),
229 b'required': False,
229 b'required': False,
230 b'type': b'set',
230 b'type': b'set',
231 b'validvalues': set([
231 b'validvalues': set([
232 b'bookmarks',
232 b'bookmarks',
233 b'parents',
233 b'parents',
234 b'phase',
234 b'phase',
235 b'revision'
235 b'revision'
236 ])
236 ])
237 },
237 },
238 b'revisions': {
238 b'revisions': {
239 b'required': True,
239 b'required': True,
240 b'type': b'list'
240 b'type': b'list'
241 }
241 }
242 },
242 },
243 b'permissions': [
243 b'permissions': [
244 b'pull'
244 b'pull'
245 ]
245 ]
246 },
246 },
247 b'filedata': {
247 b'filedata': {
248 b'args': {
248 b'args': {
249 b'fields': {
249 b'fields': {
250 b'default': set([]),
250 b'default': set([]),
251 b'required': False,
251 b'required': False,
252 b'type': b'set',
252 b'type': b'set',
253 b'validvalues': set([
253 b'validvalues': set([
254 b'linknode',
254 b'parents',
255 b'parents',
255 b'revision'
256 b'revision'
256 ])
257 ])
257 },
258 },
258 b'haveparents': {
259 b'haveparents': {
259 b'default': False,
260 b'default': False,
260 b'required': False,
261 b'required': False,
261 b'type': b'bool'
262 b'type': b'bool'
262 },
263 },
263 b'nodes': {
264 b'nodes': {
264 b'required': True,
265 b'required': True,
265 b'type': b'list'
266 b'type': b'list'
266 },
267 },
267 b'path': {
268 b'path': {
268 b'required': True,
269 b'required': True,
269 b'type': b'bytes'
270 b'type': b'bytes'
270 }
271 }
271 },
272 },
272 b'permissions': [
273 b'permissions': [
273 b'pull'
274 b'pull'
274 ]
275 ]
275 },
276 },
276 b'filesdata': {
277 b'filesdata': {
277 b'args': {
278 b'args': {
278 b'fields': {
279 b'fields': {
279 b'default': set([]),
280 b'default': set([]),
280 b'required': False,
281 b'required': False,
281 b'type': b'set',
282 b'type': b'set',
282 b'validvalues': set([
283 b'validvalues': set([
283 b'firstchangeset',
284 b'firstchangeset',
285 b'linknode',
284 b'parents',
286 b'parents',
285 b'revision'
287 b'revision'
286 ])
288 ])
287 },
289 },
288 b'haveparents': {
290 b'haveparents': {
289 b'default': False,
291 b'default': False,
290 b'required': False,
292 b'required': False,
291 b'type': b'bool'
293 b'type': b'bool'
292 },
294 },
293 b'pathfilter': {
295 b'pathfilter': {
294 b'default': None,
296 b'default': None,
295 b'required': False,
297 b'required': False,
296 b'type': b'dict'
298 b'type': b'dict'
297 },
299 },
298 b'revisions': {
300 b'revisions': {
299 b'required': True,
301 b'required': True,
300 b'type': b'list'
302 b'type': b'list'
301 }
303 }
302 },
304 },
303 b'permissions': [
305 b'permissions': [
304 b'pull'
306 b'pull'
305 ],
307 ],
306 b'recommendedbatchsize': 50000
308 b'recommendedbatchsize': 50000
307 },
309 },
308 b'heads': {
310 b'heads': {
309 b'args': {
311 b'args': {
310 b'publiconly': {
312 b'publiconly': {
311 b'default': False,
313 b'default': False,
312 b'required': False,
314 b'required': False,
313 b'type': b'bool'
315 b'type': b'bool'
314 }
316 }
315 },
317 },
316 b'permissions': [
318 b'permissions': [
317 b'pull'
319 b'pull'
318 ]
320 ]
319 },
321 },
320 b'known': {
322 b'known': {
321 b'args': {
323 b'args': {
322 b'nodes': {
324 b'nodes': {
323 b'default': [],
325 b'default': [],
324 b'required': False,
326 b'required': False,
325 b'type': b'list'
327 b'type': b'list'
326 }
328 }
327 },
329 },
328 b'permissions': [
330 b'permissions': [
329 b'pull'
331 b'pull'
330 ]
332 ]
331 },
333 },
332 b'listkeys': {
334 b'listkeys': {
333 b'args': {
335 b'args': {
334 b'namespace': {
336 b'namespace': {
335 b'required': True,
337 b'required': True,
336 b'type': b'bytes'
338 b'type': b'bytes'
337 }
339 }
338 },
340 },
339 b'permissions': [
341 b'permissions': [
340 b'pull'
342 b'pull'
341 ]
343 ]
342 },
344 },
343 b'lookup': {
345 b'lookup': {
344 b'args': {
346 b'args': {
345 b'key': {
347 b'key': {
346 b'required': True,
348 b'required': True,
347 b'type': b'bytes'
349 b'type': b'bytes'
348 }
350 }
349 },
351 },
350 b'permissions': [
352 b'permissions': [
351 b'pull'
353 b'pull'
352 ]
354 ]
353 },
355 },
354 b'manifestdata': {
356 b'manifestdata': {
355 b'args': {
357 b'args': {
356 b'fields': {
358 b'fields': {
357 b'default': set([]),
359 b'default': set([]),
358 b'required': False,
360 b'required': False,
359 b'type': b'set',
361 b'type': b'set',
360 b'validvalues': set([
362 b'validvalues': set([
361 b'parents',
363 b'parents',
362 b'revision'
364 b'revision'
363 ])
365 ])
364 },
366 },
365 b'haveparents': {
367 b'haveparents': {
366 b'default': False,
368 b'default': False,
367 b'required': False,
369 b'required': False,
368 b'type': b'bool'
370 b'type': b'bool'
369 },
371 },
370 b'nodes': {
372 b'nodes': {
371 b'required': True,
373 b'required': True,
372 b'type': b'list'
374 b'type': b'list'
373 },
375 },
374 b'tree': {
376 b'tree': {
375 b'required': True,
377 b'required': True,
376 b'type': b'bytes'
378 b'type': b'bytes'
377 }
379 }
378 },
380 },
379 b'permissions': [
381 b'permissions': [
380 b'pull'
382 b'pull'
381 ],
383 ],
382 b'recommendedbatchsize': 100000
384 b'recommendedbatchsize': 100000
383 },
385 },
384 b'pushkey': {
386 b'pushkey': {
385 b'args': {
387 b'args': {
386 b'key': {
388 b'key': {
387 b'required': True,
389 b'required': True,
388 b'type': b'bytes'
390 b'type': b'bytes'
389 },
391 },
390 b'namespace': {
392 b'namespace': {
391 b'required': True,
393 b'required': True,
392 b'type': b'bytes'
394 b'type': b'bytes'
393 },
395 },
394 b'new': {
396 b'new': {
395 b'required': True,
397 b'required': True,
396 b'type': b'bytes'
398 b'type': b'bytes'
397 },
399 },
398 b'old': {
400 b'old': {
399 b'required': True,
401 b'required': True,
400 b'type': b'bytes'
402 b'type': b'bytes'
401 }
403 }
402 },
404 },
403 b'permissions': [
405 b'permissions': [
404 b'push'
406 b'push'
405 ]
407 ]
406 },
408 },
407 b'rawstorefiledata': {
409 b'rawstorefiledata': {
408 b'args': {
410 b'args': {
409 b'files': {
411 b'files': {
410 b'required': True,
412 b'required': True,
411 b'type': b'list'
413 b'type': b'list'
412 },
414 },
413 b'pathfilter': {
415 b'pathfilter': {
414 b'default': None,
416 b'default': None,
415 b'required': False,
417 b'required': False,
416 b'type': b'list'
418 b'type': b'list'
417 }
419 }
418 },
420 },
419 b'permissions': [
421 b'permissions': [
420 b'pull'
422 b'pull'
421 ]
423 ]
422 }
424 }
423 },
425 },
424 b'framingmediatypes': [
426 b'framingmediatypes': [
425 b'application/mercurial-exp-framing-0006'
427 b'application/mercurial-exp-framing-0006'
426 ],
428 ],
427 b'pathfilterprefixes': set([
429 b'pathfilterprefixes': set([
428 b'path:',
430 b'path:',
429 b'rootfilesin:'
431 b'rootfilesin:'
430 ]),
432 ]),
431 b'rawrepoformats': [
433 b'rawrepoformats': [
432 b'generaldelta',
434 b'generaldelta',
433 b'revlogv1'
435 b'revlogv1'
434 ]
436 ]
435 }
437 }
436 ]
438 ]
437
439
438 $ test -f .hg/blackbox.log
440 $ test -f .hg/blackbox.log
439 [1]
441 [1]
440
442
441 An error is not cached
443 An error is not cached
442
444
443 $ sendhttpv2peer << EOF
445 $ sendhttpv2peer << EOF
444 > command manifestdata
446 > command manifestdata
445 > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
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 > tree eval:b''
448 > tree eval:b''
447 > fields eval:[b'parents']
449 > fields eval:[b'parents']
448 > EOF
450 > EOF
449 creating http peer for wire protocol version 2
451 creating http peer for wire protocol version 2
450 sending manifestdata command
452 sending manifestdata command
451 abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa! (esc)
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 [255]
454 [255]
453
455
454 $ cat .hg/blackbox.log
456 $ cat .hg/blackbox.log
455 *> cacher constructed for manifestdata (glob)
457 *> cacher constructed for manifestdata (glob)
456 *> cache miss for 2cba2a7d0d1575fea2fe68f597e97a7c2ac2f705 (glob)
458 *> cache miss for 2cba2a7d0d1575fea2fe68f597e97a7c2ac2f705 (glob)
457 *> cacher exiting due to error (glob)
459 *> cacher exiting due to error (glob)
458
460
459 $ killdaemons.py
461 $ killdaemons.py
460 $ rm .hg/blackbox.log
462 $ rm .hg/blackbox.log
@@ -1,744 +1,748 b''
1 #require no-chg
1 #require no-chg
2
2
3 $ . $TESTDIR/wireprotohelpers.sh
3 $ . $TESTDIR/wireprotohelpers.sh
4
4
5 $ hg init server
5 $ hg init server
6
6
7 zstd isn't present in plain builds. Make tests easier by removing
7 zstd isn't present in plain builds. Make tests easier by removing
8 zstd from the equation.
8 zstd from the equation.
9
9
10 $ cat >> server/.hg/hgrc << EOF
10 $ cat >> server/.hg/hgrc << EOF
11 > [server]
11 > [server]
12 > compressionengines = zlib
12 > compressionengines = zlib
13 > EOF
13 > EOF
14
14
15 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
15 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
16 $ cat hg.pid > $DAEMON_PIDS
16 $ cat hg.pid > $DAEMON_PIDS
17
17
18 A normal capabilities request is serviced for version 1
18 A normal capabilities request is serviced for version 1
19
19
20 $ sendhttpraw << EOF
20 $ sendhttpraw << EOF
21 > httprequest GET ?cmd=capabilities
21 > httprequest GET ?cmd=capabilities
22 > user-agent: test
22 > user-agent: test
23 > EOF
23 > EOF
24 using raw connection to peer
24 using raw connection to peer
25 s> GET /?cmd=capabilities HTTP/1.1\r\n
25 s> GET /?cmd=capabilities HTTP/1.1\r\n
26 s> Accept-Encoding: identity\r\n
26 s> Accept-Encoding: identity\r\n
27 s> user-agent: test\r\n
27 s> user-agent: test\r\n
28 s> host: $LOCALIP:$HGPORT\r\n (glob)
28 s> host: $LOCALIP:$HGPORT\r\n (glob)
29 s> \r\n
29 s> \r\n
30 s> makefile('rb', None)
30 s> makefile('rb', None)
31 s> HTTP/1.1 200 Script output follows\r\n
31 s> HTTP/1.1 200 Script output follows\r\n
32 s> Server: testing stub value\r\n
32 s> Server: testing stub value\r\n
33 s> Date: $HTTP_DATE$\r\n
33 s> Date: $HTTP_DATE$\r\n
34 s> Content-Type: application/mercurial-0.1\r\n
34 s> Content-Type: application/mercurial-0.1\r\n
35 s> Content-Length: *\r\n (glob)
35 s> Content-Length: *\r\n (glob)
36 s> \r\n
36 s> \r\n
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
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 A proper request without the API server enabled returns the legacy response
39 A proper request without the API server enabled returns the legacy response
40
40
41 $ sendhttpraw << EOF
41 $ sendhttpraw << EOF
42 > httprequest GET ?cmd=capabilities
42 > httprequest GET ?cmd=capabilities
43 > user-agent: test
43 > user-agent: test
44 > x-hgupgrade-1: foo
44 > x-hgupgrade-1: foo
45 > x-hgproto-1: cbor
45 > x-hgproto-1: cbor
46 > EOF
46 > EOF
47 using raw connection to peer
47 using raw connection to peer
48 s> GET /?cmd=capabilities HTTP/1.1\r\n
48 s> GET /?cmd=capabilities HTTP/1.1\r\n
49 s> Accept-Encoding: identity\r\n
49 s> Accept-Encoding: identity\r\n
50 s> user-agent: test\r\n
50 s> user-agent: test\r\n
51 s> x-hgproto-1: cbor\r\n
51 s> x-hgproto-1: cbor\r\n
52 s> x-hgupgrade-1: foo\r\n
52 s> x-hgupgrade-1: foo\r\n
53 s> host: $LOCALIP:$HGPORT\r\n (glob)
53 s> host: $LOCALIP:$HGPORT\r\n (glob)
54 s> \r\n
54 s> \r\n
55 s> makefile('rb', None)
55 s> makefile('rb', None)
56 s> HTTP/1.1 200 Script output follows\r\n
56 s> HTTP/1.1 200 Script output follows\r\n
57 s> Server: testing stub value\r\n
57 s> Server: testing stub value\r\n
58 s> Date: $HTTP_DATE$\r\n
58 s> Date: $HTTP_DATE$\r\n
59 s> Content-Type: application/mercurial-0.1\r\n
59 s> Content-Type: application/mercurial-0.1\r\n
60 s> Content-Length: *\r\n (glob)
60 s> Content-Length: *\r\n (glob)
61 s> \r\n
61 s> \r\n
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
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 Restart with just API server enabled. This enables serving the new format.
64 Restart with just API server enabled. This enables serving the new format.
65
65
66 $ killdaemons.py
66 $ killdaemons.py
67 $ cat error.log
67 $ cat error.log
68
68
69 $ cat >> server/.hg/hgrc << EOF
69 $ cat >> server/.hg/hgrc << EOF
70 > [experimental]
70 > [experimental]
71 > web.apiserver = true
71 > web.apiserver = true
72 > EOF
72 > EOF
73
73
74 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
74 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
75 $ cat hg.pid > $DAEMON_PIDS
75 $ cat hg.pid > $DAEMON_PIDS
76
76
77 X-HgUpgrade-<N> without CBOR advertisement uses legacy response
77 X-HgUpgrade-<N> without CBOR advertisement uses legacy response
78
78
79 $ sendhttpraw << EOF
79 $ sendhttpraw << EOF
80 > httprequest GET ?cmd=capabilities
80 > httprequest GET ?cmd=capabilities
81 > user-agent: test
81 > user-agent: test
82 > x-hgupgrade-1: foo bar
82 > x-hgupgrade-1: foo bar
83 > EOF
83 > EOF
84 using raw connection to peer
84 using raw connection to peer
85 s> GET /?cmd=capabilities HTTP/1.1\r\n
85 s> GET /?cmd=capabilities HTTP/1.1\r\n
86 s> Accept-Encoding: identity\r\n
86 s> Accept-Encoding: identity\r\n
87 s> user-agent: test\r\n
87 s> user-agent: test\r\n
88 s> x-hgupgrade-1: foo bar\r\n
88 s> x-hgupgrade-1: foo bar\r\n
89 s> host: $LOCALIP:$HGPORT\r\n (glob)
89 s> host: $LOCALIP:$HGPORT\r\n (glob)
90 s> \r\n
90 s> \r\n
91 s> makefile('rb', None)
91 s> makefile('rb', None)
92 s> HTTP/1.1 200 Script output follows\r\n
92 s> HTTP/1.1 200 Script output follows\r\n
93 s> Server: testing stub value\r\n
93 s> Server: testing stub value\r\n
94 s> Date: $HTTP_DATE$\r\n
94 s> Date: $HTTP_DATE$\r\n
95 s> Content-Type: application/mercurial-0.1\r\n
95 s> Content-Type: application/mercurial-0.1\r\n
96 s> Content-Length: *\r\n (glob)
96 s> Content-Length: *\r\n (glob)
97 s> \r\n
97 s> \r\n
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
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 X-HgUpgrade-<N> without known serialization in X-HgProto-<N> uses legacy response
100 X-HgUpgrade-<N> without known serialization in X-HgProto-<N> uses legacy response
101
101
102 $ sendhttpraw << EOF
102 $ sendhttpraw << EOF
103 > httprequest GET ?cmd=capabilities
103 > httprequest GET ?cmd=capabilities
104 > user-agent: test
104 > user-agent: test
105 > x-hgupgrade-1: foo bar
105 > x-hgupgrade-1: foo bar
106 > x-hgproto-1: some value
106 > x-hgproto-1: some value
107 > EOF
107 > EOF
108 using raw connection to peer
108 using raw connection to peer
109 s> GET /?cmd=capabilities HTTP/1.1\r\n
109 s> GET /?cmd=capabilities HTTP/1.1\r\n
110 s> Accept-Encoding: identity\r\n
110 s> Accept-Encoding: identity\r\n
111 s> user-agent: test\r\n
111 s> user-agent: test\r\n
112 s> x-hgproto-1: some value\r\n
112 s> x-hgproto-1: some value\r\n
113 s> x-hgupgrade-1: foo bar\r\n
113 s> x-hgupgrade-1: foo bar\r\n
114 s> host: $LOCALIP:$HGPORT\r\n (glob)
114 s> host: $LOCALIP:$HGPORT\r\n (glob)
115 s> \r\n
115 s> \r\n
116 s> makefile('rb', None)
116 s> makefile('rb', None)
117 s> HTTP/1.1 200 Script output follows\r\n
117 s> HTTP/1.1 200 Script output follows\r\n
118 s> Server: testing stub value\r\n
118 s> Server: testing stub value\r\n
119 s> Date: $HTTP_DATE$\r\n
119 s> Date: $HTTP_DATE$\r\n
120 s> Content-Type: application/mercurial-0.1\r\n
120 s> Content-Type: application/mercurial-0.1\r\n
121 s> Content-Length: *\r\n (glob)
121 s> Content-Length: *\r\n (glob)
122 s> \r\n
122 s> \r\n
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
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 X-HgUpgrade-<N> + X-HgProto-<N> headers trigger new response format
125 X-HgUpgrade-<N> + X-HgProto-<N> headers trigger new response format
126
126
127 $ sendhttpraw << EOF
127 $ sendhttpraw << EOF
128 > httprequest GET ?cmd=capabilities
128 > httprequest GET ?cmd=capabilities
129 > user-agent: test
129 > user-agent: test
130 > x-hgupgrade-1: foo bar
130 > x-hgupgrade-1: foo bar
131 > x-hgproto-1: cbor
131 > x-hgproto-1: cbor
132 > EOF
132 > EOF
133 using raw connection to peer
133 using raw connection to peer
134 s> GET /?cmd=capabilities HTTP/1.1\r\n
134 s> GET /?cmd=capabilities HTTP/1.1\r\n
135 s> Accept-Encoding: identity\r\n
135 s> Accept-Encoding: identity\r\n
136 s> user-agent: test\r\n
136 s> user-agent: test\r\n
137 s> x-hgproto-1: cbor\r\n
137 s> x-hgproto-1: cbor\r\n
138 s> x-hgupgrade-1: foo bar\r\n
138 s> x-hgupgrade-1: foo bar\r\n
139 s> host: $LOCALIP:$HGPORT\r\n (glob)
139 s> host: $LOCALIP:$HGPORT\r\n (glob)
140 s> \r\n
140 s> \r\n
141 s> makefile('rb', None)
141 s> makefile('rb', None)
142 s> HTTP/1.1 200 OK\r\n
142 s> HTTP/1.1 200 OK\r\n
143 s> Server: testing stub value\r\n
143 s> Server: testing stub value\r\n
144 s> Date: $HTTP_DATE$\r\n
144 s> Date: $HTTP_DATE$\r\n
145 s> Content-Type: application/mercurial-cbor\r\n
145 s> Content-Type: application/mercurial-cbor\r\n
146 s> Content-Length: *\r\n (glob)
146 s> Content-Length: *\r\n (glob)
147 s> \r\n
147 s> \r\n
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
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 cbor> [
149 cbor> [
150 {
150 {
151 b'apibase': b'api/',
151 b'apibase': b'api/',
152 b'apis': {},
152 b'apis': {},
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'
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 Restart server to enable HTTPv2
157 Restart server to enable HTTPv2
158
158
159 $ killdaemons.py
159 $ killdaemons.py
160 $ enablehttpv2 server
160 $ enablehttpv2 server
161 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
161 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
162 $ cat hg.pid > $DAEMON_PIDS
162 $ cat hg.pid > $DAEMON_PIDS
163
163
164 Only requested API services are returned
164 Only requested API services are returned
165
165
166 $ sendhttpraw << EOF
166 $ sendhttpraw << EOF
167 > httprequest GET ?cmd=capabilities
167 > httprequest GET ?cmd=capabilities
168 > user-agent: test
168 > user-agent: test
169 > x-hgupgrade-1: foo bar
169 > x-hgupgrade-1: foo bar
170 > x-hgproto-1: cbor
170 > x-hgproto-1: cbor
171 > EOF
171 > EOF
172 using raw connection to peer
172 using raw connection to peer
173 s> GET /?cmd=capabilities HTTP/1.1\r\n
173 s> GET /?cmd=capabilities HTTP/1.1\r\n
174 s> Accept-Encoding: identity\r\n
174 s> Accept-Encoding: identity\r\n
175 s> user-agent: test\r\n
175 s> user-agent: test\r\n
176 s> x-hgproto-1: cbor\r\n
176 s> x-hgproto-1: cbor\r\n
177 s> x-hgupgrade-1: foo bar\r\n
177 s> x-hgupgrade-1: foo bar\r\n
178 s> host: $LOCALIP:$HGPORT\r\n (glob)
178 s> host: $LOCALIP:$HGPORT\r\n (glob)
179 s> \r\n
179 s> \r\n
180 s> makefile('rb', None)
180 s> makefile('rb', None)
181 s> HTTP/1.1 200 OK\r\n
181 s> HTTP/1.1 200 OK\r\n
182 s> Server: testing stub value\r\n
182 s> Server: testing stub value\r\n
183 s> Date: $HTTP_DATE$\r\n
183 s> Date: $HTTP_DATE$\r\n
184 s> Content-Type: application/mercurial-cbor\r\n
184 s> Content-Type: application/mercurial-cbor\r\n
185 s> Content-Length: *\r\n (glob)
185 s> Content-Length: *\r\n (glob)
186 s> \r\n
186 s> \r\n
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
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 cbor> [
188 cbor> [
189 {
189 {
190 b'apibase': b'api/',
190 b'apibase': b'api/',
191 b'apis': {},
191 b'apis': {},
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'
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 Request for HTTPv2 service returns information about it
196 Request for HTTPv2 service returns information about it
197
197
198 $ sendhttpraw << EOF
198 $ sendhttpraw << EOF
199 > httprequest GET ?cmd=capabilities
199 > httprequest GET ?cmd=capabilities
200 > user-agent: test
200 > user-agent: test
201 > x-hgupgrade-1: exp-http-v2-0003 foo bar
201 > x-hgupgrade-1: exp-http-v2-0003 foo bar
202 > x-hgproto-1: cbor
202 > x-hgproto-1: cbor
203 > EOF
203 > EOF
204 using raw connection to peer
204 using raw connection to peer
205 s> GET /?cmd=capabilities HTTP/1.1\r\n
205 s> GET /?cmd=capabilities HTTP/1.1\r\n
206 s> Accept-Encoding: identity\r\n
206 s> Accept-Encoding: identity\r\n
207 s> user-agent: test\r\n
207 s> user-agent: test\r\n
208 s> x-hgproto-1: cbor\r\n
208 s> x-hgproto-1: cbor\r\n
209 s> x-hgupgrade-1: exp-http-v2-0003 foo bar\r\n
209 s> x-hgupgrade-1: exp-http-v2-0003 foo bar\r\n
210 s> host: $LOCALIP:$HGPORT\r\n (glob)
210 s> host: $LOCALIP:$HGPORT\r\n (glob)
211 s> \r\n
211 s> \r\n
212 s> makefile('rb', None)
212 s> makefile('rb', None)
213 s> HTTP/1.1 200 OK\r\n
213 s> HTTP/1.1 200 OK\r\n
214 s> Server: testing stub value\r\n
214 s> Server: testing stub value\r\n
215 s> Date: $HTTP_DATE$\r\n
215 s> Date: $HTTP_DATE$\r\n
216 s> Content-Type: application/mercurial-cbor\r\n
216 s> Content-Type: application/mercurial-cbor\r\n
217 s> Content-Length: *\r\n (glob)
217 s> Content-Length: *\r\n (glob)
218 s> \r\n
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 cbor> [
220 cbor> [
221 {
221 {
222 b'apibase': b'api/',
222 b'apibase': b'api/',
223 b'apis': {
223 b'apis': {
224 b'exp-http-v2-0003': {
224 b'exp-http-v2-0003': {
225 b'commands': {
225 b'commands': {
226 b'branchmap': {
226 b'branchmap': {
227 b'args': {},
227 b'args': {},
228 b'permissions': [
228 b'permissions': [
229 b'pull'
229 b'pull'
230 ]
230 ]
231 },
231 },
232 b'capabilities': {
232 b'capabilities': {
233 b'args': {},
233 b'args': {},
234 b'permissions': [
234 b'permissions': [
235 b'pull'
235 b'pull'
236 ]
236 ]
237 },
237 },
238 b'changesetdata': {
238 b'changesetdata': {
239 b'args': {
239 b'args': {
240 b'fields': {
240 b'fields': {
241 b'default': set([]),
241 b'default': set([]),
242 b'required': False,
242 b'required': False,
243 b'type': b'set',
243 b'type': b'set',
244 b'validvalues': set([
244 b'validvalues': set([
245 b'bookmarks',
245 b'bookmarks',
246 b'parents',
246 b'parents',
247 b'phase',
247 b'phase',
248 b'revision'
248 b'revision'
249 ])
249 ])
250 },
250 },
251 b'revisions': {
251 b'revisions': {
252 b'required': True,
252 b'required': True,
253 b'type': b'list'
253 b'type': b'list'
254 }
254 }
255 },
255 },
256 b'permissions': [
256 b'permissions': [
257 b'pull'
257 b'pull'
258 ]
258 ]
259 },
259 },
260 b'filedata': {
260 b'filedata': {
261 b'args': {
261 b'args': {
262 b'fields': {
262 b'fields': {
263 b'default': set([]),
263 b'default': set([]),
264 b'required': False,
264 b'required': False,
265 b'type': b'set',
265 b'type': b'set',
266 b'validvalues': set([
266 b'validvalues': set([
267 b'linknode',
267 b'parents',
268 b'parents',
268 b'revision'
269 b'revision'
269 ])
270 ])
270 },
271 },
271 b'haveparents': {
272 b'haveparents': {
272 b'default': False,
273 b'default': False,
273 b'required': False,
274 b'required': False,
274 b'type': b'bool'
275 b'type': b'bool'
275 },
276 },
276 b'nodes': {
277 b'nodes': {
277 b'required': True,
278 b'required': True,
278 b'type': b'list'
279 b'type': b'list'
279 },
280 },
280 b'path': {
281 b'path': {
281 b'required': True,
282 b'required': True,
282 b'type': b'bytes'
283 b'type': b'bytes'
283 }
284 }
284 },
285 },
285 b'permissions': [
286 b'permissions': [
286 b'pull'
287 b'pull'
287 ]
288 ]
288 },
289 },
289 b'filesdata': {
290 b'filesdata': {
290 b'args': {
291 b'args': {
291 b'fields': {
292 b'fields': {
292 b'default': set([]),
293 b'default': set([]),
293 b'required': False,
294 b'required': False,
294 b'type': b'set',
295 b'type': b'set',
295 b'validvalues': set([
296 b'validvalues': set([
296 b'firstchangeset',
297 b'firstchangeset',
298 b'linknode',
297 b'parents',
299 b'parents',
298 b'revision'
300 b'revision'
299 ])
301 ])
300 },
302 },
301 b'haveparents': {
303 b'haveparents': {
302 b'default': False,
304 b'default': False,
303 b'required': False,
305 b'required': False,
304 b'type': b'bool'
306 b'type': b'bool'
305 },
307 },
306 b'pathfilter': {
308 b'pathfilter': {
307 b'default': None,
309 b'default': None,
308 b'required': False,
310 b'required': False,
309 b'type': b'dict'
311 b'type': b'dict'
310 },
312 },
311 b'revisions': {
313 b'revisions': {
312 b'required': True,
314 b'required': True,
313 b'type': b'list'
315 b'type': b'list'
314 }
316 }
315 },
317 },
316 b'permissions': [
318 b'permissions': [
317 b'pull'
319 b'pull'
318 ],
320 ],
319 b'recommendedbatchsize': 50000
321 b'recommendedbatchsize': 50000
320 },
322 },
321 b'heads': {
323 b'heads': {
322 b'args': {
324 b'args': {
323 b'publiconly': {
325 b'publiconly': {
324 b'default': False,
326 b'default': False,
325 b'required': False,
327 b'required': False,
326 b'type': b'bool'
328 b'type': b'bool'
327 }
329 }
328 },
330 },
329 b'permissions': [
331 b'permissions': [
330 b'pull'
332 b'pull'
331 ]
333 ]
332 },
334 },
333 b'known': {
335 b'known': {
334 b'args': {
336 b'args': {
335 b'nodes': {
337 b'nodes': {
336 b'default': [],
338 b'default': [],
337 b'required': False,
339 b'required': False,
338 b'type': b'list'
340 b'type': b'list'
339 }
341 }
340 },
342 },
341 b'permissions': [
343 b'permissions': [
342 b'pull'
344 b'pull'
343 ]
345 ]
344 },
346 },
345 b'listkeys': {
347 b'listkeys': {
346 b'args': {
348 b'args': {
347 b'namespace': {
349 b'namespace': {
348 b'required': True,
350 b'required': True,
349 b'type': b'bytes'
351 b'type': b'bytes'
350 }
352 }
351 },
353 },
352 b'permissions': [
354 b'permissions': [
353 b'pull'
355 b'pull'
354 ]
356 ]
355 },
357 },
356 b'lookup': {
358 b'lookup': {
357 b'args': {
359 b'args': {
358 b'key': {
360 b'key': {
359 b'required': True,
361 b'required': True,
360 b'type': b'bytes'
362 b'type': b'bytes'
361 }
363 }
362 },
364 },
363 b'permissions': [
365 b'permissions': [
364 b'pull'
366 b'pull'
365 ]
367 ]
366 },
368 },
367 b'manifestdata': {
369 b'manifestdata': {
368 b'args': {
370 b'args': {
369 b'fields': {
371 b'fields': {
370 b'default': set([]),
372 b'default': set([]),
371 b'required': False,
373 b'required': False,
372 b'type': b'set',
374 b'type': b'set',
373 b'validvalues': set([
375 b'validvalues': set([
374 b'parents',
376 b'parents',
375 b'revision'
377 b'revision'
376 ])
378 ])
377 },
379 },
378 b'haveparents': {
380 b'haveparents': {
379 b'default': False,
381 b'default': False,
380 b'required': False,
382 b'required': False,
381 b'type': b'bool'
383 b'type': b'bool'
382 },
384 },
383 b'nodes': {
385 b'nodes': {
384 b'required': True,
386 b'required': True,
385 b'type': b'list'
387 b'type': b'list'
386 },
388 },
387 b'tree': {
389 b'tree': {
388 b'required': True,
390 b'required': True,
389 b'type': b'bytes'
391 b'type': b'bytes'
390 }
392 }
391 },
393 },
392 b'permissions': [
394 b'permissions': [
393 b'pull'
395 b'pull'
394 ],
396 ],
395 b'recommendedbatchsize': 100000
397 b'recommendedbatchsize': 100000
396 },
398 },
397 b'pushkey': {
399 b'pushkey': {
398 b'args': {
400 b'args': {
399 b'key': {
401 b'key': {
400 b'required': True,
402 b'required': True,
401 b'type': b'bytes'
403 b'type': b'bytes'
402 },
404 },
403 b'namespace': {
405 b'namespace': {
404 b'required': True,
406 b'required': True,
405 b'type': b'bytes'
407 b'type': b'bytes'
406 },
408 },
407 b'new': {
409 b'new': {
408 b'required': True,
410 b'required': True,
409 b'type': b'bytes'
411 b'type': b'bytes'
410 },
412 },
411 b'old': {
413 b'old': {
412 b'required': True,
414 b'required': True,
413 b'type': b'bytes'
415 b'type': b'bytes'
414 }
416 }
415 },
417 },
416 b'permissions': [
418 b'permissions': [
417 b'push'
419 b'push'
418 ]
420 ]
419 },
421 },
420 b'rawstorefiledata': {
422 b'rawstorefiledata': {
421 b'args': {
423 b'args': {
422 b'files': {
424 b'files': {
423 b'required': True,
425 b'required': True,
424 b'type': b'list'
426 b'type': b'list'
425 },
427 },
426 b'pathfilter': {
428 b'pathfilter': {
427 b'default': None,
429 b'default': None,
428 b'required': False,
430 b'required': False,
429 b'type': b'list'
431 b'type': b'list'
430 }
432 }
431 },
433 },
432 b'permissions': [
434 b'permissions': [
433 b'pull'
435 b'pull'
434 ]
436 ]
435 }
437 }
436 },
438 },
437 b'framingmediatypes': [
439 b'framingmediatypes': [
438 b'application/mercurial-exp-framing-0006'
440 b'application/mercurial-exp-framing-0006'
439 ],
441 ],
440 b'pathfilterprefixes': set([
442 b'pathfilterprefixes': set([
441 b'path:',
443 b'path:',
442 b'rootfilesin:'
444 b'rootfilesin:'
443 ]),
445 ]),
444 b'rawrepoformats': [
446 b'rawrepoformats': [
445 b'generaldelta',
447 b'generaldelta',
446 b'revlogv1'
448 b'revlogv1'
447 ]
449 ]
448 }
450 }
449 },
451 },
450 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'
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 capabilities command returns expected info
456 capabilities command returns expected info
455
457
456 $ sendhttpv2peerhandshake << EOF
458 $ sendhttpv2peerhandshake << EOF
457 > command capabilities
459 > command capabilities
458 > EOF
460 > EOF
459 creating http peer for wire protocol version 2
461 creating http peer for wire protocol version 2
460 s> GET /?cmd=capabilities HTTP/1.1\r\n
462 s> GET /?cmd=capabilities HTTP/1.1\r\n
461 s> Accept-Encoding: identity\r\n
463 s> Accept-Encoding: identity\r\n
462 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
464 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
463 s> x-hgproto-1: cbor\r\n
465 s> x-hgproto-1: cbor\r\n
464 s> x-hgupgrade-1: exp-http-v2-0003\r\n
466 s> x-hgupgrade-1: exp-http-v2-0003\r\n
465 s> accept: application/mercurial-0.1\r\n
467 s> accept: application/mercurial-0.1\r\n
466 s> host: $LOCALIP:$HGPORT\r\n (glob)
468 s> host: $LOCALIP:$HGPORT\r\n (glob)
467 s> user-agent: Mercurial debugwireproto\r\n
469 s> user-agent: Mercurial debugwireproto\r\n
468 s> \r\n
470 s> \r\n
469 s> makefile('rb', None)
471 s> makefile('rb', None)
470 s> HTTP/1.1 200 OK\r\n
472 s> HTTP/1.1 200 OK\r\n
471 s> Server: testing stub value\r\n
473 s> Server: testing stub value\r\n
472 s> Date: $HTTP_DATE$\r\n
474 s> Date: $HTTP_DATE$\r\n
473 s> Content-Type: application/mercurial-cbor\r\n
475 s> Content-Type: application/mercurial-cbor\r\n
474 s> Content-Length: *\r\n (glob)
476 s> Content-Length: *\r\n (glob)
475 s> \r\n
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 sending capabilities command
479 sending capabilities command
478 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
480 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
479 s> Accept-Encoding: identity\r\n
481 s> Accept-Encoding: identity\r\n
480 s> accept: application/mercurial-exp-framing-0006\r\n
482 s> accept: application/mercurial-exp-framing-0006\r\n
481 s> content-type: application/mercurial-exp-framing-0006\r\n
483 s> content-type: application/mercurial-exp-framing-0006\r\n
482 s> content-length: 63\r\n
484 s> content-length: 63\r\n
483 s> host: $LOCALIP:$HGPORT\r\n (glob)
485 s> host: $LOCALIP:$HGPORT\r\n (glob)
484 s> user-agent: Mercurial debugwireproto\r\n
486 s> user-agent: Mercurial debugwireproto\r\n
485 s> \r\n
487 s> \r\n
486 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x13\x00\x00\x01\x00\x01\x00\x11\xa1DnameLcapabilities
488 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x13\x00\x00\x01\x00\x01\x00\x11\xa1DnameLcapabilities
487 s> makefile('rb', None)
489 s> makefile('rb', None)
488 s> HTTP/1.1 200 OK\r\n
490 s> HTTP/1.1 200 OK\r\n
489 s> Server: testing stub value\r\n
491 s> Server: testing stub value\r\n
490 s> Date: $HTTP_DATE$\r\n
492 s> Date: $HTTP_DATE$\r\n
491 s> Content-Type: application/mercurial-exp-framing-0006\r\n
493 s> Content-Type: application/mercurial-exp-framing-0006\r\n
492 s> Transfer-Encoding: chunked\r\n
494 s> Transfer-Encoding: chunked\r\n
493 s> \r\n
495 s> \r\n
494 s> 11\r\n
496 s> 11\r\n
495 s> \t\x00\x00\x01\x00\x02\x01\x92
497 s> \t\x00\x00\x01\x00\x02\x01\x92
496 s> Hidentity
498 s> Hidentity
497 s> \r\n
499 s> \r\n
498 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
500 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
499 s> 13\r\n
501 s> 13\r\n
500 s> \x0b\x00\x00\x01\x00\x02\x041
502 s> \x0b\x00\x00\x01\x00\x02\x041
501 s> \xa1FstatusBok
503 s> \xa1FstatusBok
502 s> \r\n
504 s> \r\n
503 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
505 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
504 s> 63f\r\n
506 s> 651\r\n
505 s> 7\x06\x00\x01\x00\x02\x041
507 s> I\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
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 s> \r\n
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 s> 8\r\n
511 s> 8\r\n
510 s> \x00\x00\x00\x01\x00\x02\x002
512 s> \x00\x00\x00\x01\x00\x02\x002
511 s> \r\n
513 s> \r\n
512 s> 0\r\n
514 s> 0\r\n
513 s> \r\n
515 s> \r\n
514 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
516 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
515 response: gen[
517 response: gen[
516 {
518 {
517 b'commands': {
519 b'commands': {
518 b'branchmap': {
520 b'branchmap': {
519 b'args': {},
521 b'args': {},
520 b'permissions': [
522 b'permissions': [
521 b'pull'
523 b'pull'
522 ]
524 ]
523 },
525 },
524 b'capabilities': {
526 b'capabilities': {
525 b'args': {},
527 b'args': {},
526 b'permissions': [
528 b'permissions': [
527 b'pull'
529 b'pull'
528 ]
530 ]
529 },
531 },
530 b'changesetdata': {
532 b'changesetdata': {
531 b'args': {
533 b'args': {
532 b'fields': {
534 b'fields': {
533 b'default': set([]),
535 b'default': set([]),
534 b'required': False,
536 b'required': False,
535 b'type': b'set',
537 b'type': b'set',
536 b'validvalues': set([
538 b'validvalues': set([
537 b'bookmarks',
539 b'bookmarks',
538 b'parents',
540 b'parents',
539 b'phase',
541 b'phase',
540 b'revision'
542 b'revision'
541 ])
543 ])
542 },
544 },
543 b'revisions': {
545 b'revisions': {
544 b'required': True,
546 b'required': True,
545 b'type': b'list'
547 b'type': b'list'
546 }
548 }
547 },
549 },
548 b'permissions': [
550 b'permissions': [
549 b'pull'
551 b'pull'
550 ]
552 ]
551 },
553 },
552 b'filedata': {
554 b'filedata': {
553 b'args': {
555 b'args': {
554 b'fields': {
556 b'fields': {
555 b'default': set([]),
557 b'default': set([]),
556 b'required': False,
558 b'required': False,
557 b'type': b'set',
559 b'type': b'set',
558 b'validvalues': set([
560 b'validvalues': set([
561 b'linknode',
559 b'parents',
562 b'parents',
560 b'revision'
563 b'revision'
561 ])
564 ])
562 },
565 },
563 b'haveparents': {
566 b'haveparents': {
564 b'default': False,
567 b'default': False,
565 b'required': False,
568 b'required': False,
566 b'type': b'bool'
569 b'type': b'bool'
567 },
570 },
568 b'nodes': {
571 b'nodes': {
569 b'required': True,
572 b'required': True,
570 b'type': b'list'
573 b'type': b'list'
571 },
574 },
572 b'path': {
575 b'path': {
573 b'required': True,
576 b'required': True,
574 b'type': b'bytes'
577 b'type': b'bytes'
575 }
578 }
576 },
579 },
577 b'permissions': [
580 b'permissions': [
578 b'pull'
581 b'pull'
579 ]
582 ]
580 },
583 },
581 b'filesdata': {
584 b'filesdata': {
582 b'args': {
585 b'args': {
583 b'fields': {
586 b'fields': {
584 b'default': set([]),
587 b'default': set([]),
585 b'required': False,
588 b'required': False,
586 b'type': b'set',
589 b'type': b'set',
587 b'validvalues': set([
590 b'validvalues': set([
588 b'firstchangeset',
591 b'firstchangeset',
592 b'linknode',
589 b'parents',
593 b'parents',
590 b'revision'
594 b'revision'
591 ])
595 ])
592 },
596 },
593 b'haveparents': {
597 b'haveparents': {
594 b'default': False,
598 b'default': False,
595 b'required': False,
599 b'required': False,
596 b'type': b'bool'
600 b'type': b'bool'
597 },
601 },
598 b'pathfilter': {
602 b'pathfilter': {
599 b'default': None,
603 b'default': None,
600 b'required': False,
604 b'required': False,
601 b'type': b'dict'
605 b'type': b'dict'
602 },
606 },
603 b'revisions': {
607 b'revisions': {
604 b'required': True,
608 b'required': True,
605 b'type': b'list'
609 b'type': b'list'
606 }
610 }
607 },
611 },
608 b'permissions': [
612 b'permissions': [
609 b'pull'
613 b'pull'
610 ],
614 ],
611 b'recommendedbatchsize': 50000
615 b'recommendedbatchsize': 50000
612 },
616 },
613 b'heads': {
617 b'heads': {
614 b'args': {
618 b'args': {
615 b'publiconly': {
619 b'publiconly': {
616 b'default': False,
620 b'default': False,
617 b'required': False,
621 b'required': False,
618 b'type': b'bool'
622 b'type': b'bool'
619 }
623 }
620 },
624 },
621 b'permissions': [
625 b'permissions': [
622 b'pull'
626 b'pull'
623 ]
627 ]
624 },
628 },
625 b'known': {
629 b'known': {
626 b'args': {
630 b'args': {
627 b'nodes': {
631 b'nodes': {
628 b'default': [],
632 b'default': [],
629 b'required': False,
633 b'required': False,
630 b'type': b'list'
634 b'type': b'list'
631 }
635 }
632 },
636 },
633 b'permissions': [
637 b'permissions': [
634 b'pull'
638 b'pull'
635 ]
639 ]
636 },
640 },
637 b'listkeys': {
641 b'listkeys': {
638 b'args': {
642 b'args': {
639 b'namespace': {
643 b'namespace': {
640 b'required': True,
644 b'required': True,
641 b'type': b'bytes'
645 b'type': b'bytes'
642 }
646 }
643 },
647 },
644 b'permissions': [
648 b'permissions': [
645 b'pull'
649 b'pull'
646 ]
650 ]
647 },
651 },
648 b'lookup': {
652 b'lookup': {
649 b'args': {
653 b'args': {
650 b'key': {
654 b'key': {
651 b'required': True,
655 b'required': True,
652 b'type': b'bytes'
656 b'type': b'bytes'
653 }
657 }
654 },
658 },
655 b'permissions': [
659 b'permissions': [
656 b'pull'
660 b'pull'
657 ]
661 ]
658 },
662 },
659 b'manifestdata': {
663 b'manifestdata': {
660 b'args': {
664 b'args': {
661 b'fields': {
665 b'fields': {
662 b'default': set([]),
666 b'default': set([]),
663 b'required': False,
667 b'required': False,
664 b'type': b'set',
668 b'type': b'set',
665 b'validvalues': set([
669 b'validvalues': set([
666 b'parents',
670 b'parents',
667 b'revision'
671 b'revision'
668 ])
672 ])
669 },
673 },
670 b'haveparents': {
674 b'haveparents': {
671 b'default': False,
675 b'default': False,
672 b'required': False,
676 b'required': False,
673 b'type': b'bool'
677 b'type': b'bool'
674 },
678 },
675 b'nodes': {
679 b'nodes': {
676 b'required': True,
680 b'required': True,
677 b'type': b'list'
681 b'type': b'list'
678 },
682 },
679 b'tree': {
683 b'tree': {
680 b'required': True,
684 b'required': True,
681 b'type': b'bytes'
685 b'type': b'bytes'
682 }
686 }
683 },
687 },
684 b'permissions': [
688 b'permissions': [
685 b'pull'
689 b'pull'
686 ],
690 ],
687 b'recommendedbatchsize': 100000
691 b'recommendedbatchsize': 100000
688 },
692 },
689 b'pushkey': {
693 b'pushkey': {
690 b'args': {
694 b'args': {
691 b'key': {
695 b'key': {
692 b'required': True,
696 b'required': True,
693 b'type': b'bytes'
697 b'type': b'bytes'
694 },
698 },
695 b'namespace': {
699 b'namespace': {
696 b'required': True,
700 b'required': True,
697 b'type': b'bytes'
701 b'type': b'bytes'
698 },
702 },
699 b'new': {
703 b'new': {
700 b'required': True,
704 b'required': True,
701 b'type': b'bytes'
705 b'type': b'bytes'
702 },
706 },
703 b'old': {
707 b'old': {
704 b'required': True,
708 b'required': True,
705 b'type': b'bytes'
709 b'type': b'bytes'
706 }
710 }
707 },
711 },
708 b'permissions': [
712 b'permissions': [
709 b'push'
713 b'push'
710 ]
714 ]
711 },
715 },
712 b'rawstorefiledata': {
716 b'rawstorefiledata': {
713 b'args': {
717 b'args': {
714 b'files': {
718 b'files': {
715 b'required': True,
719 b'required': True,
716 b'type': b'list'
720 b'type': b'list'
717 },
721 },
718 b'pathfilter': {
722 b'pathfilter': {
719 b'default': None,
723 b'default': None,
720 b'required': False,
724 b'required': False,
721 b'type': b'list'
725 b'type': b'list'
722 }
726 }
723 },
727 },
724 b'permissions': [
728 b'permissions': [
725 b'pull'
729 b'pull'
726 ]
730 ]
727 }
731 }
728 },
732 },
729 b'framingmediatypes': [
733 b'framingmediatypes': [
730 b'application/mercurial-exp-framing-0006'
734 b'application/mercurial-exp-framing-0006'
731 ],
735 ],
732 b'pathfilterprefixes': set([
736 b'pathfilterprefixes': set([
733 b'path:',
737 b'path:',
734 b'rootfilesin:'
738 b'rootfilesin:'
735 ]),
739 ]),
736 b'rawrepoformats': [
740 b'rawrepoformats': [
737 b'generaldelta',
741 b'generaldelta',
738 b'revlogv1'
742 b'revlogv1'
739 ]
743 ]
740 }
744 }
741 ]
745 ]
742 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
746 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
743
747
744 $ cat error.log
748 $ cat error.log
@@ -1,1058 +1,1164 b''
1 $ . $TESTDIR/wireprotohelpers.sh
1 $ . $TESTDIR/wireprotohelpers.sh
2
2
3 $ hg init server
3 $ hg init server
4 $ enablehttpv2 server
4 $ enablehttpv2 server
5 $ cd server
5 $ cd server
6 $ cat > a << EOF
6 $ cat > a << EOF
7 > a0
7 > a0
8 > 00000000000000000000000000000000000000
8 > 00000000000000000000000000000000000000
9 > 11111111111111111111111111111111111111
9 > 11111111111111111111111111111111111111
10 > EOF
10 > EOF
11 $ cat > b << EOF
11 $ cat > b << EOF
12 > b0
12 > b0
13 > aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
13 > aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
14 > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
14 > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
15 > EOF
15 > EOF
16 $ mkdir -p dir0/child0 dir0/child1 dir1
16 $ mkdir -p dir0/child0 dir0/child1 dir1
17 $ echo c0 > dir0/c
17 $ echo c0 > dir0/c
18 $ echo d0 > dir0/d
18 $ echo d0 > dir0/d
19 $ echo e0 > dir0/child0/e
19 $ echo e0 > dir0/child0/e
20 $ echo f0 > dir0/child1/f
20 $ echo f0 > dir0/child1/f
21 $ hg -q commit -A -m 'commit 0'
21 $ hg -q commit -A -m 'commit 0'
22
22
23 $ echo a1 >> a
23 $ echo a1 >> a
24 $ echo d1 > dir0/d
24 $ echo d1 > dir0/d
25 $ echo g0 > g
25 $ echo g0 > g
26 $ echo h0 > h
26 $ echo h0 > h
27 $ hg -q commit -A -m 'commit 1'
27 $ hg -q commit -A -m 'commit 1'
28 $ echo f1 > dir0/child1/f
28 $ echo f1 > dir0/child1/f
29 $ echo i0 > dir0/i
29 $ echo i0 > dir0/i
30 $ hg -q commit -A -m 'commit 2'
30 $ hg -q commit -A -m 'commit 2'
31
31
32 $ hg -q up -r 0
32 $ hg -q up -r 0
33 $ echo a2 >> a
33 $ echo a2 >> a
34 $ hg commit -m 'commit 3'
34 $ hg commit -m 'commit 3'
35 created new head
35 created new head
36
36
37 $ hg log -G -T '{rev}:{node} {desc}\n'
37 $ hg log -G -T '{rev}:{node} {desc}\n'
38 @ 3:476fbf122cd82f6726f0191ff146f67140946abc commit 3
38 @ 3:476fbf122cd82f6726f0191ff146f67140946abc commit 3
39 |
39 |
40 | o 2:b91c03cbba3519ab149b6cd0a0afbdb5cf1b5c8a commit 2
40 | o 2:b91c03cbba3519ab149b6cd0a0afbdb5cf1b5c8a commit 2
41 | |
41 | |
42 | o 1:5b0b1a23577e205ea240e39c9704e28d7697cbd8 commit 1
42 | o 1:5b0b1a23577e205ea240e39c9704e28d7697cbd8 commit 1
43 |/
43 |/
44 o 0:6e875ff18c227659ad6143bb3580c65700734884 commit 0
44 o 0:6e875ff18c227659ad6143bb3580c65700734884 commit 0
45
45
46
46
47 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
47 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
48 $ cat hg.pid > $DAEMON_PIDS
48 $ cat hg.pid > $DAEMON_PIDS
49
49
50 Missing arguments is an error
50 Missing arguments is an error
51
51
52 $ sendhttpv2peer << EOF
52 $ sendhttpv2peer << EOF
53 > command filesdata
53 > command filesdata
54 > EOF
54 > EOF
55 creating http peer for wire protocol version 2
55 creating http peer for wire protocol version 2
56 sending filesdata command
56 sending filesdata command
57 abort: missing required arguments: revisions!
57 abort: missing required arguments: revisions!
58 [255]
58 [255]
59
59
60 Bad pattern to pathfilter is rejected
60 Bad pattern to pathfilter is rejected
61
61
62 $ sendhttpv2peer << EOF
62 $ sendhttpv2peer << EOF
63 > command filesdata
63 > command filesdata
64 > revisions eval:[{
64 > revisions eval:[{
65 > b'type': b'changesetexplicit',
65 > b'type': b'changesetexplicit',
66 > b'nodes': [
66 > b'nodes': [
67 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
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 > pathfilter eval:{b'include': [b'bad:foo']}
69 > pathfilter eval:{b'include': [b'bad:foo']}
70 > EOF
70 > EOF
71 creating http peer for wire protocol version 2
71 creating http peer for wire protocol version 2
72 sending filesdata command
72 sending filesdata command
73 abort: include pattern must begin with `path:` or `rootfilesin:`; got bad:foo!
73 abort: include pattern must begin with `path:` or `rootfilesin:`; got bad:foo!
74 [255]
74 [255]
75
75
76 $ sendhttpv2peer << EOF
76 $ sendhttpv2peer << EOF
77 > command filesdata
77 > command filesdata
78 > revisions eval:[{
78 > revisions eval:[{
79 > b'type': b'changesetexplicit',
79 > b'type': b'changesetexplicit',
80 > b'nodes': [
80 > b'nodes': [
81 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
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 > pathfilter eval:{b'exclude': [b'glob:foo']}
83 > pathfilter eval:{b'exclude': [b'glob:foo']}
84 > EOF
84 > EOF
85 creating http peer for wire protocol version 2
85 creating http peer for wire protocol version 2
86 sending filesdata command
86 sending filesdata command
87 abort: exclude pattern must begin with `path:` or `rootfilesin:`; got glob:foo!
87 abort: exclude pattern must begin with `path:` or `rootfilesin:`; got glob:foo!
88 [255]
88 [255]
89
89
90 Fetching a single changeset without parents fetches all files
90 Fetching a single changeset without parents fetches all files
91
91
92 $ sendhttpv2peer << EOF
92 $ sendhttpv2peer << EOF
93 > command filesdata
93 > command filesdata
94 > revisions eval:[{
94 > revisions eval:[{
95 > b'type': b'changesetexplicit',
95 > b'type': b'changesetexplicit',
96 > b'nodes': [
96 > b'nodes': [
97 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
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 > EOF
99 > EOF
100 creating http peer for wire protocol version 2
100 creating http peer for wire protocol version 2
101 sending filesdata command
101 sending filesdata command
102 response: gen[
102 response: gen[
103 {
103 {
104 b'totalitems': 8,
104 b'totalitems': 8,
105 b'totalpaths': 8
105 b'totalpaths': 8
106 },
106 },
107 {
107 {
108 b'path': b'a',
108 b'path': b'a',
109 b'totalitems': 1
109 b'totalitems': 1
110 },
110 },
111 {
111 {
112 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
112 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
113 },
113 },
114 {
114 {
115 b'path': b'b',
115 b'path': b'b',
116 b'totalitems': 1
116 b'totalitems': 1
117 },
117 },
118 {
118 {
119 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
119 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
120 },
120 },
121 {
121 {
122 b'path': b'dir0/c',
122 b'path': b'dir0/c',
123 b'totalitems': 1
123 b'totalitems': 1
124 },
124 },
125 {
125 {
126 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
126 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
127 },
127 },
128 {
128 {
129 b'path': b'dir0/child0/e',
129 b'path': b'dir0/child0/e',
130 b'totalitems': 1
130 b'totalitems': 1
131 },
131 },
132 {
132 {
133 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
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 b'path': b'dir0/child1/f',
136 b'path': b'dir0/child1/f',
137 b'totalitems': 1
137 b'totalitems': 1
138 },
138 },
139 {
139 {
140 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
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 b'path': b'dir0/d',
143 b'path': b'dir0/d',
144 b'totalitems': 1
144 b'totalitems': 1
145 },
145 },
146 {
146 {
147 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
147 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
148 },
148 },
149 {
149 {
150 b'path': b'g',
150 b'path': b'g',
151 b'totalitems': 1
151 b'totalitems': 1
152 },
152 },
153 {
153 {
154 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
154 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
155 },
155 },
156 {
156 {
157 b'path': b'h',
157 b'path': b'h',
158 b'totalitems': 1
158 b'totalitems': 1
159 },
159 },
160 {
160 {
161 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
161 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
162 }
162 }
163 ]
163 ]
164
164
165 Fetching a single changeset saying parents data is available fetches just new files
165 Fetching a single changeset saying parents data is available fetches just new files
166
166
167 $ sendhttpv2peer << EOF
167 $ sendhttpv2peer << EOF
168 > command filesdata
168 > command filesdata
169 > revisions eval:[{
169 > revisions eval:[{
170 > b'type': b'changesetexplicit',
170 > b'type': b'changesetexplicit',
171 > b'nodes': [
171 > b'nodes': [
172 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
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 > haveparents eval:True
174 > haveparents eval:True
175 > EOF
175 > EOF
176 creating http peer for wire protocol version 2
176 creating http peer for wire protocol version 2
177 sending filesdata command
177 sending filesdata command
178 response: gen[
178 response: gen[
179 {
179 {
180 b'totalitems': 4,
180 b'totalitems': 4,
181 b'totalpaths': 4
181 b'totalpaths': 4
182 },
182 },
183 {
183 {
184 b'path': b'a',
184 b'path': b'a',
185 b'totalitems': 1
185 b'totalitems': 1
186 },
186 },
187 {
187 {
188 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
188 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
189 },
189 },
190 {
190 {
191 b'path': b'dir0/d',
191 b'path': b'dir0/d',
192 b'totalitems': 1
192 b'totalitems': 1
193 },
193 },
194 {
194 {
195 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
195 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
196 },
196 },
197 {
197 {
198 b'path': b'g',
198 b'path': b'g',
199 b'totalitems': 1
199 b'totalitems': 1
200 },
200 },
201 {
201 {
202 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
202 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
203 },
203 },
204 {
204 {
205 b'path': b'h',
205 b'path': b'h',
206 b'totalitems': 1
206 b'totalitems': 1
207 },
207 },
208 {
208 {
209 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
209 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
210 }
210 }
211 ]
211 ]
212
212
213 A path filter for a sub-directory is honored
213 A path filter for a sub-directory is honored
214
214
215 $ sendhttpv2peer << EOF
215 $ sendhttpv2peer << EOF
216 > command filesdata
216 > command filesdata
217 > revisions eval:[{
217 > revisions eval:[{
218 > b'type': b'changesetexplicit',
218 > b'type': b'changesetexplicit',
219 > b'nodes': [
219 > b'nodes': [
220 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
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 > haveparents eval:True
222 > haveparents eval:True
223 > pathfilter eval:{b'include': [b'path:dir0']}
223 > pathfilter eval:{b'include': [b'path:dir0']}
224 > EOF
224 > EOF
225 creating http peer for wire protocol version 2
225 creating http peer for wire protocol version 2
226 sending filesdata command
226 sending filesdata command
227 response: gen[
227 response: gen[
228 {
228 {
229 b'totalitems': 1,
229 b'totalitems': 1,
230 b'totalpaths': 1
230 b'totalpaths': 1
231 },
231 },
232 {
232 {
233 b'path': b'dir0/d',
233 b'path': b'dir0/d',
234 b'totalitems': 1
234 b'totalitems': 1
235 },
235 },
236 {
236 {
237 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
237 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
238 }
238 }
239 ]
239 ]
240
240
241 $ sendhttpv2peer << EOF
241 $ sendhttpv2peer << EOF
242 > command filesdata
242 > command filesdata
243 > revisions eval:[{
243 > revisions eval:[{
244 > b'type': b'changesetexplicit',
244 > b'type': b'changesetexplicit',
245 > b'nodes': [
245 > b'nodes': [
246 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
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 > haveparents eval:True
248 > haveparents eval:True
249 > pathfilter eval:{b'exclude': [b'path:a', b'path:g']}
249 > pathfilter eval:{b'exclude': [b'path:a', b'path:g']}
250 > EOF
250 > EOF
251 creating http peer for wire protocol version 2
251 creating http peer for wire protocol version 2
252 sending filesdata command
252 sending filesdata command
253 response: gen[
253 response: gen[
254 {
254 {
255 b'totalitems': 2,
255 b'totalitems': 2,
256 b'totalpaths': 2
256 b'totalpaths': 2
257 },
257 },
258 {
258 {
259 b'path': b'dir0/d',
259 b'path': b'dir0/d',
260 b'totalitems': 1
260 b'totalitems': 1
261 },
261 },
262 {
262 {
263 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
263 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
264 },
264 },
265 {
265 {
266 b'path': b'h',
266 b'path': b'h',
267 b'totalitems': 1
267 b'totalitems': 1
268 },
268 },
269 {
269 {
270 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
270 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
271 }
271 }
272 ]
272 ]
273
273
274 Requesting multiple changeset nodes without haveparents sends all data for both
274 Requesting multiple changeset nodes without haveparents sends all data for both
275
275
276 $ sendhttpv2peer << EOF
276 $ sendhttpv2peer << EOF
277 > command filesdata
277 > command filesdata
278 > revisions eval:[{
278 > revisions eval:[{
279 > b'type': b'changesetexplicit',
279 > b'type': b'changesetexplicit',
280 > b'nodes': [
280 > b'nodes': [
281 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
281 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
282 > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
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 > EOF
284 > EOF
285 creating http peer for wire protocol version 2
285 creating http peer for wire protocol version 2
286 sending filesdata command
286 sending filesdata command
287 response: gen[
287 response: gen[
288 {
288 {
289 b'totalitems': 10,
289 b'totalitems': 10,
290 b'totalpaths': 9
290 b'totalpaths': 9
291 },
291 },
292 {
292 {
293 b'path': b'a',
293 b'path': b'a',
294 b'totalitems': 1
294 b'totalitems': 1
295 },
295 },
296 {
296 {
297 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
297 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
298 },
298 },
299 {
299 {
300 b'path': b'b',
300 b'path': b'b',
301 b'totalitems': 1
301 b'totalitems': 1
302 },
302 },
303 {
303 {
304 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
304 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
305 },
305 },
306 {
306 {
307 b'path': b'dir0/c',
307 b'path': b'dir0/c',
308 b'totalitems': 1
308 b'totalitems': 1
309 },
309 },
310 {
310 {
311 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
311 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
312 },
312 },
313 {
313 {
314 b'path': b'dir0/child0/e',
314 b'path': b'dir0/child0/e',
315 b'totalitems': 1
315 b'totalitems': 1
316 },
316 },
317 {
317 {
318 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
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 b'path': b'dir0/child1/f',
321 b'path': b'dir0/child1/f',
322 b'totalitems': 2
322 b'totalitems': 2
323 },
323 },
324 {
324 {
325 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
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 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
328 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
329 },
329 },
330 {
330 {
331 b'path': b'dir0/d',
331 b'path': b'dir0/d',
332 b'totalitems': 1
332 b'totalitems': 1
333 },
333 },
334 {
334 {
335 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
335 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
336 },
336 },
337 {
337 {
338 b'path': b'dir0/i',
338 b'path': b'dir0/i',
339 b'totalitems': 1
339 b'totalitems': 1
340 },
340 },
341 {
341 {
342 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
342 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
343 },
343 },
344 {
344 {
345 b'path': b'g',
345 b'path': b'g',
346 b'totalitems': 1
346 b'totalitems': 1
347 },
347 },
348 {
348 {
349 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
349 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
350 },
350 },
351 {
351 {
352 b'path': b'h',
352 b'path': b'h',
353 b'totalitems': 1
353 b'totalitems': 1
354 },
354 },
355 {
355 {
356 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
356 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
357 }
357 }
358 ]
358 ]
359
359
360 Requesting multiple changeset nodes with haveparents sends incremental data for both
360 Requesting multiple changeset nodes with haveparents sends incremental data for both
361
361
362 $ sendhttpv2peer << EOF
362 $ sendhttpv2peer << EOF
363 > command filesdata
363 > command filesdata
364 > revisions eval:[{
364 > revisions eval:[{
365 > b'type': b'changesetexplicit',
365 > b'type': b'changesetexplicit',
366 > b'nodes': [
366 > b'nodes': [
367 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
367 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
368 > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
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 > haveparents eval:True
370 > haveparents eval:True
371 > EOF
371 > EOF
372 creating http peer for wire protocol version 2
372 creating http peer for wire protocol version 2
373 sending filesdata command
373 sending filesdata command
374 response: gen[
374 response: gen[
375 {
375 {
376 b'totalitems': 6,
376 b'totalitems': 6,
377 b'totalpaths': 6
377 b'totalpaths': 6
378 },
378 },
379 {
379 {
380 b'path': b'a',
380 b'path': b'a',
381 b'totalitems': 1
381 b'totalitems': 1
382 },
382 },
383 {
383 {
384 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
384 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
385 },
385 },
386 {
386 {
387 b'path': b'dir0/child1/f',
387 b'path': b'dir0/child1/f',
388 b'totalitems': 1
388 b'totalitems': 1
389 },
389 },
390 {
390 {
391 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
391 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
392 },
392 },
393 {
393 {
394 b'path': b'dir0/d',
394 b'path': b'dir0/d',
395 b'totalitems': 1
395 b'totalitems': 1
396 },
396 },
397 {
397 {
398 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
398 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
399 },
399 },
400 {
400 {
401 b'path': b'dir0/i',
401 b'path': b'dir0/i',
402 b'totalitems': 1
402 b'totalitems': 1
403 },
403 },
404 {
404 {
405 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
405 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
406 },
406 },
407 {
407 {
408 b'path': b'g',
408 b'path': b'g',
409 b'totalitems': 1
409 b'totalitems': 1
410 },
410 },
411 {
411 {
412 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
412 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
413 },
413 },
414 {
414 {
415 b'path': b'h',
415 b'path': b'h',
416 b'totalitems': 1
416 b'totalitems': 1
417 },
417 },
418 {
418 {
419 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
419 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
420 }
420 }
421 ]
421 ]
422
422
423 Requesting parents works
423 Requesting parents works
424
424
425 $ sendhttpv2peer << EOF
425 $ sendhttpv2peer << EOF
426 > command filesdata
426 > command filesdata
427 > revisions eval:[{
427 > revisions eval:[{
428 > b'type': b'changesetexplicit',
428 > b'type': b'changesetexplicit',
429 > b'nodes': [
429 > b'nodes': [
430 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
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 > fields eval:[b'parents']
432 > fields eval:[b'parents']
433 > EOF
433 > EOF
434 creating http peer for wire protocol version 2
434 creating http peer for wire protocol version 2
435 sending filesdata command
435 sending filesdata command
436 response: gen[
436 response: gen[
437 {
437 {
438 b'totalitems': 8,
438 b'totalitems': 8,
439 b'totalpaths': 8
439 b'totalpaths': 8
440 },
440 },
441 {
441 {
442 b'path': b'a',
442 b'path': b'a',
443 b'totalitems': 1
443 b'totalitems': 1
444 },
444 },
445 {
445 {
446 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11',
446 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11',
447 b'parents': [
447 b'parents': [
448 b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
448 b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
449 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 b'path': b'b',
453 b'path': b'b',
454 b'totalitems': 1
454 b'totalitems': 1
455 },
455 },
456 {
456 {
457 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2',
457 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2',
458 b'parents': [
458 b'parents': [
459 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
459 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
460 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 b'path': b'dir0/c',
464 b'path': b'dir0/c',
465 b'totalitems': 1
465 b'totalitems': 1
466 },
466 },
467 {
467 {
468 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01',
468 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01',
469 b'parents': [
469 b'parents': [
470 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
470 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
471 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 b'path': b'dir0/child0/e',
475 b'path': b'dir0/child0/e',
476 b'totalitems': 1
476 b'totalitems': 1
477 },
477 },
478 {
478 {
479 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4',
479 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4',
480 b'parents': [
480 b'parents': [
481 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
481 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
482 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 b'path': b'dir0/child1/f',
486 b'path': b'dir0/child1/f',
487 b'totalitems': 1
487 b'totalitems': 1
488 },
488 },
489 {
489 {
490 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4',
490 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4',
491 b'parents': [
491 b'parents': [
492 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
492 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
493 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 b'path': b'dir0/d',
497 b'path': b'dir0/d',
498 b'totalitems': 1
498 b'totalitems': 1
499 },
499 },
500 {
500 {
501 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G',
501 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G',
502 b'parents': [
502 b'parents': [
503 b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
503 b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
504 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 b'path': b'g',
508 b'path': b'g',
509 b'totalitems': 1
509 b'totalitems': 1
510 },
510 },
511 {
511 {
512 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c',
512 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c',
513 b'parents': [
513 b'parents': [
514 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
514 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
515 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 b'path': b'h',
519 b'path': b'h',
520 b'totalitems': 1
520 b'totalitems': 1
521 },
521 },
522 {
522 {
523 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K',
523 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K',
524 b'parents': [
524 b'parents': [
525 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
525 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
526 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 Requesting revision data works
531 Requesting revision data works
532 (haveparents defaults to False, so fulltext is emitted)
532 (haveparents defaults to False, so fulltext is emitted)
533
533
534 $ sendhttpv2peer << EOF
534 $ sendhttpv2peer << EOF
535 > command filesdata
535 > command filesdata
536 > revisions eval:[{
536 > revisions eval:[{
537 > b'type': b'changesetexplicit',
537 > b'type': b'changesetexplicit',
538 > b'nodes': [
538 > b'nodes': [
539 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
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 > fields eval:[b'revision']
541 > fields eval:[b'revision']
542 > EOF
542 > EOF
543 creating http peer for wire protocol version 2
543 creating http peer for wire protocol version 2
544 sending filesdata command
544 sending filesdata command
545 response: gen[
545 response: gen[
546 {
546 {
547 b'totalitems': 8,
547 b'totalitems': 8,
548 b'totalpaths': 8
548 b'totalpaths': 8
549 },
549 },
550 {
550 {
551 b'path': b'a',
551 b'path': b'a',
552 b'totalitems': 1
552 b'totalitems': 1
553 },
553 },
554 {
554 {
555 b'fieldsfollowing': [
555 b'fieldsfollowing': [
556 [
556 [
557 b'revision',
557 b'revision',
558 84
558 84
559 ]
559 ]
560 ],
560 ],
561 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
561 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
562 },
562 },
563 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n',
563 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n',
564 {
564 {
565 b'path': b'b',
565 b'path': b'b',
566 b'totalitems': 1
566 b'totalitems': 1
567 },
567 },
568 {
568 {
569 b'fieldsfollowing': [
569 b'fieldsfollowing': [
570 [
570 [
571 b'revision',
571 b'revision',
572 81
572 81
573 ]
573 ]
574 ],
574 ],
575 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
575 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
576 },
576 },
577 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
577 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
578 {
578 {
579 b'path': b'dir0/c',
579 b'path': b'dir0/c',
580 b'totalitems': 1
580 b'totalitems': 1
581 },
581 },
582 {
582 {
583 b'fieldsfollowing': [
583 b'fieldsfollowing': [
584 [
584 [
585 b'revision',
585 b'revision',
586 3
586 3
587 ]
587 ]
588 ],
588 ],
589 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
589 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
590 },
590 },
591 b'c0\n',
591 b'c0\n',
592 {
592 {
593 b'path': b'dir0/child0/e',
593 b'path': b'dir0/child0/e',
594 b'totalitems': 1
594 b'totalitems': 1
595 },
595 },
596 {
596 {
597 b'fieldsfollowing': [
597 b'fieldsfollowing': [
598 [
598 [
599 b'revision',
599 b'revision',
600 3
600 3
601 ]
601 ]
602 ],
602 ],
603 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
603 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
604 },
604 },
605 b'e0\n',
605 b'e0\n',
606 {
606 {
607 b'path': b'dir0/child1/f',
607 b'path': b'dir0/child1/f',
608 b'totalitems': 1
608 b'totalitems': 1
609 },
609 },
610 {
610 {
611 b'fieldsfollowing': [
611 b'fieldsfollowing': [
612 [
612 [
613 b'revision',
613 b'revision',
614 3
614 3
615 ]
615 ]
616 ],
616 ],
617 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
617 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
618 },
618 },
619 b'f0\n',
619 b'f0\n',
620 {
620 {
621 b'path': b'dir0/d',
621 b'path': b'dir0/d',
622 b'totalitems': 1
622 b'totalitems': 1
623 },
623 },
624 {
624 {
625 b'fieldsfollowing': [
625 b'fieldsfollowing': [
626 [
626 [
627 b'revision',
627 b'revision',
628 3
628 3
629 ]
629 ]
630 ],
630 ],
631 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
631 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
632 },
632 },
633 b'd1\n',
633 b'd1\n',
634 {
634 {
635 b'path': b'g',
635 b'path': b'g',
636 b'totalitems': 1
636 b'totalitems': 1
637 },
637 },
638 {
638 {
639 b'fieldsfollowing': [
639 b'fieldsfollowing': [
640 [
640 [
641 b'revision',
641 b'revision',
642 3
642 3
643 ]
643 ]
644 ],
644 ],
645 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
645 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
646 },
646 },
647 b'g0\n',
647 b'g0\n',
648 {
648 {
649 b'path': b'h',
649 b'path': b'h',
650 b'totalitems': 1
650 b'totalitems': 1
651 },
651 },
652 {
652 {
653 b'fieldsfollowing': [
653 b'fieldsfollowing': [
654 [
654 [
655 b'revision',
655 b'revision',
656 3
656 3
657 ]
657 ]
658 ],
658 ],
659 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
659 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
660 },
660 },
661 b'h0\n'
661 b'h0\n'
662 ]
662 ]
663
663
664 haveparents=False should be same as above
664 haveparents=False should be same as above
665
665
666 $ sendhttpv2peer << EOF
666 $ sendhttpv2peer << EOF
667 > command filesdata
667 > command filesdata
668 > revisions eval:[{
668 > revisions eval:[{
669 > b'type': b'changesetexplicit',
669 > b'type': b'changesetexplicit',
670 > b'nodes': [
670 > b'nodes': [
671 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
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 > fields eval:[b'revision']
673 > fields eval:[b'revision']
674 > haveparents eval:False
674 > haveparents eval:False
675 > EOF
675 > EOF
676 creating http peer for wire protocol version 2
676 creating http peer for wire protocol version 2
677 sending filesdata command
677 sending filesdata command
678 response: gen[
678 response: gen[
679 {
679 {
680 b'totalitems': 8,
680 b'totalitems': 8,
681 b'totalpaths': 8
681 b'totalpaths': 8
682 },
682 },
683 {
683 {
684 b'path': b'a',
684 b'path': b'a',
685 b'totalitems': 1
685 b'totalitems': 1
686 },
686 },
687 {
687 {
688 b'fieldsfollowing': [
688 b'fieldsfollowing': [
689 [
689 [
690 b'revision',
690 b'revision',
691 84
691 84
692 ]
692 ]
693 ],
693 ],
694 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
694 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
695 },
695 },
696 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n',
696 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n',
697 {
697 {
698 b'path': b'b',
698 b'path': b'b',
699 b'totalitems': 1
699 b'totalitems': 1
700 },
700 },
701 {
701 {
702 b'fieldsfollowing': [
702 b'fieldsfollowing': [
703 [
703 [
704 b'revision',
704 b'revision',
705 81
705 81
706 ]
706 ]
707 ],
707 ],
708 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
708 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
709 },
709 },
710 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
710 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
711 {
711 {
712 b'path': b'dir0/c',
712 b'path': b'dir0/c',
713 b'totalitems': 1
713 b'totalitems': 1
714 },
714 },
715 {
715 {
716 b'fieldsfollowing': [
716 b'fieldsfollowing': [
717 [
717 [
718 b'revision',
718 b'revision',
719 3
719 3
720 ]
720 ]
721 ],
721 ],
722 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
722 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
723 },
723 },
724 b'c0\n',
724 b'c0\n',
725 {
725 {
726 b'path': b'dir0/child0/e',
726 b'path': b'dir0/child0/e',
727 b'totalitems': 1
727 b'totalitems': 1
728 },
728 },
729 {
729 {
730 b'fieldsfollowing': [
730 b'fieldsfollowing': [
731 [
731 [
732 b'revision',
732 b'revision',
733 3
733 3
734 ]
734 ]
735 ],
735 ],
736 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
736 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
737 },
737 },
738 b'e0\n',
738 b'e0\n',
739 {
739 {
740 b'path': b'dir0/child1/f',
740 b'path': b'dir0/child1/f',
741 b'totalitems': 1
741 b'totalitems': 1
742 },
742 },
743 {
743 {
744 b'fieldsfollowing': [
744 b'fieldsfollowing': [
745 [
745 [
746 b'revision',
746 b'revision',
747 3
747 3
748 ]
748 ]
749 ],
749 ],
750 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
750 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
751 },
751 },
752 b'f0\n',
752 b'f0\n',
753 {
753 {
754 b'path': b'dir0/d',
754 b'path': b'dir0/d',
755 b'totalitems': 1
755 b'totalitems': 1
756 },
756 },
757 {
757 {
758 b'fieldsfollowing': [
758 b'fieldsfollowing': [
759 [
759 [
760 b'revision',
760 b'revision',
761 3
761 3
762 ]
762 ]
763 ],
763 ],
764 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
764 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
765 },
765 },
766 b'd1\n',
766 b'd1\n',
767 {
767 {
768 b'path': b'g',
768 b'path': b'g',
769 b'totalitems': 1
769 b'totalitems': 1
770 },
770 },
771 {
771 {
772 b'fieldsfollowing': [
772 b'fieldsfollowing': [
773 [
773 [
774 b'revision',
774 b'revision',
775 3
775 3
776 ]
776 ]
777 ],
777 ],
778 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
778 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
779 },
779 },
780 b'g0\n',
780 b'g0\n',
781 {
781 {
782 b'path': b'h',
782 b'path': b'h',
783 b'totalitems': 1
783 b'totalitems': 1
784 },
784 },
785 {
785 {
786 b'fieldsfollowing': [
786 b'fieldsfollowing': [
787 [
787 [
788 b'revision',
788 b'revision',
789 3
789 3
790 ]
790 ]
791 ],
791 ],
792 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
792 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
793 },
793 },
794 b'h0\n'
794 b'h0\n'
795 ]
795 ]
796
796
797 haveparents=True should emit a delta
797 haveparents=True should emit a delta
798
798
799 $ sendhttpv2peer << EOF
799 $ sendhttpv2peer << EOF
800 > command filesdata
800 > command filesdata
801 > revisions eval:[{
801 > revisions eval:[{
802 > b'type': b'changesetexplicit',
802 > b'type': b'changesetexplicit',
803 > b'nodes': [
803 > b'nodes': [
804 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
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 > fields eval:[b'revision']
806 > fields eval:[b'revision']
807 > haveparents eval:True
807 > haveparents eval:True
808 > EOF
808 > EOF
809 creating http peer for wire protocol version 2
809 creating http peer for wire protocol version 2
810 sending filesdata command
810 sending filesdata command
811 response: gen[
811 response: gen[
812 {
812 {
813 b'totalitems': 4,
813 b'totalitems': 4,
814 b'totalpaths': 4
814 b'totalpaths': 4
815 },
815 },
816 {
816 {
817 b'path': b'a',
817 b'path': b'a',
818 b'totalitems': 1
818 b'totalitems': 1
819 },
819 },
820 {
820 {
821 b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
821 b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
822 b'fieldsfollowing': [
822 b'fieldsfollowing': [
823 [
823 [
824 b'delta',
824 b'delta',
825 15
825 15
826 ]
826 ]
827 ],
827 ],
828 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
828 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
829 },
829 },
830 b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n',
830 b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n',
831 {
831 {
832 b'path': b'dir0/d',
832 b'path': b'dir0/d',
833 b'totalitems': 1
833 b'totalitems': 1
834 },
834 },
835 {
835 {
836 b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
836 b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
837 b'fieldsfollowing': [
837 b'fieldsfollowing': [
838 [
838 [
839 b'delta',
839 b'delta',
840 15
840 15
841 ]
841 ]
842 ],
842 ],
843 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
843 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
844 },
844 },
845 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n',
845 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n',
846 {
846 {
847 b'path': b'g',
847 b'path': b'g',
848 b'totalitems': 1
848 b'totalitems': 1
849 },
849 },
850 {
850 {
851 b'fieldsfollowing': [
851 b'fieldsfollowing': [
852 [
852 [
853 b'revision',
853 b'revision',
854 3
854 3
855 ]
855 ]
856 ],
856 ],
857 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
857 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
858 },
858 },
859 b'g0\n',
859 b'g0\n',
860 {
860 {
861 b'path': b'h',
861 b'path': b'h',
862 b'totalitems': 1
862 b'totalitems': 1
863 },
863 },
864 {
864 {
865 b'fieldsfollowing': [
865 b'fieldsfollowing': [
866 [
866 [
867 b'revision',
867 b'revision',
868 3
868 3
869 ]
869 ]
870 ],
870 ],
871 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
871 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
872 },
872 },
873 b'h0\n'
873 b'h0\n'
874 ]
874 ]
875
875
876 Requesting multiple revisions works
876 Requesting multiple revisions works
877 (first revision is a fulltext since haveparents=False by default)
877 (first revision is a fulltext since haveparents=False by default)
878
878
879 $ sendhttpv2peer << EOF
879 $ sendhttpv2peer << EOF
880 > command filesdata
880 > command filesdata
881 > revisions eval:[{
881 > revisions eval:[{
882 > b'type': b'changesetexplicit',
882 > b'type': b'changesetexplicit',
883 > b'nodes': [
883 > b'nodes': [
884 > b'\x6e\x87\x5f\xf1\x8c\x22\x76\x59\xad\x61\x43\xbb\x35\x80\xc6\x57\x00\x73\x48\x84',
884 > b'\x6e\x87\x5f\xf1\x8c\x22\x76\x59\xad\x61\x43\xbb\x35\x80\xc6\x57\x00\x73\x48\x84',
885 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
885 > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
886 > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
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 > fields eval:[b'revision']
888 > fields eval:[b'revision']
889 > EOF
889 > EOF
890 creating http peer for wire protocol version 2
890 creating http peer for wire protocol version 2
891 sending filesdata command
891 sending filesdata command
892 response: gen[
892 response: gen[
893 {
893 {
894 b'totalitems': 12,
894 b'totalitems': 12,
895 b'totalpaths': 9
895 b'totalpaths': 9
896 },
896 },
897 {
897 {
898 b'path': b'a',
898 b'path': b'a',
899 b'totalitems': 2
899 b'totalitems': 2
900 },
900 },
901 {
901 {
902 b'fieldsfollowing': [
902 b'fieldsfollowing': [
903 [
903 [
904 b'revision',
904 b'revision',
905 81
905 81
906 ]
906 ]
907 ],
907 ],
908 b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9'
908 b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9'
909 },
909 },
910 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\n',
910 b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\n',
911 {
911 {
912 b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
912 b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
913 b'fieldsfollowing': [
913 b'fieldsfollowing': [
914 [
914 [
915 b'delta',
915 b'delta',
916 15
916 15
917 ]
917 ]
918 ],
918 ],
919 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
919 b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
920 },
920 },
921 b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n',
921 b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n',
922 {
922 {
923 b'path': b'b',
923 b'path': b'b',
924 b'totalitems': 1
924 b'totalitems': 1
925 },
925 },
926 {
926 {
927 b'fieldsfollowing': [
927 b'fieldsfollowing': [
928 [
928 [
929 b'revision',
929 b'revision',
930 81
930 81
931 ]
931 ]
932 ],
932 ],
933 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
933 b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
934 },
934 },
935 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
935 b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
936 {
936 {
937 b'path': b'dir0/c',
937 b'path': b'dir0/c',
938 b'totalitems': 1
938 b'totalitems': 1
939 },
939 },
940 {
940 {
941 b'fieldsfollowing': [
941 b'fieldsfollowing': [
942 [
942 [
943 b'revision',
943 b'revision',
944 3
944 3
945 ]
945 ]
946 ],
946 ],
947 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
947 b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
948 },
948 },
949 b'c0\n',
949 b'c0\n',
950 {
950 {
951 b'path': b'dir0/child0/e',
951 b'path': b'dir0/child0/e',
952 b'totalitems': 1
952 b'totalitems': 1
953 },
953 },
954 {
954 {
955 b'fieldsfollowing': [
955 b'fieldsfollowing': [
956 [
956 [
957 b'revision',
957 b'revision',
958 3
958 3
959 ]
959 ]
960 ],
960 ],
961 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
961 b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
962 },
962 },
963 b'e0\n',
963 b'e0\n',
964 {
964 {
965 b'path': b'dir0/child1/f',
965 b'path': b'dir0/child1/f',
966 b'totalitems': 2
966 b'totalitems': 2
967 },
967 },
968 {
968 {
969 b'fieldsfollowing': [
969 b'fieldsfollowing': [
970 [
970 [
971 b'revision',
971 b'revision',
972 3
972 3
973 ]
973 ]
974 ],
974 ],
975 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
975 b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
976 },
976 },
977 b'f0\n',
977 b'f0\n',
978 {
978 {
979 b'deltabasenode': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4',
979 b'deltabasenode': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4',
980 b'fieldsfollowing': [
980 b'fieldsfollowing': [
981 [
981 [
982 b'delta',
982 b'delta',
983 15
983 15
984 ]
984 ]
985 ],
985 ],
986 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
986 b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
987 },
987 },
988 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03f1\n',
988 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03f1\n',
989 {
989 {
990 b'path': b'dir0/d',
990 b'path': b'dir0/d',
991 b'totalitems': 2
991 b'totalitems': 2
992 },
992 },
993 {
993 {
994 b'fieldsfollowing': [
994 b'fieldsfollowing': [
995 [
995 [
996 b'revision',
996 b'revision',
997 3
997 3
998 ]
998 ]
999 ],
999 ],
1000 b'node': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&'
1000 b'node': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&'
1001 },
1001 },
1002 b'd0\n',
1002 b'd0\n',
1003 {
1003 {
1004 b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
1004 b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
1005 b'fieldsfollowing': [
1005 b'fieldsfollowing': [
1006 [
1006 [
1007 b'delta',
1007 b'delta',
1008 15
1008 15
1009 ]
1009 ]
1010 ],
1010 ],
1011 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
1011 b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
1012 },
1012 },
1013 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n',
1013 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n',
1014 {
1014 {
1015 b'path': b'dir0/i',
1015 b'path': b'dir0/i',
1016 b'totalitems': 1
1016 b'totalitems': 1
1017 },
1017 },
1018 {
1018 {
1019 b'fieldsfollowing': [
1019 b'fieldsfollowing': [
1020 [
1020 [
1021 b'revision',
1021 b'revision',
1022 3
1022 3
1023 ]
1023 ]
1024 ],
1024 ],
1025 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
1025 b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
1026 },
1026 },
1027 b'i0\n',
1027 b'i0\n',
1028 {
1028 {
1029 b'path': b'g',
1029 b'path': b'g',
1030 b'totalitems': 1
1030 b'totalitems': 1
1031 },
1031 },
1032 {
1032 {
1033 b'fieldsfollowing': [
1033 b'fieldsfollowing': [
1034 [
1034 [
1035 b'revision',
1035 b'revision',
1036 3
1036 3
1037 ]
1037 ]
1038 ],
1038 ],
1039 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
1039 b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
1040 },
1040 },
1041 b'g0\n',
1041 b'g0\n',
1042 {
1042 {
1043 b'path': b'h',
1043 b'path': b'h',
1044 b'totalitems': 1
1044 b'totalitems': 1
1045 },
1045 },
1046 {
1046 {
1047 b'fieldsfollowing': [
1047 b'fieldsfollowing': [
1048 [
1048 [
1049 b'revision',
1049 b'revision',
1050 3
1050 3
1051 ]
1051 ]
1052 ],
1052 ],
1053 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
1053 b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
1054 },
1054 },
1055 b'h0\n'
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 $ cat error.log
1164 $ cat error.log
@@ -1,1462 +1,1470 b''
1 $ . $TESTDIR/wireprotohelpers.sh
1 $ . $TESTDIR/wireprotohelpers.sh
2
2
3 $ cat >> $HGRCPATH << EOF
3 $ cat >> $HGRCPATH << EOF
4 > [extensions]
4 > [extensions]
5 > blackbox =
5 > blackbox =
6 > [blackbox]
6 > [blackbox]
7 > track = simplecache
7 > track = simplecache
8 > EOF
8 > EOF
9
9
10 $ hg init server
10 $ hg init server
11 $ enablehttpv2 server
11 $ enablehttpv2 server
12 $ cd server
12 $ cd server
13 $ cat >> .hg/hgrc << EOF
13 $ cat >> .hg/hgrc << EOF
14 > [server]
14 > [server]
15 > compressionengines = zlib
15 > compressionengines = zlib
16 > [extensions]
16 > [extensions]
17 > simplecache = $TESTDIR/wireprotosimplecache.py
17 > simplecache = $TESTDIR/wireprotosimplecache.py
18 > [simplecache]
18 > [simplecache]
19 > cacheapi = true
19 > cacheapi = true
20 > EOF
20 > EOF
21
21
22 $ echo a0 > a
22 $ echo a0 > a
23 $ echo b0 > b
23 $ echo b0 > b
24 $ hg -q commit -A -m 'commit 0'
24 $ hg -q commit -A -m 'commit 0'
25 $ echo a1 > a
25 $ echo a1 > a
26 $ hg commit -m 'commit 1'
26 $ hg commit -m 'commit 1'
27
27
28 $ hg --debug debugindex -m
28 $ hg --debug debugindex -m
29 rev linkrev nodeid p1 p2
29 rev linkrev nodeid p1 p2
30 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
30 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
31 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
31 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
32
32
33 $ hg --config simplecache.redirectsfile=redirects.py serve -p $HGPORT -d --pid-file hg.pid -E error.log
33 $ hg --config simplecache.redirectsfile=redirects.py serve -p $HGPORT -d --pid-file hg.pid -E error.log
34 $ cat hg.pid > $DAEMON_PIDS
34 $ cat hg.pid > $DAEMON_PIDS
35
35
36 $ cat > redirects.py << EOF
36 $ cat > redirects.py << EOF
37 > [
37 > [
38 > {
38 > {
39 > b'name': b'target-a',
39 > b'name': b'target-a',
40 > b'protocol': b'http',
40 > b'protocol': b'http',
41 > b'snirequired': False,
41 > b'snirequired': False,
42 > b'tlsversions': [b'1.2', b'1.3'],
42 > b'tlsversions': [b'1.2', b'1.3'],
43 > b'uris': [b'http://example.com/'],
43 > b'uris': [b'http://example.com/'],
44 > },
44 > },
45 > ]
45 > ]
46 > EOF
46 > EOF
47
47
48 Redirect targets advertised when configured
48 Redirect targets advertised when configured
49
49
50 $ sendhttpv2peerhandshake << EOF
50 $ sendhttpv2peerhandshake << EOF
51 > command capabilities
51 > command capabilities
52 > EOF
52 > EOF
53 creating http peer for wire protocol version 2
53 creating http peer for wire protocol version 2
54 s> GET /?cmd=capabilities HTTP/1.1\r\n
54 s> GET /?cmd=capabilities HTTP/1.1\r\n
55 s> Accept-Encoding: identity\r\n
55 s> Accept-Encoding: identity\r\n
56 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
56 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
57 s> x-hgproto-1: cbor\r\n
57 s> x-hgproto-1: cbor\r\n
58 s> x-hgupgrade-1: exp-http-v2-0003\r\n
58 s> x-hgupgrade-1: exp-http-v2-0003\r\n
59 s> accept: application/mercurial-0.1\r\n
59 s> accept: application/mercurial-0.1\r\n
60 s> host: $LOCALIP:$HGPORT\r\n (glob)
60 s> host: $LOCALIP:$HGPORT\r\n (glob)
61 s> user-agent: Mercurial debugwireproto\r\n
61 s> user-agent: Mercurial debugwireproto\r\n
62 s> \r\n
62 s> \r\n
63 s> makefile('rb', None)
63 s> makefile('rb', None)
64 s> HTTP/1.1 200 OK\r\n
64 s> HTTP/1.1 200 OK\r\n
65 s> Server: testing stub value\r\n
65 s> Server: testing stub value\r\n
66 s> Date: $HTTP_DATE$\r\n
66 s> Date: $HTTP_DATE$\r\n
67 s> Content-Type: application/mercurial-cbor\r\n
67 s> Content-Type: application/mercurial-cbor\r\n
68 s> Content-Length: 2241\r\n
68 s> Content-Length: 2259\r\n
69 s> \r\n
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 (remote redirect target target-a is compatible)
71 (remote redirect target target-a is compatible)
72 sending capabilities command
72 sending capabilities command
73 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
73 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
74 s> Accept-Encoding: identity\r\n
74 s> Accept-Encoding: identity\r\n
75 s> accept: application/mercurial-exp-framing-0006\r\n
75 s> accept: application/mercurial-exp-framing-0006\r\n
76 s> content-type: application/mercurial-exp-framing-0006\r\n
76 s> content-type: application/mercurial-exp-framing-0006\r\n
77 s> content-length: 111\r\n
77 s> content-length: 111\r\n
78 s> host: $LOCALIP:$HGPORT\r\n (glob)
78 s> host: $LOCALIP:$HGPORT\r\n (glob)
79 s> user-agent: Mercurial debugwireproto\r\n
79 s> user-agent: Mercurial debugwireproto\r\n
80 s> \r\n
80 s> \r\n
81 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
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 s> makefile('rb', None)
82 s> makefile('rb', None)
83 s> HTTP/1.1 200 OK\r\n
83 s> HTTP/1.1 200 OK\r\n
84 s> Server: testing stub value\r\n
84 s> Server: testing stub value\r\n
85 s> Date: $HTTP_DATE$\r\n
85 s> Date: $HTTP_DATE$\r\n
86 s> Content-Type: application/mercurial-exp-framing-0006\r\n
86 s> Content-Type: application/mercurial-exp-framing-0006\r\n
87 s> Transfer-Encoding: chunked\r\n
87 s> Transfer-Encoding: chunked\r\n
88 s> \r\n
88 s> \r\n
89 s> 11\r\n
89 s> 11\r\n
90 s> \t\x00\x00\x01\x00\x02\x01\x92
90 s> \t\x00\x00\x01\x00\x02\x01\x92
91 s> Hidentity
91 s> Hidentity
92 s> \r\n
92 s> \r\n
93 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
93 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
94 s> 13\r\n
94 s> 13\r\n
95 s> \x0b\x00\x00\x01\x00\x02\x041
95 s> \x0b\x00\x00\x01\x00\x02\x041
96 s> \xa1FstatusBok
96 s> \xa1FstatusBok
97 s> \r\n
97 s> \r\n
98 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
98 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
99 s> 6bf\r\n
99 s> 6d1\r\n
100 s> \xb7\x06\x00\x01\x00\x02\x041
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\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/
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 s> \r\n
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 s> 8\r\n
104 s> 8\r\n
105 s> \x00\x00\x00\x01\x00\x02\x002
105 s> \x00\x00\x00\x01\x00\x02\x002
106 s> \r\n
106 s> \r\n
107 s> 0\r\n
107 s> 0\r\n
108 s> \r\n
108 s> \r\n
109 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
109 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
110 response: gen[
110 response: gen[
111 {
111 {
112 b'commands': {
112 b'commands': {
113 b'branchmap': {
113 b'branchmap': {
114 b'args': {},
114 b'args': {},
115 b'permissions': [
115 b'permissions': [
116 b'pull'
116 b'pull'
117 ]
117 ]
118 },
118 },
119 b'capabilities': {
119 b'capabilities': {
120 b'args': {},
120 b'args': {},
121 b'permissions': [
121 b'permissions': [
122 b'pull'
122 b'pull'
123 ]
123 ]
124 },
124 },
125 b'changesetdata': {
125 b'changesetdata': {
126 b'args': {
126 b'args': {
127 b'fields': {
127 b'fields': {
128 b'default': set([]),
128 b'default': set([]),
129 b'required': False,
129 b'required': False,
130 b'type': b'set',
130 b'type': b'set',
131 b'validvalues': set([
131 b'validvalues': set([
132 b'bookmarks',
132 b'bookmarks',
133 b'parents',
133 b'parents',
134 b'phase',
134 b'phase',
135 b'revision'
135 b'revision'
136 ])
136 ])
137 },
137 },
138 b'revisions': {
138 b'revisions': {
139 b'required': True,
139 b'required': True,
140 b'type': b'list'
140 b'type': b'list'
141 }
141 }
142 },
142 },
143 b'permissions': [
143 b'permissions': [
144 b'pull'
144 b'pull'
145 ]
145 ]
146 },
146 },
147 b'filedata': {
147 b'filedata': {
148 b'args': {
148 b'args': {
149 b'fields': {
149 b'fields': {
150 b'default': set([]),
150 b'default': set([]),
151 b'required': False,
151 b'required': False,
152 b'type': b'set',
152 b'type': b'set',
153 b'validvalues': set([
153 b'validvalues': set([
154 b'linknode',
154 b'parents',
155 b'parents',
155 b'revision'
156 b'revision'
156 ])
157 ])
157 },
158 },
158 b'haveparents': {
159 b'haveparents': {
159 b'default': False,
160 b'default': False,
160 b'required': False,
161 b'required': False,
161 b'type': b'bool'
162 b'type': b'bool'
162 },
163 },
163 b'nodes': {
164 b'nodes': {
164 b'required': True,
165 b'required': True,
165 b'type': b'list'
166 b'type': b'list'
166 },
167 },
167 b'path': {
168 b'path': {
168 b'required': True,
169 b'required': True,
169 b'type': b'bytes'
170 b'type': b'bytes'
170 }
171 }
171 },
172 },
172 b'permissions': [
173 b'permissions': [
173 b'pull'
174 b'pull'
174 ]
175 ]
175 },
176 },
176 b'filesdata': {
177 b'filesdata': {
177 b'args': {
178 b'args': {
178 b'fields': {
179 b'fields': {
179 b'default': set([]),
180 b'default': set([]),
180 b'required': False,
181 b'required': False,
181 b'type': b'set',
182 b'type': b'set',
182 b'validvalues': set([
183 b'validvalues': set([
183 b'firstchangeset',
184 b'firstchangeset',
185 b'linknode',
184 b'parents',
186 b'parents',
185 b'revision'
187 b'revision'
186 ])
188 ])
187 },
189 },
188 b'haveparents': {
190 b'haveparents': {
189 b'default': False,
191 b'default': False,
190 b'required': False,
192 b'required': False,
191 b'type': b'bool'
193 b'type': b'bool'
192 },
194 },
193 b'pathfilter': {
195 b'pathfilter': {
194 b'default': None,
196 b'default': None,
195 b'required': False,
197 b'required': False,
196 b'type': b'dict'
198 b'type': b'dict'
197 },
199 },
198 b'revisions': {
200 b'revisions': {
199 b'required': True,
201 b'required': True,
200 b'type': b'list'
202 b'type': b'list'
201 }
203 }
202 },
204 },
203 b'permissions': [
205 b'permissions': [
204 b'pull'
206 b'pull'
205 ],
207 ],
206 b'recommendedbatchsize': 50000
208 b'recommendedbatchsize': 50000
207 },
209 },
208 b'heads': {
210 b'heads': {
209 b'args': {
211 b'args': {
210 b'publiconly': {
212 b'publiconly': {
211 b'default': False,
213 b'default': False,
212 b'required': False,
214 b'required': False,
213 b'type': b'bool'
215 b'type': b'bool'
214 }
216 }
215 },
217 },
216 b'permissions': [
218 b'permissions': [
217 b'pull'
219 b'pull'
218 ]
220 ]
219 },
221 },
220 b'known': {
222 b'known': {
221 b'args': {
223 b'args': {
222 b'nodes': {
224 b'nodes': {
223 b'default': [],
225 b'default': [],
224 b'required': False,
226 b'required': False,
225 b'type': b'list'
227 b'type': b'list'
226 }
228 }
227 },
229 },
228 b'permissions': [
230 b'permissions': [
229 b'pull'
231 b'pull'
230 ]
232 ]
231 },
233 },
232 b'listkeys': {
234 b'listkeys': {
233 b'args': {
235 b'args': {
234 b'namespace': {
236 b'namespace': {
235 b'required': True,
237 b'required': True,
236 b'type': b'bytes'
238 b'type': b'bytes'
237 }
239 }
238 },
240 },
239 b'permissions': [
241 b'permissions': [
240 b'pull'
242 b'pull'
241 ]
243 ]
242 },
244 },
243 b'lookup': {
245 b'lookup': {
244 b'args': {
246 b'args': {
245 b'key': {
247 b'key': {
246 b'required': True,
248 b'required': True,
247 b'type': b'bytes'
249 b'type': b'bytes'
248 }
250 }
249 },
251 },
250 b'permissions': [
252 b'permissions': [
251 b'pull'
253 b'pull'
252 ]
254 ]
253 },
255 },
254 b'manifestdata': {
256 b'manifestdata': {
255 b'args': {
257 b'args': {
256 b'fields': {
258 b'fields': {
257 b'default': set([]),
259 b'default': set([]),
258 b'required': False,
260 b'required': False,
259 b'type': b'set',
261 b'type': b'set',
260 b'validvalues': set([
262 b'validvalues': set([
261 b'parents',
263 b'parents',
262 b'revision'
264 b'revision'
263 ])
265 ])
264 },
266 },
265 b'haveparents': {
267 b'haveparents': {
266 b'default': False,
268 b'default': False,
267 b'required': False,
269 b'required': False,
268 b'type': b'bool'
270 b'type': b'bool'
269 },
271 },
270 b'nodes': {
272 b'nodes': {
271 b'required': True,
273 b'required': True,
272 b'type': b'list'
274 b'type': b'list'
273 },
275 },
274 b'tree': {
276 b'tree': {
275 b'required': True,
277 b'required': True,
276 b'type': b'bytes'
278 b'type': b'bytes'
277 }
279 }
278 },
280 },
279 b'permissions': [
281 b'permissions': [
280 b'pull'
282 b'pull'
281 ],
283 ],
282 b'recommendedbatchsize': 100000
284 b'recommendedbatchsize': 100000
283 },
285 },
284 b'pushkey': {
286 b'pushkey': {
285 b'args': {
287 b'args': {
286 b'key': {
288 b'key': {
287 b'required': True,
289 b'required': True,
288 b'type': b'bytes'
290 b'type': b'bytes'
289 },
291 },
290 b'namespace': {
292 b'namespace': {
291 b'required': True,
293 b'required': True,
292 b'type': b'bytes'
294 b'type': b'bytes'
293 },
295 },
294 b'new': {
296 b'new': {
295 b'required': True,
297 b'required': True,
296 b'type': b'bytes'
298 b'type': b'bytes'
297 },
299 },
298 b'old': {
300 b'old': {
299 b'required': True,
301 b'required': True,
300 b'type': b'bytes'
302 b'type': b'bytes'
301 }
303 }
302 },
304 },
303 b'permissions': [
305 b'permissions': [
304 b'push'
306 b'push'
305 ]
307 ]
306 },
308 },
307 b'rawstorefiledata': {
309 b'rawstorefiledata': {
308 b'args': {
310 b'args': {
309 b'files': {
311 b'files': {
310 b'required': True,
312 b'required': True,
311 b'type': b'list'
313 b'type': b'list'
312 },
314 },
313 b'pathfilter': {
315 b'pathfilter': {
314 b'default': None,
316 b'default': None,
315 b'required': False,
317 b'required': False,
316 b'type': b'list'
318 b'type': b'list'
317 }
319 }
318 },
320 },
319 b'permissions': [
321 b'permissions': [
320 b'pull'
322 b'pull'
321 ]
323 ]
322 }
324 }
323 },
325 },
324 b'framingmediatypes': [
326 b'framingmediatypes': [
325 b'application/mercurial-exp-framing-0006'
327 b'application/mercurial-exp-framing-0006'
326 ],
328 ],
327 b'pathfilterprefixes': set([
329 b'pathfilterprefixes': set([
328 b'path:',
330 b'path:',
329 b'rootfilesin:'
331 b'rootfilesin:'
330 ]),
332 ]),
331 b'rawrepoformats': [
333 b'rawrepoformats': [
332 b'generaldelta',
334 b'generaldelta',
333 b'revlogv1'
335 b'revlogv1'
334 ],
336 ],
335 b'redirect': {
337 b'redirect': {
336 b'hashes': [
338 b'hashes': [
337 b'sha256',
339 b'sha256',
338 b'sha1'
340 b'sha1'
339 ],
341 ],
340 b'targets': [
342 b'targets': [
341 {
343 {
342 b'name': b'target-a',
344 b'name': b'target-a',
343 b'protocol': b'http',
345 b'protocol': b'http',
344 b'snirequired': False,
346 b'snirequired': False,
345 b'tlsversions': [
347 b'tlsversions': [
346 b'1.2',
348 b'1.2',
347 b'1.3'
349 b'1.3'
348 ],
350 ],
349 b'uris': [
351 b'uris': [
350 b'http://example.com/'
352 b'http://example.com/'
351 ]
353 ]
352 }
354 }
353 ]
355 ]
354 }
356 }
355 }
357 }
356 ]
358 ]
357 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
359 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
358
360
359 Unknown protocol is filtered from compatible targets
361 Unknown protocol is filtered from compatible targets
360
362
361 $ cat > redirects.py << EOF
363 $ cat > redirects.py << EOF
362 > [
364 > [
363 > {
365 > {
364 > b'name': b'target-a',
366 > b'name': b'target-a',
365 > b'protocol': b'http',
367 > b'protocol': b'http',
366 > b'uris': [b'http://example.com/'],
368 > b'uris': [b'http://example.com/'],
367 > },
369 > },
368 > {
370 > {
369 > b'name': b'target-b',
371 > b'name': b'target-b',
370 > b'protocol': b'unknown',
372 > b'protocol': b'unknown',
371 > b'uris': [b'unknown://example.com/'],
373 > b'uris': [b'unknown://example.com/'],
372 > },
374 > },
373 > ]
375 > ]
374 > EOF
376 > EOF
375
377
376 $ sendhttpv2peerhandshake << EOF
378 $ sendhttpv2peerhandshake << EOF
377 > command capabilities
379 > command capabilities
378 > EOF
380 > EOF
379 creating http peer for wire protocol version 2
381 creating http peer for wire protocol version 2
380 s> GET /?cmd=capabilities HTTP/1.1\r\n
382 s> GET /?cmd=capabilities HTTP/1.1\r\n
381 s> Accept-Encoding: identity\r\n
383 s> Accept-Encoding: identity\r\n
382 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
384 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
383 s> x-hgproto-1: cbor\r\n
385 s> x-hgproto-1: cbor\r\n
384 s> x-hgupgrade-1: exp-http-v2-0003\r\n
386 s> x-hgupgrade-1: exp-http-v2-0003\r\n
385 s> accept: application/mercurial-0.1\r\n
387 s> accept: application/mercurial-0.1\r\n
386 s> host: $LOCALIP:$HGPORT\r\n (glob)
388 s> host: $LOCALIP:$HGPORT\r\n (glob)
387 s> user-agent: Mercurial debugwireproto\r\n
389 s> user-agent: Mercurial debugwireproto\r\n
388 s> \r\n
390 s> \r\n
389 s> makefile('rb', None)
391 s> makefile('rb', None)
390 s> HTTP/1.1 200 OK\r\n
392 s> HTTP/1.1 200 OK\r\n
391 s> Server: testing stub value\r\n
393 s> Server: testing stub value\r\n
392 s> Date: $HTTP_DATE$\r\n
394 s> Date: $HTTP_DATE$\r\n
393 s> Content-Type: application/mercurial-cbor\r\n
395 s> Content-Type: application/mercurial-cbor\r\n
394 s> Content-Length: 2268\r\n
396 s> Content-Length: 2286\r\n
395 s> \r\n
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 (remote redirect target target-a is compatible)
399 (remote redirect target target-a is compatible)
398 (remote redirect target target-b uses unsupported protocol: unknown)
400 (remote redirect target target-b uses unsupported protocol: unknown)
399 sending capabilities command
401 sending capabilities command
400 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
402 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
401 s> Accept-Encoding: identity\r\n
403 s> Accept-Encoding: identity\r\n
402 s> accept: application/mercurial-exp-framing-0006\r\n
404 s> accept: application/mercurial-exp-framing-0006\r\n
403 s> content-type: application/mercurial-exp-framing-0006\r\n
405 s> content-type: application/mercurial-exp-framing-0006\r\n
404 s> content-length: 111\r\n
406 s> content-length: 111\r\n
405 s> host: $LOCALIP:$HGPORT\r\n (glob)
407 s> host: $LOCALIP:$HGPORT\r\n (glob)
406 s> user-agent: Mercurial debugwireproto\r\n
408 s> user-agent: Mercurial debugwireproto\r\n
407 s> \r\n
409 s> \r\n
408 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
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 s> makefile('rb', None)
411 s> makefile('rb', None)
410 s> HTTP/1.1 200 OK\r\n
412 s> HTTP/1.1 200 OK\r\n
411 s> Server: testing stub value\r\n
413 s> Server: testing stub value\r\n
412 s> Date: $HTTP_DATE$\r\n
414 s> Date: $HTTP_DATE$\r\n
413 s> Content-Type: application/mercurial-exp-framing-0006\r\n
415 s> Content-Type: application/mercurial-exp-framing-0006\r\n
414 s> Transfer-Encoding: chunked\r\n
416 s> Transfer-Encoding: chunked\r\n
415 s> \r\n
417 s> \r\n
416 s> 11\r\n
418 s> 11\r\n
417 s> \t\x00\x00\x01\x00\x02\x01\x92
419 s> \t\x00\x00\x01\x00\x02\x01\x92
418 s> Hidentity
420 s> Hidentity
419 s> \r\n
421 s> \r\n
420 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
422 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
421 s> 13\r\n
423 s> 13\r\n
422 s> \x0b\x00\x00\x01\x00\x02\x041
424 s> \x0b\x00\x00\x01\x00\x02\x041
423 s> \xa1FstatusBok
425 s> \xa1FstatusBok
424 s> \r\n
426 s> \r\n
425 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
427 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
426 s> 6da\r\n
428 s> 6ec\r\n
427 s> \xd2\x06\x00\x01\x00\x02\x041
429 s> \xe4\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/
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 s> \r\n
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 s> 8\r\n
433 s> 8\r\n
432 s> \x00\x00\x00\x01\x00\x02\x002
434 s> \x00\x00\x00\x01\x00\x02\x002
433 s> \r\n
435 s> \r\n
434 s> 0\r\n
436 s> 0\r\n
435 s> \r\n
437 s> \r\n
436 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
438 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
437 response: gen[
439 response: gen[
438 {
440 {
439 b'commands': {
441 b'commands': {
440 b'branchmap': {
442 b'branchmap': {
441 b'args': {},
443 b'args': {},
442 b'permissions': [
444 b'permissions': [
443 b'pull'
445 b'pull'
444 ]
446 ]
445 },
447 },
446 b'capabilities': {
448 b'capabilities': {
447 b'args': {},
449 b'args': {},
448 b'permissions': [
450 b'permissions': [
449 b'pull'
451 b'pull'
450 ]
452 ]
451 },
453 },
452 b'changesetdata': {
454 b'changesetdata': {
453 b'args': {
455 b'args': {
454 b'fields': {
456 b'fields': {
455 b'default': set([]),
457 b'default': set([]),
456 b'required': False,
458 b'required': False,
457 b'type': b'set',
459 b'type': b'set',
458 b'validvalues': set([
460 b'validvalues': set([
459 b'bookmarks',
461 b'bookmarks',
460 b'parents',
462 b'parents',
461 b'phase',
463 b'phase',
462 b'revision'
464 b'revision'
463 ])
465 ])
464 },
466 },
465 b'revisions': {
467 b'revisions': {
466 b'required': True,
468 b'required': True,
467 b'type': b'list'
469 b'type': b'list'
468 }
470 }
469 },
471 },
470 b'permissions': [
472 b'permissions': [
471 b'pull'
473 b'pull'
472 ]
474 ]
473 },
475 },
474 b'filedata': {
476 b'filedata': {
475 b'args': {
477 b'args': {
476 b'fields': {
478 b'fields': {
477 b'default': set([]),
479 b'default': set([]),
478 b'required': False,
480 b'required': False,
479 b'type': b'set',
481 b'type': b'set',
480 b'validvalues': set([
482 b'validvalues': set([
483 b'linknode',
481 b'parents',
484 b'parents',
482 b'revision'
485 b'revision'
483 ])
486 ])
484 },
487 },
485 b'haveparents': {
488 b'haveparents': {
486 b'default': False,
489 b'default': False,
487 b'required': False,
490 b'required': False,
488 b'type': b'bool'
491 b'type': b'bool'
489 },
492 },
490 b'nodes': {
493 b'nodes': {
491 b'required': True,
494 b'required': True,
492 b'type': b'list'
495 b'type': b'list'
493 },
496 },
494 b'path': {
497 b'path': {
495 b'required': True,
498 b'required': True,
496 b'type': b'bytes'
499 b'type': b'bytes'
497 }
500 }
498 },
501 },
499 b'permissions': [
502 b'permissions': [
500 b'pull'
503 b'pull'
501 ]
504 ]
502 },
505 },
503 b'filesdata': {
506 b'filesdata': {
504 b'args': {
507 b'args': {
505 b'fields': {
508 b'fields': {
506 b'default': set([]),
509 b'default': set([]),
507 b'required': False,
510 b'required': False,
508 b'type': b'set',
511 b'type': b'set',
509 b'validvalues': set([
512 b'validvalues': set([
510 b'firstchangeset',
513 b'firstchangeset',
514 b'linknode',
511 b'parents',
515 b'parents',
512 b'revision'
516 b'revision'
513 ])
517 ])
514 },
518 },
515 b'haveparents': {
519 b'haveparents': {
516 b'default': False,
520 b'default': False,
517 b'required': False,
521 b'required': False,
518 b'type': b'bool'
522 b'type': b'bool'
519 },
523 },
520 b'pathfilter': {
524 b'pathfilter': {
521 b'default': None,
525 b'default': None,
522 b'required': False,
526 b'required': False,
523 b'type': b'dict'
527 b'type': b'dict'
524 },
528 },
525 b'revisions': {
529 b'revisions': {
526 b'required': True,
530 b'required': True,
527 b'type': b'list'
531 b'type': b'list'
528 }
532 }
529 },
533 },
530 b'permissions': [
534 b'permissions': [
531 b'pull'
535 b'pull'
532 ],
536 ],
533 b'recommendedbatchsize': 50000
537 b'recommendedbatchsize': 50000
534 },
538 },
535 b'heads': {
539 b'heads': {
536 b'args': {
540 b'args': {
537 b'publiconly': {
541 b'publiconly': {
538 b'default': False,
542 b'default': False,
539 b'required': False,
543 b'required': False,
540 b'type': b'bool'
544 b'type': b'bool'
541 }
545 }
542 },
546 },
543 b'permissions': [
547 b'permissions': [
544 b'pull'
548 b'pull'
545 ]
549 ]
546 },
550 },
547 b'known': {
551 b'known': {
548 b'args': {
552 b'args': {
549 b'nodes': {
553 b'nodes': {
550 b'default': [],
554 b'default': [],
551 b'required': False,
555 b'required': False,
552 b'type': b'list'
556 b'type': b'list'
553 }
557 }
554 },
558 },
555 b'permissions': [
559 b'permissions': [
556 b'pull'
560 b'pull'
557 ]
561 ]
558 },
562 },
559 b'listkeys': {
563 b'listkeys': {
560 b'args': {
564 b'args': {
561 b'namespace': {
565 b'namespace': {
562 b'required': True,
566 b'required': True,
563 b'type': b'bytes'
567 b'type': b'bytes'
564 }
568 }
565 },
569 },
566 b'permissions': [
570 b'permissions': [
567 b'pull'
571 b'pull'
568 ]
572 ]
569 },
573 },
570 b'lookup': {
574 b'lookup': {
571 b'args': {
575 b'args': {
572 b'key': {
576 b'key': {
573 b'required': True,
577 b'required': True,
574 b'type': b'bytes'
578 b'type': b'bytes'
575 }
579 }
576 },
580 },
577 b'permissions': [
581 b'permissions': [
578 b'pull'
582 b'pull'
579 ]
583 ]
580 },
584 },
581 b'manifestdata': {
585 b'manifestdata': {
582 b'args': {
586 b'args': {
583 b'fields': {
587 b'fields': {
584 b'default': set([]),
588 b'default': set([]),
585 b'required': False,
589 b'required': False,
586 b'type': b'set',
590 b'type': b'set',
587 b'validvalues': set([
591 b'validvalues': set([
588 b'parents',
592 b'parents',
589 b'revision'
593 b'revision'
590 ])
594 ])
591 },
595 },
592 b'haveparents': {
596 b'haveparents': {
593 b'default': False,
597 b'default': False,
594 b'required': False,
598 b'required': False,
595 b'type': b'bool'
599 b'type': b'bool'
596 },
600 },
597 b'nodes': {
601 b'nodes': {
598 b'required': True,
602 b'required': True,
599 b'type': b'list'
603 b'type': b'list'
600 },
604 },
601 b'tree': {
605 b'tree': {
602 b'required': True,
606 b'required': True,
603 b'type': b'bytes'
607 b'type': b'bytes'
604 }
608 }
605 },
609 },
606 b'permissions': [
610 b'permissions': [
607 b'pull'
611 b'pull'
608 ],
612 ],
609 b'recommendedbatchsize': 100000
613 b'recommendedbatchsize': 100000
610 },
614 },
611 b'pushkey': {
615 b'pushkey': {
612 b'args': {
616 b'args': {
613 b'key': {
617 b'key': {
614 b'required': True,
618 b'required': True,
615 b'type': b'bytes'
619 b'type': b'bytes'
616 },
620 },
617 b'namespace': {
621 b'namespace': {
618 b'required': True,
622 b'required': True,
619 b'type': b'bytes'
623 b'type': b'bytes'
620 },
624 },
621 b'new': {
625 b'new': {
622 b'required': True,
626 b'required': True,
623 b'type': b'bytes'
627 b'type': b'bytes'
624 },
628 },
625 b'old': {
629 b'old': {
626 b'required': True,
630 b'required': True,
627 b'type': b'bytes'
631 b'type': b'bytes'
628 }
632 }
629 },
633 },
630 b'permissions': [
634 b'permissions': [
631 b'push'
635 b'push'
632 ]
636 ]
633 },
637 },
634 b'rawstorefiledata': {
638 b'rawstorefiledata': {
635 b'args': {
639 b'args': {
636 b'files': {
640 b'files': {
637 b'required': True,
641 b'required': True,
638 b'type': b'list'
642 b'type': b'list'
639 },
643 },
640 b'pathfilter': {
644 b'pathfilter': {
641 b'default': None,
645 b'default': None,
642 b'required': False,
646 b'required': False,
643 b'type': b'list'
647 b'type': b'list'
644 }
648 }
645 },
649 },
646 b'permissions': [
650 b'permissions': [
647 b'pull'
651 b'pull'
648 ]
652 ]
649 }
653 }
650 },
654 },
651 b'framingmediatypes': [
655 b'framingmediatypes': [
652 b'application/mercurial-exp-framing-0006'
656 b'application/mercurial-exp-framing-0006'
653 ],
657 ],
654 b'pathfilterprefixes': set([
658 b'pathfilterprefixes': set([
655 b'path:',
659 b'path:',
656 b'rootfilesin:'
660 b'rootfilesin:'
657 ]),
661 ]),
658 b'rawrepoformats': [
662 b'rawrepoformats': [
659 b'generaldelta',
663 b'generaldelta',
660 b'revlogv1'
664 b'revlogv1'
661 ],
665 ],
662 b'redirect': {
666 b'redirect': {
663 b'hashes': [
667 b'hashes': [
664 b'sha256',
668 b'sha256',
665 b'sha1'
669 b'sha1'
666 ],
670 ],
667 b'targets': [
671 b'targets': [
668 {
672 {
669 b'name': b'target-a',
673 b'name': b'target-a',
670 b'protocol': b'http',
674 b'protocol': b'http',
671 b'uris': [
675 b'uris': [
672 b'http://example.com/'
676 b'http://example.com/'
673 ]
677 ]
674 },
678 },
675 {
679 {
676 b'name': b'target-b',
680 b'name': b'target-b',
677 b'protocol': b'unknown',
681 b'protocol': b'unknown',
678 b'uris': [
682 b'uris': [
679 b'unknown://example.com/'
683 b'unknown://example.com/'
680 ]
684 ]
681 }
685 }
682 ]
686 ]
683 }
687 }
684 }
688 }
685 ]
689 ]
686 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
690 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
687
691
688 Missing SNI support filters targets that require SNI
692 Missing SNI support filters targets that require SNI
689
693
690 $ cat > nosni.py << EOF
694 $ cat > nosni.py << EOF
691 > from mercurial import sslutil
695 > from mercurial import sslutil
692 > sslutil.hassni = False
696 > sslutil.hassni = False
693 > EOF
697 > EOF
694 $ cat >> $HGRCPATH << EOF
698 $ cat >> $HGRCPATH << EOF
695 > [extensions]
699 > [extensions]
696 > nosni=`pwd`/nosni.py
700 > nosni=`pwd`/nosni.py
697 > EOF
701 > EOF
698
702
699 $ cat > redirects.py << EOF
703 $ cat > redirects.py << EOF
700 > [
704 > [
701 > {
705 > {
702 > b'name': b'target-bad-tls',
706 > b'name': b'target-bad-tls',
703 > b'protocol': b'https',
707 > b'protocol': b'https',
704 > b'uris': [b'https://example.com/'],
708 > b'uris': [b'https://example.com/'],
705 > b'snirequired': True,
709 > b'snirequired': True,
706 > },
710 > },
707 > ]
711 > ]
708 > EOF
712 > EOF
709
713
710 $ sendhttpv2peerhandshake << EOF
714 $ sendhttpv2peerhandshake << EOF
711 > command capabilities
715 > command capabilities
712 > EOF
716 > EOF
713 creating http peer for wire protocol version 2
717 creating http peer for wire protocol version 2
714 s> GET /?cmd=capabilities HTTP/1.1\r\n
718 s> GET /?cmd=capabilities HTTP/1.1\r\n
715 s> Accept-Encoding: identity\r\n
719 s> Accept-Encoding: identity\r\n
716 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
720 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
717 s> x-hgproto-1: cbor\r\n
721 s> x-hgproto-1: cbor\r\n
718 s> x-hgupgrade-1: exp-http-v2-0003\r\n
722 s> x-hgupgrade-1: exp-http-v2-0003\r\n
719 s> accept: application/mercurial-0.1\r\n
723 s> accept: application/mercurial-0.1\r\n
720 s> host: $LOCALIP:$HGPORT\r\n (glob)
724 s> host: $LOCALIP:$HGPORT\r\n (glob)
721 s> user-agent: Mercurial debugwireproto\r\n
725 s> user-agent: Mercurial debugwireproto\r\n
722 s> \r\n
726 s> \r\n
723 s> makefile('rb', None)
727 s> makefile('rb', None)
724 s> HTTP/1.1 200 OK\r\n
728 s> HTTP/1.1 200 OK\r\n
725 s> Server: testing stub value\r\n
729 s> Server: testing stub value\r\n
726 s> Date: $HTTP_DATE$\r\n
730 s> Date: $HTTP_DATE$\r\n
727 s> Content-Type: application/mercurial-cbor\r\n
731 s> Content-Type: application/mercurial-cbor\r\n
728 s> Content-Length: 2228\r\n
732 s> Content-Length: 2246\r\n
729 s> \r\n
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 (redirect target target-bad-tls requires SNI, which is unsupported)
735 (redirect target target-bad-tls requires SNI, which is unsupported)
732 sending capabilities command
736 sending capabilities command
733 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
737 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
734 s> Accept-Encoding: identity\r\n
738 s> Accept-Encoding: identity\r\n
735 s> accept: application/mercurial-exp-framing-0006\r\n
739 s> accept: application/mercurial-exp-framing-0006\r\n
736 s> content-type: application/mercurial-exp-framing-0006\r\n
740 s> content-type: application/mercurial-exp-framing-0006\r\n
737 s> content-length: 102\r\n
741 s> content-length: 102\r\n
738 s> host: $LOCALIP:$HGPORT\r\n (glob)
742 s> host: $LOCALIP:$HGPORT\r\n (glob)
739 s> user-agent: Mercurial debugwireproto\r\n
743 s> user-agent: Mercurial debugwireproto\r\n
740 s> \r\n
744 s> \r\n
741 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
745 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
742 s> makefile('rb', None)
746 s> makefile('rb', None)
743 s> HTTP/1.1 200 OK\r\n
747 s> HTTP/1.1 200 OK\r\n
744 s> Server: testing stub value\r\n
748 s> Server: testing stub value\r\n
745 s> Date: $HTTP_DATE$\r\n
749 s> Date: $HTTP_DATE$\r\n
746 s> Content-Type: application/mercurial-exp-framing-0006\r\n
750 s> Content-Type: application/mercurial-exp-framing-0006\r\n
747 s> Transfer-Encoding: chunked\r\n
751 s> Transfer-Encoding: chunked\r\n
748 s> \r\n
752 s> \r\n
749 s> 11\r\n
753 s> 11\r\n
750 s> \t\x00\x00\x01\x00\x02\x01\x92
754 s> \t\x00\x00\x01\x00\x02\x01\x92
751 s> Hidentity
755 s> Hidentity
752 s> \r\n
756 s> \r\n
753 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
757 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
754 s> 13\r\n
758 s> 13\r\n
755 s> \x0b\x00\x00\x01\x00\x02\x041
759 s> \x0b\x00\x00\x01\x00\x02\x041
756 s> \xa1FstatusBok
760 s> \xa1FstatusBok
757 s> \r\n
761 s> \r\n
758 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
762 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
759 s> 6b2\r\n
763 s> 6c4\r\n
760 s> \xaa\x06\x00\x01\x00\x02\x041
764 s> \xbc\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/
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 s> \r\n
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 s> 8\r\n
768 s> 8\r\n
765 s> \x00\x00\x00\x01\x00\x02\x002
769 s> \x00\x00\x00\x01\x00\x02\x002
766 s> \r\n
770 s> \r\n
767 s> 0\r\n
771 s> 0\r\n
768 s> \r\n
772 s> \r\n
769 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
773 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
770 response: gen[
774 response: gen[
771 {
775 {
772 b'commands': {
776 b'commands': {
773 b'branchmap': {
777 b'branchmap': {
774 b'args': {},
778 b'args': {},
775 b'permissions': [
779 b'permissions': [
776 b'pull'
780 b'pull'
777 ]
781 ]
778 },
782 },
779 b'capabilities': {
783 b'capabilities': {
780 b'args': {},
784 b'args': {},
781 b'permissions': [
785 b'permissions': [
782 b'pull'
786 b'pull'
783 ]
787 ]
784 },
788 },
785 b'changesetdata': {
789 b'changesetdata': {
786 b'args': {
790 b'args': {
787 b'fields': {
791 b'fields': {
788 b'default': set([]),
792 b'default': set([]),
789 b'required': False,
793 b'required': False,
790 b'type': b'set',
794 b'type': b'set',
791 b'validvalues': set([
795 b'validvalues': set([
792 b'bookmarks',
796 b'bookmarks',
793 b'parents',
797 b'parents',
794 b'phase',
798 b'phase',
795 b'revision'
799 b'revision'
796 ])
800 ])
797 },
801 },
798 b'revisions': {
802 b'revisions': {
799 b'required': True,
803 b'required': True,
800 b'type': b'list'
804 b'type': b'list'
801 }
805 }
802 },
806 },
803 b'permissions': [
807 b'permissions': [
804 b'pull'
808 b'pull'
805 ]
809 ]
806 },
810 },
807 b'filedata': {
811 b'filedata': {
808 b'args': {
812 b'args': {
809 b'fields': {
813 b'fields': {
810 b'default': set([]),
814 b'default': set([]),
811 b'required': False,
815 b'required': False,
812 b'type': b'set',
816 b'type': b'set',
813 b'validvalues': set([
817 b'validvalues': set([
818 b'linknode',
814 b'parents',
819 b'parents',
815 b'revision'
820 b'revision'
816 ])
821 ])
817 },
822 },
818 b'haveparents': {
823 b'haveparents': {
819 b'default': False,
824 b'default': False,
820 b'required': False,
825 b'required': False,
821 b'type': b'bool'
826 b'type': b'bool'
822 },
827 },
823 b'nodes': {
828 b'nodes': {
824 b'required': True,
829 b'required': True,
825 b'type': b'list'
830 b'type': b'list'
826 },
831 },
827 b'path': {
832 b'path': {
828 b'required': True,
833 b'required': True,
829 b'type': b'bytes'
834 b'type': b'bytes'
830 }
835 }
831 },
836 },
832 b'permissions': [
837 b'permissions': [
833 b'pull'
838 b'pull'
834 ]
839 ]
835 },
840 },
836 b'filesdata': {
841 b'filesdata': {
837 b'args': {
842 b'args': {
838 b'fields': {
843 b'fields': {
839 b'default': set([]),
844 b'default': set([]),
840 b'required': False,
845 b'required': False,
841 b'type': b'set',
846 b'type': b'set',
842 b'validvalues': set([
847 b'validvalues': set([
843 b'firstchangeset',
848 b'firstchangeset',
849 b'linknode',
844 b'parents',
850 b'parents',
845 b'revision'
851 b'revision'
846 ])
852 ])
847 },
853 },
848 b'haveparents': {
854 b'haveparents': {
849 b'default': False,
855 b'default': False,
850 b'required': False,
856 b'required': False,
851 b'type': b'bool'
857 b'type': b'bool'
852 },
858 },
853 b'pathfilter': {
859 b'pathfilter': {
854 b'default': None,
860 b'default': None,
855 b'required': False,
861 b'required': False,
856 b'type': b'dict'
862 b'type': b'dict'
857 },
863 },
858 b'revisions': {
864 b'revisions': {
859 b'required': True,
865 b'required': True,
860 b'type': b'list'
866 b'type': b'list'
861 }
867 }
862 },
868 },
863 b'permissions': [
869 b'permissions': [
864 b'pull'
870 b'pull'
865 ],
871 ],
866 b'recommendedbatchsize': 50000
872 b'recommendedbatchsize': 50000
867 },
873 },
868 b'heads': {
874 b'heads': {
869 b'args': {
875 b'args': {
870 b'publiconly': {
876 b'publiconly': {
871 b'default': False,
877 b'default': False,
872 b'required': False,
878 b'required': False,
873 b'type': b'bool'
879 b'type': b'bool'
874 }
880 }
875 },
881 },
876 b'permissions': [
882 b'permissions': [
877 b'pull'
883 b'pull'
878 ]
884 ]
879 },
885 },
880 b'known': {
886 b'known': {
881 b'args': {
887 b'args': {
882 b'nodes': {
888 b'nodes': {
883 b'default': [],
889 b'default': [],
884 b'required': False,
890 b'required': False,
885 b'type': b'list'
891 b'type': b'list'
886 }
892 }
887 },
893 },
888 b'permissions': [
894 b'permissions': [
889 b'pull'
895 b'pull'
890 ]
896 ]
891 },
897 },
892 b'listkeys': {
898 b'listkeys': {
893 b'args': {
899 b'args': {
894 b'namespace': {
900 b'namespace': {
895 b'required': True,
901 b'required': True,
896 b'type': b'bytes'
902 b'type': b'bytes'
897 }
903 }
898 },
904 },
899 b'permissions': [
905 b'permissions': [
900 b'pull'
906 b'pull'
901 ]
907 ]
902 },
908 },
903 b'lookup': {
909 b'lookup': {
904 b'args': {
910 b'args': {
905 b'key': {
911 b'key': {
906 b'required': True,
912 b'required': True,
907 b'type': b'bytes'
913 b'type': b'bytes'
908 }
914 }
909 },
915 },
910 b'permissions': [
916 b'permissions': [
911 b'pull'
917 b'pull'
912 ]
918 ]
913 },
919 },
914 b'manifestdata': {
920 b'manifestdata': {
915 b'args': {
921 b'args': {
916 b'fields': {
922 b'fields': {
917 b'default': set([]),
923 b'default': set([]),
918 b'required': False,
924 b'required': False,
919 b'type': b'set',
925 b'type': b'set',
920 b'validvalues': set([
926 b'validvalues': set([
921 b'parents',
927 b'parents',
922 b'revision'
928 b'revision'
923 ])
929 ])
924 },
930 },
925 b'haveparents': {
931 b'haveparents': {
926 b'default': False,
932 b'default': False,
927 b'required': False,
933 b'required': False,
928 b'type': b'bool'
934 b'type': b'bool'
929 },
935 },
930 b'nodes': {
936 b'nodes': {
931 b'required': True,
937 b'required': True,
932 b'type': b'list'
938 b'type': b'list'
933 },
939 },
934 b'tree': {
940 b'tree': {
935 b'required': True,
941 b'required': True,
936 b'type': b'bytes'
942 b'type': b'bytes'
937 }
943 }
938 },
944 },
939 b'permissions': [
945 b'permissions': [
940 b'pull'
946 b'pull'
941 ],
947 ],
942 b'recommendedbatchsize': 100000
948 b'recommendedbatchsize': 100000
943 },
949 },
944 b'pushkey': {
950 b'pushkey': {
945 b'args': {
951 b'args': {
946 b'key': {
952 b'key': {
947 b'required': True,
953 b'required': True,
948 b'type': b'bytes'
954 b'type': b'bytes'
949 },
955 },
950 b'namespace': {
956 b'namespace': {
951 b'required': True,
957 b'required': True,
952 b'type': b'bytes'
958 b'type': b'bytes'
953 },
959 },
954 b'new': {
960 b'new': {
955 b'required': True,
961 b'required': True,
956 b'type': b'bytes'
962 b'type': b'bytes'
957 },
963 },
958 b'old': {
964 b'old': {
959 b'required': True,
965 b'required': True,
960 b'type': b'bytes'
966 b'type': b'bytes'
961 }
967 }
962 },
968 },
963 b'permissions': [
969 b'permissions': [
964 b'push'
970 b'push'
965 ]
971 ]
966 },
972 },
967 b'rawstorefiledata': {
973 b'rawstorefiledata': {
968 b'args': {
974 b'args': {
969 b'files': {
975 b'files': {
970 b'required': True,
976 b'required': True,
971 b'type': b'list'
977 b'type': b'list'
972 },
978 },
973 b'pathfilter': {
979 b'pathfilter': {
974 b'default': None,
980 b'default': None,
975 b'required': False,
981 b'required': False,
976 b'type': b'list'
982 b'type': b'list'
977 }
983 }
978 },
984 },
979 b'permissions': [
985 b'permissions': [
980 b'pull'
986 b'pull'
981 ]
987 ]
982 }
988 }
983 },
989 },
984 b'framingmediatypes': [
990 b'framingmediatypes': [
985 b'application/mercurial-exp-framing-0006'
991 b'application/mercurial-exp-framing-0006'
986 ],
992 ],
987 b'pathfilterprefixes': set([
993 b'pathfilterprefixes': set([
988 b'path:',
994 b'path:',
989 b'rootfilesin:'
995 b'rootfilesin:'
990 ]),
996 ]),
991 b'rawrepoformats': [
997 b'rawrepoformats': [
992 b'generaldelta',
998 b'generaldelta',
993 b'revlogv1'
999 b'revlogv1'
994 ],
1000 ],
995 b'redirect': {
1001 b'redirect': {
996 b'hashes': [
1002 b'hashes': [
997 b'sha256',
1003 b'sha256',
998 b'sha1'
1004 b'sha1'
999 ],
1005 ],
1000 b'targets': [
1006 b'targets': [
1001 {
1007 {
1002 b'name': b'target-bad-tls',
1008 b'name': b'target-bad-tls',
1003 b'protocol': b'https',
1009 b'protocol': b'https',
1004 b'snirequired': True,
1010 b'snirequired': True,
1005 b'uris': [
1011 b'uris': [
1006 b'https://example.com/'
1012 b'https://example.com/'
1007 ]
1013 ]
1008 }
1014 }
1009 ]
1015 ]
1010 }
1016 }
1011 }
1017 }
1012 ]
1018 ]
1013 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1019 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1014
1020
1015 $ cat >> $HGRCPATH << EOF
1021 $ cat >> $HGRCPATH << EOF
1016 > [extensions]
1022 > [extensions]
1017 > nosni=!
1023 > nosni=!
1018 > EOF
1024 > EOF
1019
1025
1020 Unknown tls value is filtered from compatible targets
1026 Unknown tls value is filtered from compatible targets
1021
1027
1022 $ cat > redirects.py << EOF
1028 $ cat > redirects.py << EOF
1023 > [
1029 > [
1024 > {
1030 > {
1025 > b'name': b'target-bad-tls',
1031 > b'name': b'target-bad-tls',
1026 > b'protocol': b'https',
1032 > b'protocol': b'https',
1027 > b'uris': [b'https://example.com/'],
1033 > b'uris': [b'https://example.com/'],
1028 > b'tlsversions': [b'42', b'39'],
1034 > b'tlsversions': [b'42', b'39'],
1029 > },
1035 > },
1030 > ]
1036 > ]
1031 > EOF
1037 > EOF
1032
1038
1033 $ sendhttpv2peerhandshake << EOF
1039 $ sendhttpv2peerhandshake << EOF
1034 > command capabilities
1040 > command capabilities
1035 > EOF
1041 > EOF
1036 creating http peer for wire protocol version 2
1042 creating http peer for wire protocol version 2
1037 s> GET /?cmd=capabilities HTTP/1.1\r\n
1043 s> GET /?cmd=capabilities HTTP/1.1\r\n
1038 s> Accept-Encoding: identity\r\n
1044 s> Accept-Encoding: identity\r\n
1039 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
1045 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
1040 s> x-hgproto-1: cbor\r\n
1046 s> x-hgproto-1: cbor\r\n
1041 s> x-hgupgrade-1: exp-http-v2-0003\r\n
1047 s> x-hgupgrade-1: exp-http-v2-0003\r\n
1042 s> accept: application/mercurial-0.1\r\n
1048 s> accept: application/mercurial-0.1\r\n
1043 s> host: $LOCALIP:$HGPORT\r\n (glob)
1049 s> host: $LOCALIP:$HGPORT\r\n (glob)
1044 s> user-agent: Mercurial debugwireproto\r\n
1050 s> user-agent: Mercurial debugwireproto\r\n
1045 s> \r\n
1051 s> \r\n
1046 s> makefile('rb', None)
1052 s> makefile('rb', None)
1047 s> HTTP/1.1 200 OK\r\n
1053 s> HTTP/1.1 200 OK\r\n
1048 s> Server: testing stub value\r\n
1054 s> Server: testing stub value\r\n
1049 s> Date: $HTTP_DATE$\r\n
1055 s> Date: $HTTP_DATE$\r\n
1050 s> Content-Type: application/mercurial-cbor\r\n
1056 s> Content-Type: application/mercurial-cbor\r\n
1051 s> Content-Length: 2234\r\n
1057 s> Content-Length: 2252\r\n
1052 s> \r\n
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 (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42)
1060 (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42)
1055 sending capabilities command
1061 sending capabilities command
1056 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
1062 s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
1057 s> Accept-Encoding: identity\r\n
1063 s> Accept-Encoding: identity\r\n
1058 s> accept: application/mercurial-exp-framing-0006\r\n
1064 s> accept: application/mercurial-exp-framing-0006\r\n
1059 s> content-type: application/mercurial-exp-framing-0006\r\n
1065 s> content-type: application/mercurial-exp-framing-0006\r\n
1060 s> content-length: 102\r\n
1066 s> content-length: 102\r\n
1061 s> host: $LOCALIP:$HGPORT\r\n (glob)
1067 s> host: $LOCALIP:$HGPORT\r\n (glob)
1062 s> user-agent: Mercurial debugwireproto\r\n
1068 s> user-agent: Mercurial debugwireproto\r\n
1063 s> \r\n
1069 s> \r\n
1064 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
1070 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
1065 s> makefile('rb', None)
1071 s> makefile('rb', None)
1066 s> HTTP/1.1 200 OK\r\n
1072 s> HTTP/1.1 200 OK\r\n
1067 s> Server: testing stub value\r\n
1073 s> Server: testing stub value\r\n
1068 s> Date: $HTTP_DATE$\r\n
1074 s> Date: $HTTP_DATE$\r\n
1069 s> Content-Type: application/mercurial-exp-framing-0006\r\n
1075 s> Content-Type: application/mercurial-exp-framing-0006\r\n
1070 s> Transfer-Encoding: chunked\r\n
1076 s> Transfer-Encoding: chunked\r\n
1071 s> \r\n
1077 s> \r\n
1072 s> 11\r\n
1078 s> 11\r\n
1073 s> \t\x00\x00\x01\x00\x02\x01\x92
1079 s> \t\x00\x00\x01\x00\x02\x01\x92
1074 s> Hidentity
1080 s> Hidentity
1075 s> \r\n
1081 s> \r\n
1076 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
1082 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
1077 s> 13\r\n
1083 s> 13\r\n
1078 s> \x0b\x00\x00\x01\x00\x02\x041
1084 s> \x0b\x00\x00\x01\x00\x02\x041
1079 s> \xa1FstatusBok
1085 s> \xa1FstatusBok
1080 s> \r\n
1086 s> \r\n
1081 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
1087 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
1082 s> 6b8\r\n
1088 s> 6ca\r\n
1083 s> \xb0\x06\x00\x01\x00\x02\x041
1089 s> \xc2\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/
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 s> \r\n
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 s> 8\r\n
1093 s> 8\r\n
1088 s> \x00\x00\x00\x01\x00\x02\x002
1094 s> \x00\x00\x00\x01\x00\x02\x002
1089 s> \r\n
1095 s> \r\n
1090 s> 0\r\n
1096 s> 0\r\n
1091 s> \r\n
1097 s> \r\n
1092 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
1098 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
1093 response: gen[
1099 response: gen[
1094 {
1100 {
1095 b'commands': {
1101 b'commands': {
1096 b'branchmap': {
1102 b'branchmap': {
1097 b'args': {},
1103 b'args': {},
1098 b'permissions': [
1104 b'permissions': [
1099 b'pull'
1105 b'pull'
1100 ]
1106 ]
1101 },
1107 },
1102 b'capabilities': {
1108 b'capabilities': {
1103 b'args': {},
1109 b'args': {},
1104 b'permissions': [
1110 b'permissions': [
1105 b'pull'
1111 b'pull'
1106 ]
1112 ]
1107 },
1113 },
1108 b'changesetdata': {
1114 b'changesetdata': {
1109 b'args': {
1115 b'args': {
1110 b'fields': {
1116 b'fields': {
1111 b'default': set([]),
1117 b'default': set([]),
1112 b'required': False,
1118 b'required': False,
1113 b'type': b'set',
1119 b'type': b'set',
1114 b'validvalues': set([
1120 b'validvalues': set([
1115 b'bookmarks',
1121 b'bookmarks',
1116 b'parents',
1122 b'parents',
1117 b'phase',
1123 b'phase',
1118 b'revision'
1124 b'revision'
1119 ])
1125 ])
1120 },
1126 },
1121 b'revisions': {
1127 b'revisions': {
1122 b'required': True,
1128 b'required': True,
1123 b'type': b'list'
1129 b'type': b'list'
1124 }
1130 }
1125 },
1131 },
1126 b'permissions': [
1132 b'permissions': [
1127 b'pull'
1133 b'pull'
1128 ]
1134 ]
1129 },
1135 },
1130 b'filedata': {
1136 b'filedata': {
1131 b'args': {
1137 b'args': {
1132 b'fields': {
1138 b'fields': {
1133 b'default': set([]),
1139 b'default': set([]),
1134 b'required': False,
1140 b'required': False,
1135 b'type': b'set',
1141 b'type': b'set',
1136 b'validvalues': set([
1142 b'validvalues': set([
1143 b'linknode',
1137 b'parents',
1144 b'parents',
1138 b'revision'
1145 b'revision'
1139 ])
1146 ])
1140 },
1147 },
1141 b'haveparents': {
1148 b'haveparents': {
1142 b'default': False,
1149 b'default': False,
1143 b'required': False,
1150 b'required': False,
1144 b'type': b'bool'
1151 b'type': b'bool'
1145 },
1152 },
1146 b'nodes': {
1153 b'nodes': {
1147 b'required': True,
1154 b'required': True,
1148 b'type': b'list'
1155 b'type': b'list'
1149 },
1156 },
1150 b'path': {
1157 b'path': {
1151 b'required': True,
1158 b'required': True,
1152 b'type': b'bytes'
1159 b'type': b'bytes'
1153 }
1160 }
1154 },
1161 },
1155 b'permissions': [
1162 b'permissions': [
1156 b'pull'
1163 b'pull'
1157 ]
1164 ]
1158 },
1165 },
1159 b'filesdata': {
1166 b'filesdata': {
1160 b'args': {
1167 b'args': {
1161 b'fields': {
1168 b'fields': {
1162 b'default': set([]),
1169 b'default': set([]),
1163 b'required': False,
1170 b'required': False,
1164 b'type': b'set',
1171 b'type': b'set',
1165 b'validvalues': set([
1172 b'validvalues': set([
1166 b'firstchangeset',
1173 b'firstchangeset',
1174 b'linknode',
1167 b'parents',
1175 b'parents',
1168 b'revision'
1176 b'revision'
1169 ])
1177 ])
1170 },
1178 },
1171 b'haveparents': {
1179 b'haveparents': {
1172 b'default': False,
1180 b'default': False,
1173 b'required': False,
1181 b'required': False,
1174 b'type': b'bool'
1182 b'type': b'bool'
1175 },
1183 },
1176 b'pathfilter': {
1184 b'pathfilter': {
1177 b'default': None,
1185 b'default': None,
1178 b'required': False,
1186 b'required': False,
1179 b'type': b'dict'
1187 b'type': b'dict'
1180 },
1188 },
1181 b'revisions': {
1189 b'revisions': {
1182 b'required': True,
1190 b'required': True,
1183 b'type': b'list'
1191 b'type': b'list'
1184 }
1192 }
1185 },
1193 },
1186 b'permissions': [
1194 b'permissions': [
1187 b'pull'
1195 b'pull'
1188 ],
1196 ],
1189 b'recommendedbatchsize': 50000
1197 b'recommendedbatchsize': 50000
1190 },
1198 },
1191 b'heads': {
1199 b'heads': {
1192 b'args': {
1200 b'args': {
1193 b'publiconly': {
1201 b'publiconly': {
1194 b'default': False,
1202 b'default': False,
1195 b'required': False,
1203 b'required': False,
1196 b'type': b'bool'
1204 b'type': b'bool'
1197 }
1205 }
1198 },
1206 },
1199 b'permissions': [
1207 b'permissions': [
1200 b'pull'
1208 b'pull'
1201 ]
1209 ]
1202 },
1210 },
1203 b'known': {
1211 b'known': {
1204 b'args': {
1212 b'args': {
1205 b'nodes': {
1213 b'nodes': {
1206 b'default': [],
1214 b'default': [],
1207 b'required': False,
1215 b'required': False,
1208 b'type': b'list'
1216 b'type': b'list'
1209 }
1217 }
1210 },
1218 },
1211 b'permissions': [
1219 b'permissions': [
1212 b'pull'
1220 b'pull'
1213 ]
1221 ]
1214 },
1222 },
1215 b'listkeys': {
1223 b'listkeys': {
1216 b'args': {
1224 b'args': {
1217 b'namespace': {
1225 b'namespace': {
1218 b'required': True,
1226 b'required': True,
1219 b'type': b'bytes'
1227 b'type': b'bytes'
1220 }
1228 }
1221 },
1229 },
1222 b'permissions': [
1230 b'permissions': [
1223 b'pull'
1231 b'pull'
1224 ]
1232 ]
1225 },
1233 },
1226 b'lookup': {
1234 b'lookup': {
1227 b'args': {
1235 b'args': {
1228 b'key': {
1236 b'key': {
1229 b'required': True,
1237 b'required': True,
1230 b'type': b'bytes'
1238 b'type': b'bytes'
1231 }
1239 }
1232 },
1240 },
1233 b'permissions': [
1241 b'permissions': [
1234 b'pull'
1242 b'pull'
1235 ]
1243 ]
1236 },
1244 },
1237 b'manifestdata': {
1245 b'manifestdata': {
1238 b'args': {
1246 b'args': {
1239 b'fields': {
1247 b'fields': {
1240 b'default': set([]),
1248 b'default': set([]),
1241 b'required': False,
1249 b'required': False,
1242 b'type': b'set',
1250 b'type': b'set',
1243 b'validvalues': set([
1251 b'validvalues': set([
1244 b'parents',
1252 b'parents',
1245 b'revision'
1253 b'revision'
1246 ])
1254 ])
1247 },
1255 },
1248 b'haveparents': {
1256 b'haveparents': {
1249 b'default': False,
1257 b'default': False,
1250 b'required': False,
1258 b'required': False,
1251 b'type': b'bool'
1259 b'type': b'bool'
1252 },
1260 },
1253 b'nodes': {
1261 b'nodes': {
1254 b'required': True,
1262 b'required': True,
1255 b'type': b'list'
1263 b'type': b'list'
1256 },
1264 },
1257 b'tree': {
1265 b'tree': {
1258 b'required': True,
1266 b'required': True,
1259 b'type': b'bytes'
1267 b'type': b'bytes'
1260 }
1268 }
1261 },
1269 },
1262 b'permissions': [
1270 b'permissions': [
1263 b'pull'
1271 b'pull'
1264 ],
1272 ],
1265 b'recommendedbatchsize': 100000
1273 b'recommendedbatchsize': 100000
1266 },
1274 },
1267 b'pushkey': {
1275 b'pushkey': {
1268 b'args': {
1276 b'args': {
1269 b'key': {
1277 b'key': {
1270 b'required': True,
1278 b'required': True,
1271 b'type': b'bytes'
1279 b'type': b'bytes'
1272 },
1280 },
1273 b'namespace': {
1281 b'namespace': {
1274 b'required': True,
1282 b'required': True,
1275 b'type': b'bytes'
1283 b'type': b'bytes'
1276 },
1284 },
1277 b'new': {
1285 b'new': {
1278 b'required': True,
1286 b'required': True,
1279 b'type': b'bytes'
1287 b'type': b'bytes'
1280 },
1288 },
1281 b'old': {
1289 b'old': {
1282 b'required': True,
1290 b'required': True,
1283 b'type': b'bytes'
1291 b'type': b'bytes'
1284 }
1292 }
1285 },
1293 },
1286 b'permissions': [
1294 b'permissions': [
1287 b'push'
1295 b'push'
1288 ]
1296 ]
1289 },
1297 },
1290 b'rawstorefiledata': {
1298 b'rawstorefiledata': {
1291 b'args': {
1299 b'args': {
1292 b'files': {
1300 b'files': {
1293 b'required': True,
1301 b'required': True,
1294 b'type': b'list'
1302 b'type': b'list'
1295 },
1303 },
1296 b'pathfilter': {
1304 b'pathfilter': {
1297 b'default': None,
1305 b'default': None,
1298 b'required': False,
1306 b'required': False,
1299 b'type': b'list'
1307 b'type': b'list'
1300 }
1308 }
1301 },
1309 },
1302 b'permissions': [
1310 b'permissions': [
1303 b'pull'
1311 b'pull'
1304 ]
1312 ]
1305 }
1313 }
1306 },
1314 },
1307 b'framingmediatypes': [
1315 b'framingmediatypes': [
1308 b'application/mercurial-exp-framing-0006'
1316 b'application/mercurial-exp-framing-0006'
1309 ],
1317 ],
1310 b'pathfilterprefixes': set([
1318 b'pathfilterprefixes': set([
1311 b'path:',
1319 b'path:',
1312 b'rootfilesin:'
1320 b'rootfilesin:'
1313 ]),
1321 ]),
1314 b'rawrepoformats': [
1322 b'rawrepoformats': [
1315 b'generaldelta',
1323 b'generaldelta',
1316 b'revlogv1'
1324 b'revlogv1'
1317 ],
1325 ],
1318 b'redirect': {
1326 b'redirect': {
1319 b'hashes': [
1327 b'hashes': [
1320 b'sha256',
1328 b'sha256',
1321 b'sha1'
1329 b'sha1'
1322 ],
1330 ],
1323 b'targets': [
1331 b'targets': [
1324 {
1332 {
1325 b'name': b'target-bad-tls',
1333 b'name': b'target-bad-tls',
1326 b'protocol': b'https',
1334 b'protocol': b'https',
1327 b'tlsversions': [
1335 b'tlsversions': [
1328 b'42',
1336 b'42',
1329 b'39'
1337 b'39'
1330 ],
1338 ],
1331 b'uris': [
1339 b'uris': [
1332 b'https://example.com/'
1340 b'https://example.com/'
1333 ]
1341 ]
1334 }
1342 }
1335 ]
1343 ]
1336 }
1344 }
1337 }
1345 }
1338 ]
1346 ]
1339 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1347 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1340
1348
1341 Set up the server to issue content redirects to its built-in API server.
1349 Set up the server to issue content redirects to its built-in API server.
1342
1350
1343 $ cat > redirects.py << EOF
1351 $ cat > redirects.py << EOF
1344 > [
1352 > [
1345 > {
1353 > {
1346 > b'name': b'local',
1354 > b'name': b'local',
1347 > b'protocol': b'http',
1355 > b'protocol': b'http',
1348 > b'uris': [b'http://example.com/'],
1356 > b'uris': [b'http://example.com/'],
1349 > },
1357 > },
1350 > ]
1358 > ]
1351 > EOF
1359 > EOF
1352
1360
1353 Request to eventual cache URL should return 404 (validating the cache server works)
1361 Request to eventual cache URL should return 404 (validating the cache server works)
1354
1362
1355 $ sendhttpraw << EOF
1363 $ sendhttpraw << EOF
1356 > httprequest GET api/simplecache/missingkey
1364 > httprequest GET api/simplecache/missingkey
1357 > user-agent: test
1365 > user-agent: test
1358 > EOF
1366 > EOF
1359 using raw connection to peer
1367 using raw connection to peer
1360 s> GET /api/simplecache/missingkey HTTP/1.1\r\n
1368 s> GET /api/simplecache/missingkey HTTP/1.1\r\n
1361 s> Accept-Encoding: identity\r\n
1369 s> Accept-Encoding: identity\r\n
1362 s> user-agent: test\r\n
1370 s> user-agent: test\r\n
1363 s> host: $LOCALIP:$HGPORT\r\n (glob)
1371 s> host: $LOCALIP:$HGPORT\r\n (glob)
1364 s> \r\n
1372 s> \r\n
1365 s> makefile('rb', None)
1373 s> makefile('rb', None)
1366 s> HTTP/1.1 404 Not Found\r\n
1374 s> HTTP/1.1 404 Not Found\r\n
1367 s> Server: testing stub value\r\n
1375 s> Server: testing stub value\r\n
1368 s> Date: $HTTP_DATE$\r\n
1376 s> Date: $HTTP_DATE$\r\n
1369 s> Content-Type: text/plain\r\n
1377 s> Content-Type: text/plain\r\n
1370 s> Content-Length: 22\r\n
1378 s> Content-Length: 22\r\n
1371 s> \r\n
1379 s> \r\n
1372 s> key not found in cache
1380 s> key not found in cache
1373
1381
1374 Send a cacheable request
1382 Send a cacheable request
1375
1383
1376 $ sendhttpv2peer << EOF
1384 $ sendhttpv2peer << EOF
1377 > command manifestdata
1385 > command manifestdata
1378 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
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 > tree eval:b''
1387 > tree eval:b''
1380 > fields eval:[b'parents']
1388 > fields eval:[b'parents']
1381 > EOF
1389 > EOF
1382 creating http peer for wire protocol version 2
1390 creating http peer for wire protocol version 2
1383 sending manifestdata command
1391 sending manifestdata command
1384 response: gen[
1392 response: gen[
1385 {
1393 {
1386 b'totalitems': 1
1394 b'totalitems': 1
1387 },
1395 },
1388 {
1396 {
1389 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1397 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1390 b'parents': [
1398 b'parents': [
1391 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1399 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1392 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 Cached entry should be available on server
1405 Cached entry should be available on server
1398
1406
1399 $ sendhttpraw << EOF
1407 $ sendhttpraw << EOF
1400 > httprequest GET api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c
1408 > httprequest GET api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c
1401 > user-agent: test
1409 > user-agent: test
1402 > EOF
1410 > EOF
1403 using raw connection to peer
1411 using raw connection to peer
1404 s> GET /api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c HTTP/1.1\r\n
1412 s> GET /api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c HTTP/1.1\r\n
1405 s> Accept-Encoding: identity\r\n
1413 s> Accept-Encoding: identity\r\n
1406 s> user-agent: test\r\n
1414 s> user-agent: test\r\n
1407 s> host: $LOCALIP:$HGPORT\r\n (glob)
1415 s> host: $LOCALIP:$HGPORT\r\n (glob)
1408 s> \r\n
1416 s> \r\n
1409 s> makefile('rb', None)
1417 s> makefile('rb', None)
1410 s> HTTP/1.1 200 OK\r\n
1418 s> HTTP/1.1 200 OK\r\n
1411 s> Server: testing stub value\r\n
1419 s> Server: testing stub value\r\n
1412 s> Date: $HTTP_DATE$\r\n
1420 s> Date: $HTTP_DATE$\r\n
1413 s> Content-Type: application/mercurial-cbor\r\n
1421 s> Content-Type: application/mercurial-cbor\r\n
1414 s> Content-Length: 91\r\n
1422 s> Content-Length: 91\r\n
1415 s> \r\n
1423 s> \r\n
1416 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
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 cbor> [
1425 cbor> [
1418 {
1426 {
1419 b'totalitems': 1
1427 b'totalitems': 1
1420 },
1428 },
1421 {
1429 {
1422 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1430 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1423 b'parents': [
1431 b'parents': [
1424 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1432 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1425 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 2nd request should result in content redirect response
1438 2nd request should result in content redirect response
1431
1439
1432 $ sendhttpv2peer << EOF
1440 $ sendhttpv2peer << EOF
1433 > command manifestdata
1441 > command manifestdata
1434 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
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 > tree eval:b''
1443 > tree eval:b''
1436 > fields eval:[b'parents']
1444 > fields eval:[b'parents']
1437 > EOF
1445 > EOF
1438 creating http peer for wire protocol version 2
1446 creating http peer for wire protocol version 2
1439 sending manifestdata command
1447 sending manifestdata command
1440 response: gen[
1448 response: gen[
1441 {
1449 {
1442 b'totalitems': 1
1450 b'totalitems': 1
1443 },
1451 },
1444 {
1452 {
1445 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1453 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1446 b'parents': [
1454 b'parents': [
1447 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1455 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1448 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
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 $ cat error.log
1461 $ cat error.log
1454 $ killdaemons.py
1462 $ killdaemons.py
1455
1463
1456 $ cat .hg/blackbox.log
1464 $ cat .hg/blackbox.log
1457 *> cacher constructed for manifestdata (glob)
1465 *> cacher constructed for manifestdata (glob)
1458 *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1466 *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1459 *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1467 *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1460 *> cacher constructed for manifestdata (glob)
1468 *> cacher constructed for manifestdata (glob)
1461 *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1469 *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
1462 *> sending content redirect for 47abb8efa5f01b8964d74917793ad2464db0fa2c to http://*:$HGPORT/api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
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