##// END OF EJS Templates
wireprotov2: remove "compression" from capabilities response...
Gregory Szorc -
r40158:9b19b8ce default
parent child Browse files
Show More
@@ -1,539 +1,529
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 compression
91 An array of maps defining available compression format support.
92
93 The array is sorted from most preferred to least preferred.
94
95 Each entry has the following bytestring keys:
96
97 name
98 Name of the compression engine. e.g. ``zstd`` or ``zlib``.
99
100 framingmediatypes
90 framingmediatypes
101 An array of bytestrings defining the supported framing protocol
91 An array of bytestrings defining the supported framing protocol
102 media types. Servers will not accept media types not in this list.
92 media types. Servers will not accept media types not in this list.
103
93
104 pathfilterprefixes
94 pathfilterprefixes
105 (set of bytestring) Matcher prefixes that are recognized when performing
95 (set of bytestring) Matcher prefixes that are recognized when performing
106 path filtering. Specifying a path filter whose type/prefix does not
96 path filtering. Specifying a path filter whose type/prefix does not
107 match one in this set will likely be rejected by the server.
97 match one in this set will likely be rejected by the server.
108
98
109 rawrepoformats
99 rawrepoformats
110 An array of storage formats the repository is using. This set of
100 An array of storage formats the repository is using. This set of
111 requirements can be used to determine whether a client can read a
101 requirements can be used to determine whether a client can read a
112 *raw* copy of file data available.
102 *raw* copy of file data available.
113
103
114 redirect
104 redirect
115 A map declaring potential *content redirects* that may be used by this
105 A map declaring potential *content redirects* that may be used by this
116 server. Contains the following bytestring keys:
106 server. Contains the following bytestring keys:
117
107
118 targets
108 targets
119 (array of maps) Potential redirect targets. Values are maps describing
109 (array of maps) Potential redirect targets. Values are maps describing
120 this target in more detail. Each map has the following bytestring keys:
110 this target in more detail. Each map has the following bytestring keys:
121
111
122 name
112 name
123 (bytestring) Identifier for this target. The identifier will be used
113 (bytestring) Identifier for this target. The identifier will be used
124 by clients to uniquely identify this target.
114 by clients to uniquely identify this target.
125
115
126 protocol
116 protocol
127 (bytestring) High-level network protocol. Values can be
117 (bytestring) High-level network protocol. Values can be
128 ``http``, ```https``, ``ssh``, etc.
118 ``http``, ```https``, ``ssh``, etc.
129
119
130 uris
120 uris
131 (array of bytestrings) Representative URIs for this target.
121 (array of bytestrings) Representative URIs for this target.
132
122
133 snirequired (optional)
123 snirequired (optional)
134 (boolean) Indicates whether Server Name Indication is required
124 (boolean) Indicates whether Server Name Indication is required
135 to use this target. Defaults to False.
125 to use this target. Defaults to False.
136
126
137 tlsversions (optional)
127 tlsversions (optional)
138 (array of bytestring) Indicates which TLS versions are supported by
128 (array of bytestring) Indicates which TLS versions are supported by
139 this target. Values are ``1.1``, ``1.2``, ``1.3``, etc.
129 this target. Values are ``1.1``, ``1.2``, ``1.3``, etc.
140
130
141 hashes
131 hashes
142 (array of bytestring) Indicates support for hashing algorithms that are
132 (array of bytestring) Indicates support for hashing algorithms that are
143 used to ensure content integrity. Values include ``sha1``, ``sha256``,
133 used to ensure content integrity. Values include ``sha1``, ``sha256``,
144 etc.
134 etc.
145
135
146 changesetdata
136 changesetdata
147 -------------
137 -------------
148
138
149 Obtain various data related to changesets.
139 Obtain various data related to changesets.
150
140
151 The command accepts the following arguments:
141 The command accepts the following arguments:
152
142
153 noderange
143 noderange
154 (array of arrays of bytestrings) An array of 2 elements, each being an
144 (array of arrays of bytestrings) An array of 2 elements, each being an
155 array of node bytestrings. The first array denotes the changelog revisions
145 array of node bytestrings. The first array denotes the changelog revisions
156 that are already known to the client. The second array denotes the changelog
146 that are already known to the client. The second array denotes the changelog
157 revision DAG heads to fetch. The argument essentially defines a DAG range
147 revision DAG heads to fetch. The argument essentially defines a DAG range
158 bounded by root and head nodes to fetch.
148 bounded by root and head nodes to fetch.
159
149
160 The roots array may be empty. The heads array must be defined.
150 The roots array may be empty. The heads array must be defined.
161
151
162 nodes
152 nodes
163 (array of bytestrings) Changelog revisions to request explicitly.
153 (array of bytestrings) Changelog revisions to request explicitly.
164
154
165 nodesdepth
155 nodesdepth
166 (unsigned integer) Number of ancestor revisions of elements in ``nodes``
156 (unsigned integer) Number of ancestor revisions of elements in ``nodes``
167 to also fetch. When defined, for each element in ``nodes``, DAG ancestors
157 to also fetch. When defined, for each element in ``nodes``, DAG ancestors
168 will be walked until at most N total revisions are emitted.
158 will be walked until at most N total revisions are emitted.
169
159
170 fields
160 fields
171 (set of bytestring) Which data associated with changelog revisions to
161 (set of bytestring) Which data associated with changelog revisions to
172 fetch. The following values are recognized:
162 fetch. The following values are recognized:
173
163
174 bookmarks
164 bookmarks
175 Bookmarks associated with a revision.
165 Bookmarks associated with a revision.
176
166
177 parents
167 parents
178 Parent revisions.
168 Parent revisions.
179
169
180 phase
170 phase
181 The phase state of a revision.
171 The phase state of a revision.
182
172
183 revision
173 revision
184 The raw, revision data for the changelog entry. The hash of this data
174 The raw, revision data for the changelog entry. The hash of this data
185 will match the revision's node value.
175 will match the revision's node value.
186
176
187 The server resolves the set of revisions relevant to the request by taking
177 The server resolves the set of revisions relevant to the request by taking
188 the union of the ``noderange`` and ``nodes`` arguments. At least one of these
178 the union of the ``noderange`` and ``nodes`` arguments. At least one of these
189 arguments must be defined.
179 arguments must be defined.
190
180
191 The response bytestream starts with a CBOR map describing the data that follows.
181 The response bytestream starts with a CBOR map describing the data that follows.
192 This map has the following bytestring keys:
182 This map has the following bytestring keys:
193
183
194 totalitems
184 totalitems
195 (unsigned integer) Total number of changelog revisions whose data is being
185 (unsigned integer) Total number of changelog revisions whose data is being
196 transferred. This maps to the set of revisions in the requested node
186 transferred. This maps to the set of revisions in the requested node
197 range, not the total number of records that follow (see below for why).
187 range, not the total number of records that follow (see below for why).
198
188
199 Following the map header is a series of 0 or more CBOR values. If values
189 Following the map header is a series of 0 or more CBOR values. If values
200 are present, the first value will always be a map describing a single changeset
190 are present, the first value will always be a map describing a single changeset
201 revision.
191 revision.
202
192
203 If the ``fieldsfollowing`` key is present, the map will immediately be followed
193 If the ``fieldsfollowing`` key is present, the map will immediately be followed
204 by N CBOR bytestring values, where N is the number of elements in
194 by N CBOR bytestring values, where N is the number of elements in
205 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
195 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
206 by ``fieldsfollowing``.
196 by ``fieldsfollowing``.
207
197
208 Following the optional bytestring field values is the next revision descriptor
198 Following the optional bytestring field values is the next revision descriptor
209 map, or end of stream.
199 map, or end of stream.
210
200
211 Each revision descriptor map has the following bytestring keys:
201 Each revision descriptor map has the following bytestring keys:
212
202
213 node
203 node
214 (bytestring) The node value for this revision. This is the SHA-1 hash of
204 (bytestring) The node value for this revision. This is the SHA-1 hash of
215 the raw revision data.
205 the raw revision data.
216
206
217 bookmarks (optional)
207 bookmarks (optional)
218 (array of bytestrings) Bookmarks attached to this revision. Only present
208 (array of bytestrings) Bookmarks attached to this revision. Only present
219 if ``bookmarks`` data is being requested and the revision has bookmarks
209 if ``bookmarks`` data is being requested and the revision has bookmarks
220 attached.
210 attached.
221
211
222 fieldsfollowing (optional)
212 fieldsfollowing (optional)
223 (array of 2-array) Denotes what fields immediately follow this map. Each
213 (array of 2-array) Denotes what fields immediately follow this map. Each
224 value is an array with 2 elements: the bytestring field name and an unsigned
214 value is an array with 2 elements: the bytestring field name and an unsigned
225 integer describing the length of the data, in bytes.
215 integer describing the length of the data, in bytes.
226
216
227 If this key isn't present, no special fields will follow this map.
217 If this key isn't present, no special fields will follow this map.
228
218
229 The following fields may be present:
219 The following fields may be present:
230
220
231 revision
221 revision
232 Raw, revision data for the changelog entry. Contains a serialized form
222 Raw, revision data for the changelog entry. Contains a serialized form
233 of the changeset data, including the author, date, commit message, set
223 of the changeset data, including the author, date, commit message, set
234 of changed files, manifest node, and other metadata.
224 of changed files, manifest node, and other metadata.
235
225
236 Only present if the ``revision`` field was requested.
226 Only present if the ``revision`` field was requested.
237
227
238 parents (optional)
228 parents (optional)
239 (array of bytestrings) The nodes representing the parent revisions of this
229 (array of bytestrings) The nodes representing the parent revisions of this
240 revision. Only present if ``parents`` data is being requested.
230 revision. Only present if ``parents`` data is being requested.
241
231
242 phase (optional)
232 phase (optional)
243 (bytestring) The phase that a revision is in. Recognized values are
233 (bytestring) The phase that a revision is in. Recognized values are
244 ``secret``, ``draft``, and ``public``. Only present if ``phase`` data
234 ``secret``, ``draft``, and ``public``. Only present if ``phase`` data
245 is being requested.
235 is being requested.
246
236
247 If nodes are requested via ``noderange``, they will be emitted in DAG order,
237 If nodes are requested via ``noderange``, they will be emitted in DAG order,
248 parents always before children.
238 parents always before children.
249
239
250 If nodes are requested via ``nodes``, they will be emitted in requested order.
240 If nodes are requested via ``nodes``, they will be emitted in requested order.
251
241
252 Nodes from ``nodes`` are emitted before nodes from ``noderange``.
242 Nodes from ``nodes`` are emitted before nodes from ``noderange``.
253
243
254 The set of changeset revisions emitted may not match the exact set of
244 The set of changeset revisions emitted may not match the exact set of
255 changesets requested. Furthermore, the set of keys present on each
245 changesets requested. Furthermore, the set of keys present on each
256 map may vary. This is to facilitate emitting changeset updates as well
246 map may vary. This is to facilitate emitting changeset updates as well
257 as new revisions.
247 as new revisions.
258
248
259 For example, if the request wants ``phase`` and ``revision`` data,
249 For example, if the request wants ``phase`` and ``revision`` data,
260 the response may contain entries for each changeset in the common nodes
250 the response may contain entries for each changeset in the common nodes
261 set with the ``phase`` key and without the ``revision`` key in order
251 set with the ``phase`` key and without the ``revision`` key in order
262 to reflect a phase-only update.
252 to reflect a phase-only update.
263
253
264 TODO support different revision selection mechanisms (e.g. non-public, specific
254 TODO support different revision selection mechanisms (e.g. non-public, specific
265 revisions)
255 revisions)
266 TODO support different hash "namespaces" for revisions (e.g. sha-1 versus other)
256 TODO support different hash "namespaces" for revisions (e.g. sha-1 versus other)
267 TODO support emitting obsolescence data
257 TODO support emitting obsolescence data
268 TODO support filtering based on relevant paths (narrow clone)
258 TODO support filtering based on relevant paths (narrow clone)
269 TODO support hgtagsfnodes cache / tags data
259 TODO support hgtagsfnodes cache / tags data
270 TODO support branch heads cache
260 TODO support branch heads cache
271 TODO consider unify query mechanism. e.g. as an array of "query descriptors"
261 TODO consider unify query mechanism. e.g. as an array of "query descriptors"
272 rather than a set of top-level arguments that have semantics when combined.
262 rather than a set of top-level arguments that have semantics when combined.
273
263
274 filedata
264 filedata
275 --------
265 --------
276
266
277 Obtain various data related to an individual tracked file.
267 Obtain various data related to an individual tracked file.
278
268
279 The command accepts the following arguments:
269 The command accepts the following arguments:
280
270
281 fields
271 fields
282 (set of bytestring) Which data associated with a file to fetch.
272 (set of bytestring) Which data associated with a file to fetch.
283 The following values are recognized:
273 The following values are recognized:
284
274
285 parents
275 parents
286 Parent nodes for the revision.
276 Parent nodes for the revision.
287
277
288 revision
278 revision
289 The raw revision data for a file.
279 The raw revision data for a file.
290
280
291 haveparents
281 haveparents
292 (bool) Whether the client has the parent revisions of all requested
282 (bool) Whether the client has the parent revisions of all requested
293 nodes. If set, the server may emit revision data as deltas against
283 nodes. If set, the server may emit revision data as deltas against
294 any parent revision. If not set, the server MUST only emit deltas for
284 any parent revision. If not set, the server MUST only emit deltas for
295 revisions previously emitted by this command.
285 revisions previously emitted by this command.
296
286
297 False is assumed in the absence of any value.
287 False is assumed in the absence of any value.
298
288
299 nodes
289 nodes
300 (array of bytestrings) File nodes whose data to retrieve.
290 (array of bytestrings) File nodes whose data to retrieve.
301
291
302 path
292 path
303 (bytestring) Path of the tracked file whose data to retrieve.
293 (bytestring) Path of the tracked file whose data to retrieve.
304
294
305 TODO allow specifying revisions via alternate means (such as from
295 TODO allow specifying revisions via alternate means (such as from
306 changeset revisions or ranges)
296 changeset revisions or ranges)
307
297
308 The response bytestream starts with a CBOR map describing the data that
298 The response bytestream starts with a CBOR map describing the data that
309 follows. It has the following bytestream keys:
299 follows. It has the following bytestream keys:
310
300
311 totalitems
301 totalitems
312 (unsigned integer) Total number of file revisions whose data is
302 (unsigned integer) Total number of file revisions whose data is
313 being returned.
303 being returned.
314
304
315 Following the map header is a series of 0 or more CBOR values. If values
305 Following the map header is a series of 0 or more CBOR values. If values
316 are present, the first value will always be a map describing a single changeset
306 are present, the first value will always be a map describing a single changeset
317 revision.
307 revision.
318
308
319 If the ``fieldsfollowing`` key is present, the map will immediately be followed
309 If the ``fieldsfollowing`` key is present, the map will immediately be followed
320 by N CBOR bytestring values, where N is the number of elements in
310 by N CBOR bytestring values, where N is the number of elements in
321 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
311 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
322 by ``fieldsfollowing``.
312 by ``fieldsfollowing``.
323
313
324 Following the optional bytestring field values is the next revision descriptor
314 Following the optional bytestring field values is the next revision descriptor
325 map, or end of stream.
315 map, or end of stream.
326
316
327 Each revision descriptor map has the following bytestring keys:
317 Each revision descriptor map has the following bytestring keys:
328
318
329 Each map has the following bytestring keys:
319 Each map has the following bytestring keys:
330
320
331 node
321 node
332 (bytestring) The node of the file revision whose data is represented.
322 (bytestring) The node of the file revision whose data is represented.
333
323
334 deltabasenode
324 deltabasenode
335 (bytestring) Node of the file revision the following delta is against.
325 (bytestring) Node of the file revision the following delta is against.
336
326
337 Only present if the ``revision`` field is requested and delta data
327 Only present if the ``revision`` field is requested and delta data
338 follows this map.
328 follows this map.
339
329
340 fieldsfollowing
330 fieldsfollowing
341 (array of 2-array) Denotes extra bytestring fields that following this map.
331 (array of 2-array) Denotes extra bytestring fields that following this map.
342 See the documentation for ``changesetdata`` for semantics.
332 See the documentation for ``changesetdata`` for semantics.
343
333
344 The following named fields may be present:
334 The following named fields may be present:
345
335
346 ``delta``
336 ``delta``
347 The delta data to use to construct the fulltext revision.
337 The delta data to use to construct the fulltext revision.
348
338
349 Only present if the ``revision`` field is requested and a delta is
339 Only present if the ``revision`` field is requested and a delta is
350 being emitted. The ``deltabasenode`` top-level key will also be
340 being emitted. The ``deltabasenode`` top-level key will also be
351 present if this field is being emitted.
341 present if this field is being emitted.
352
342
353 ``revision``
343 ``revision``
354 The fulltext revision data for this manifest. Only present if the
344 The fulltext revision data for this manifest. Only present if the
355 ``revision`` field is requested and a fulltext revision is being emitted.
345 ``revision`` field is requested and a fulltext revision is being emitted.
356
346
357 parents
347 parents
358 (array of bytestring) The nodes of the parents of this file revision.
348 (array of bytestring) The nodes of the parents of this file revision.
359
349
360 Only present if the ``parents`` field is requested.
350 Only present if the ``parents`` field is requested.
361
351
362 When ``revision`` data is requested, the server chooses to emit either fulltext
352 When ``revision`` data is requested, the server chooses to emit either fulltext
363 revision data or a delta. What the server decides can be inferred by looking
353 revision data or a delta. What the server decides can be inferred by looking
364 for the presence of the ``delta`` or ``revision`` keys in the
354 for the presence of the ``delta`` or ``revision`` keys in the
365 ``fieldsfollowing`` array.
355 ``fieldsfollowing`` array.
366
356
367 heads
357 heads
368 -----
358 -----
369
359
370 Obtain DAG heads in the repository.
360 Obtain DAG heads in the repository.
371
361
372 The command accepts the following arguments:
362 The command accepts the following arguments:
373
363
374 publiconly (optional)
364 publiconly (optional)
375 (boolean) If set, operate on the DAG for public phase changesets only.
365 (boolean) If set, operate on the DAG for public phase changesets only.
376 Non-public (i.e. draft) phase DAG heads will not be returned.
366 Non-public (i.e. draft) phase DAG heads will not be returned.
377
367
378 The response is a CBOR array of bytestrings defining changeset nodes
368 The response is a CBOR array of bytestrings defining changeset nodes
379 of DAG heads. The array can be empty if the repository is empty or no
369 of DAG heads. The array can be empty if the repository is empty or no
380 changesets satisfied the request.
370 changesets satisfied the request.
381
371
382 TODO consider exposing phase of heads in response
372 TODO consider exposing phase of heads in response
383
373
384 known
374 known
385 -----
375 -----
386
376
387 Determine whether a series of changeset nodes is known to the server.
377 Determine whether a series of changeset nodes is known to the server.
388
378
389 The command accepts the following arguments:
379 The command accepts the following arguments:
390
380
391 nodes
381 nodes
392 (array of bytestrings) List of changeset nodes whose presence to
382 (array of bytestrings) List of changeset nodes whose presence to
393 query.
383 query.
394
384
395 The response is a bytestring where each byte contains a 0 or 1 for the
385 The response is a bytestring where each byte contains a 0 or 1 for the
396 corresponding requested node at the same index.
386 corresponding requested node at the same index.
397
387
398 TODO use a bit array for even more compact response
388 TODO use a bit array for even more compact response
399
389
400 listkeys
390 listkeys
401 --------
391 --------
402
392
403 List values in a specified ``pushkey`` namespace.
393 List values in a specified ``pushkey`` namespace.
404
394
405 The command receives the following arguments:
395 The command receives the following arguments:
406
396
407 namespace
397 namespace
408 (bytestring) Pushkey namespace to query.
398 (bytestring) Pushkey namespace to query.
409
399
410 The response is a map with bytestring keys and values.
400 The response is a map with bytestring keys and values.
411
401
412 TODO consider using binary to represent nodes in certain pushkey namespaces.
402 TODO consider using binary to represent nodes in certain pushkey namespaces.
413
403
414 lookup
404 lookup
415 ------
405 ------
416
406
417 Try to resolve a value to a changeset revision.
407 Try to resolve a value to a changeset revision.
418
408
419 Unlike ``known`` which operates on changeset nodes, lookup operates on
409 Unlike ``known`` which operates on changeset nodes, lookup operates on
420 node fragments and other names that a user may use.
410 node fragments and other names that a user may use.
421
411
422 The command receives the following arguments:
412 The command receives the following arguments:
423
413
424 key
414 key
425 (bytestring) Value to try to resolve.
415 (bytestring) Value to try to resolve.
426
416
427 On success, returns a bytestring containing the resolved node.
417 On success, returns a bytestring containing the resolved node.
428
418
429 manifestdata
419 manifestdata
430 ------------
420 ------------
431
421
432 Obtain various data related to manifests (which are lists of files in
422 Obtain various data related to manifests (which are lists of files in
433 a revision).
423 a revision).
434
424
435 The command accepts the following arguments:
425 The command accepts the following arguments:
436
426
437 fields
427 fields
438 (set of bytestring) Which data associated with manifests to fetch.
428 (set of bytestring) Which data associated with manifests to fetch.
439 The following values are recognized:
429 The following values are recognized:
440
430
441 parents
431 parents
442 Parent nodes for the manifest.
432 Parent nodes for the manifest.
443
433
444 revision
434 revision
445 The raw revision data for the manifest.
435 The raw revision data for the manifest.
446
436
447 haveparents
437 haveparents
448 (bool) Whether the client has the parent revisions of all requested
438 (bool) Whether the client has the parent revisions of all requested
449 nodes. If set, the server may emit revision data as deltas against
439 nodes. If set, the server may emit revision data as deltas against
450 any parent revision. If not set, the server MUST only emit deltas for
440 any parent revision. If not set, the server MUST only emit deltas for
451 revisions previously emitted by this command.
441 revisions previously emitted by this command.
452
442
453 False is assumed in the absence of any value.
443 False is assumed in the absence of any value.
454
444
455 nodes
445 nodes
456 (array of bytestring) Manifest nodes whose data to retrieve.
446 (array of bytestring) Manifest nodes whose data to retrieve.
457
447
458 tree
448 tree
459 (bytestring) Path to manifest to retrieve. The empty bytestring represents
449 (bytestring) Path to manifest to retrieve. The empty bytestring represents
460 the root manifest. All other values represent directories/trees within
450 the root manifest. All other values represent directories/trees within
461 the repository.
451 the repository.
462
452
463 TODO allow specifying revisions via alternate means (such as from changeset
453 TODO allow specifying revisions via alternate means (such as from changeset
464 revisions or ranges)
454 revisions or ranges)
465 TODO consider recursive expansion of manifests (with path filtering for
455 TODO consider recursive expansion of manifests (with path filtering for
466 narrow use cases)
456 narrow use cases)
467
457
468 The response bytestream starts with a CBOR map describing the data that
458 The response bytestream starts with a CBOR map describing the data that
469 follows. It has the following bytestring keys:
459 follows. It has the following bytestring keys:
470
460
471 totalitems
461 totalitems
472 (unsigned integer) Total number of manifest revisions whose data is
462 (unsigned integer) Total number of manifest revisions whose data is
473 being returned.
463 being returned.
474
464
475 Following the map header is a series of 0 or more CBOR values. If values
465 Following the map header is a series of 0 or more CBOR values. If values
476 are present, the first value will always be a map describing a single manifest
466 are present, the first value will always be a map describing a single manifest
477 revision.
467 revision.
478
468
479 If the ``fieldsfollowing`` key is present, the map will immediately be followed
469 If the ``fieldsfollowing`` key is present, the map will immediately be followed
480 by N CBOR bytestring values, where N is the number of elements in
470 by N CBOR bytestring values, where N is the number of elements in
481 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
471 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
482 by ``fieldsfollowing``.
472 by ``fieldsfollowing``.
483
473
484 Following the optional bytestring field values is the next revision descriptor
474 Following the optional bytestring field values is the next revision descriptor
485 map, or end of stream.
475 map, or end of stream.
486
476
487 Each revision descriptor map has the following bytestring keys:
477 Each revision descriptor map has the following bytestring keys:
488
478
489 node
479 node
490 (bytestring) The node of the manifest revision whose data is represented.
480 (bytestring) The node of the manifest revision whose data is represented.
491
481
492 deltabasenode
482 deltabasenode
493 (bytestring) The node that the delta representation of this revision is
483 (bytestring) The node that the delta representation of this revision is
494 computed against. Only present if the ``revision`` field is requested and
484 computed against. Only present if the ``revision`` field is requested and
495 a delta is being emitted.
485 a delta is being emitted.
496
486
497 fieldsfollowing
487 fieldsfollowing
498 (array of 2-array) Denotes extra bytestring fields that following this map.
488 (array of 2-array) Denotes extra bytestring fields that following this map.
499 See the documentation for ``changesetdata`` for semantics.
489 See the documentation for ``changesetdata`` for semantics.
500
490
501 The following named fields may be present:
491 The following named fields may be present:
502
492
503 ``delta``
493 ``delta``
504 The delta data to use to construct the fulltext revision.
494 The delta data to use to construct the fulltext revision.
505
495
506 Only present if the ``revision`` field is requested and a delta is
496 Only present if the ``revision`` field is requested and a delta is
507 being emitted. The ``deltabasenode`` top-level key will also be
497 being emitted. The ``deltabasenode`` top-level key will also be
508 present if this field is being emitted.
498 present if this field is being emitted.
509
499
510 ``revision``
500 ``revision``
511 The fulltext revision data for this manifest. Only present if the
501 The fulltext revision data for this manifest. Only present if the
512 ``revision`` field is requested and a fulltext revision is being emitted.
502 ``revision`` field is requested and a fulltext revision is being emitted.
513
503
514 parents
504 parents
515 (array of bytestring) The nodes of the parents of this manifest revision.
505 (array of bytestring) The nodes of the parents of this manifest revision.
516 Only present if the ``parents`` field is requested.
506 Only present if the ``parents`` field is requested.
517
507
518 When ``revision`` data is requested, the server chooses to emit either fulltext
508 When ``revision`` data is requested, the server chooses to emit either fulltext
519 revision data or a delta. What the server decides can be inferred by looking
509 revision data or a delta. What the server decides can be inferred by looking
520 for the presence of ``delta`` or ``revision`` in the ``fieldsfollowing`` array.
510 for the presence of ``delta`` or ``revision`` in the ``fieldsfollowing`` array.
521
511
522 pushkey
512 pushkey
523 -------
513 -------
524
514
525 Set a value using the ``pushkey`` protocol.
515 Set a value using the ``pushkey`` protocol.
526
516
527 The command receives the following arguments:
517 The command receives the following arguments:
528
518
529 namespace
519 namespace
530 (bytestring) Pushkey namespace to operate on.
520 (bytestring) Pushkey namespace to operate on.
531 key
521 key
532 (bytestring) The pushkey key to set.
522 (bytestring) The pushkey key to set.
533 old
523 old
534 (bytestring) Old value for this key.
524 (bytestring) Old value for this key.
535 new
525 new
536 (bytestring) New value for this key.
526 (bytestring) New value for this key.
537
527
538 TODO consider using binary to represent nodes is certain pushkey namespaces.
528 TODO consider using binary to represent nodes is certain pushkey namespaces.
539 TODO better define response type and meaning.
529 TODO better define response type and meaning.
@@ -1,1195 +1,1187
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 contextlib
9 import contextlib
10 import hashlib
10 import hashlib
11
11
12 from .i18n import _
12 from .i18n import _
13 from .node import (
13 from .node import (
14 hex,
14 hex,
15 nullid,
15 nullid,
16 )
16 )
17 from . import (
17 from . import (
18 discovery,
18 discovery,
19 encoding,
19 encoding,
20 error,
20 error,
21 narrowspec,
21 narrowspec,
22 pycompat,
22 pycompat,
23 util,
24 wireprotoframing,
23 wireprotoframing,
25 wireprototypes,
24 wireprototypes,
26 )
25 )
27 from .utils import (
26 from .utils import (
28 cborutil,
27 cborutil,
29 interfaceutil,
28 interfaceutil,
30 stringutil,
29 stringutil,
31 )
30 )
32
31
33 FRAMINGTYPE = b'application/mercurial-exp-framing-0005'
32 FRAMINGTYPE = b'application/mercurial-exp-framing-0005'
34
33
35 HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
34 HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
36
35
37 COMMANDS = wireprototypes.commanddict()
36 COMMANDS = wireprototypes.commanddict()
38
37
39 # Value inserted into cache key computation function. Change the value to
38 # Value inserted into cache key computation function. Change the value to
40 # force new cache keys for every command request. This should be done when
39 # force new cache keys for every command request. This should be done when
41 # there is a change to how caching works, etc.
40 # there is a change to how caching works, etc.
42 GLOBAL_CACHE_VERSION = 1
41 GLOBAL_CACHE_VERSION = 1
43
42
44 def handlehttpv2request(rctx, req, res, checkperm, urlparts):
43 def handlehttpv2request(rctx, req, res, checkperm, urlparts):
45 from .hgweb import common as hgwebcommon
44 from .hgweb import common as hgwebcommon
46
45
47 # URL space looks like: <permissions>/<command>, where <permission> can
46 # URL space looks like: <permissions>/<command>, where <permission> can
48 # be ``ro`` or ``rw`` to signal read-only or read-write, respectively.
47 # be ``ro`` or ``rw`` to signal read-only or read-write, respectively.
49
48
50 # Root URL does nothing meaningful... yet.
49 # Root URL does nothing meaningful... yet.
51 if not urlparts:
50 if not urlparts:
52 res.status = b'200 OK'
51 res.status = b'200 OK'
53 res.headers[b'Content-Type'] = b'text/plain'
52 res.headers[b'Content-Type'] = b'text/plain'
54 res.setbodybytes(_('HTTP version 2 API handler'))
53 res.setbodybytes(_('HTTP version 2 API handler'))
55 return
54 return
56
55
57 if len(urlparts) == 1:
56 if len(urlparts) == 1:
58 res.status = b'404 Not Found'
57 res.status = b'404 Not Found'
59 res.headers[b'Content-Type'] = b'text/plain'
58 res.headers[b'Content-Type'] = b'text/plain'
60 res.setbodybytes(_('do not know how to process %s\n') %
59 res.setbodybytes(_('do not know how to process %s\n') %
61 req.dispatchpath)
60 req.dispatchpath)
62 return
61 return
63
62
64 permission, command = urlparts[0:2]
63 permission, command = urlparts[0:2]
65
64
66 if permission not in (b'ro', b'rw'):
65 if permission not in (b'ro', b'rw'):
67 res.status = b'404 Not Found'
66 res.status = b'404 Not Found'
68 res.headers[b'Content-Type'] = b'text/plain'
67 res.headers[b'Content-Type'] = b'text/plain'
69 res.setbodybytes(_('unknown permission: %s') % permission)
68 res.setbodybytes(_('unknown permission: %s') % permission)
70 return
69 return
71
70
72 if req.method != 'POST':
71 if req.method != 'POST':
73 res.status = b'405 Method Not Allowed'
72 res.status = b'405 Method Not Allowed'
74 res.headers[b'Allow'] = b'POST'
73 res.headers[b'Allow'] = b'POST'
75 res.setbodybytes(_('commands require POST requests'))
74 res.setbodybytes(_('commands require POST requests'))
76 return
75 return
77
76
78 # At some point we'll want to use our own API instead of recycling the
77 # At some point we'll want to use our own API instead of recycling the
79 # behavior of version 1 of the wire protocol...
78 # behavior of version 1 of the wire protocol...
80 # TODO return reasonable responses - not responses that overload the
79 # TODO return reasonable responses - not responses that overload the
81 # HTTP status line message for error reporting.
80 # HTTP status line message for error reporting.
82 try:
81 try:
83 checkperm(rctx, req, 'pull' if permission == b'ro' else 'push')
82 checkperm(rctx, req, 'pull' if permission == b'ro' else 'push')
84 except hgwebcommon.ErrorResponse as e:
83 except hgwebcommon.ErrorResponse as e:
85 res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e))
84 res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e))
86 for k, v in e.headers:
85 for k, v in e.headers:
87 res.headers[k] = v
86 res.headers[k] = v
88 res.setbodybytes('permission denied')
87 res.setbodybytes('permission denied')
89 return
88 return
90
89
91 # We have a special endpoint to reflect the request back at the client.
90 # We have a special endpoint to reflect the request back at the client.
92 if command == b'debugreflect':
91 if command == b'debugreflect':
93 _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
92 _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
94 return
93 return
95
94
96 # Extra commands that we handle that aren't really wire protocol
95 # Extra commands that we handle that aren't really wire protocol
97 # commands. Think extra hard before making this hackery available to
96 # commands. Think extra hard before making this hackery available to
98 # extension.
97 # extension.
99 extracommands = {'multirequest'}
98 extracommands = {'multirequest'}
100
99
101 if command not in COMMANDS and command not in extracommands:
100 if command not in COMMANDS and command not in extracommands:
102 res.status = b'404 Not Found'
101 res.status = b'404 Not Found'
103 res.headers[b'Content-Type'] = b'text/plain'
102 res.headers[b'Content-Type'] = b'text/plain'
104 res.setbodybytes(_('unknown wire protocol command: %s\n') % command)
103 res.setbodybytes(_('unknown wire protocol command: %s\n') % command)
105 return
104 return
106
105
107 repo = rctx.repo
106 repo = rctx.repo
108 ui = repo.ui
107 ui = repo.ui
109
108
110 proto = httpv2protocolhandler(req, ui)
109 proto = httpv2protocolhandler(req, ui)
111
110
112 if (not COMMANDS.commandavailable(command, proto)
111 if (not COMMANDS.commandavailable(command, proto)
113 and command not in extracommands):
112 and command not in extracommands):
114 res.status = b'404 Not Found'
113 res.status = b'404 Not Found'
115 res.headers[b'Content-Type'] = b'text/plain'
114 res.headers[b'Content-Type'] = b'text/plain'
116 res.setbodybytes(_('invalid wire protocol command: %s') % command)
115 res.setbodybytes(_('invalid wire protocol command: %s') % command)
117 return
116 return
118
117
119 # TODO consider cases where proxies may add additional Accept headers.
118 # TODO consider cases where proxies may add additional Accept headers.
120 if req.headers.get(b'Accept') != FRAMINGTYPE:
119 if req.headers.get(b'Accept') != FRAMINGTYPE:
121 res.status = b'406 Not Acceptable'
120 res.status = b'406 Not Acceptable'
122 res.headers[b'Content-Type'] = b'text/plain'
121 res.headers[b'Content-Type'] = b'text/plain'
123 res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
122 res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
124 % FRAMINGTYPE)
123 % FRAMINGTYPE)
125 return
124 return
126
125
127 if req.headers.get(b'Content-Type') != FRAMINGTYPE:
126 if req.headers.get(b'Content-Type') != FRAMINGTYPE:
128 res.status = b'415 Unsupported Media Type'
127 res.status = b'415 Unsupported Media Type'
129 # TODO we should send a response with appropriate media type,
128 # TODO we should send a response with appropriate media type,
130 # since client does Accept it.
129 # since client does Accept it.
131 res.headers[b'Content-Type'] = b'text/plain'
130 res.headers[b'Content-Type'] = b'text/plain'
132 res.setbodybytes(_('client MUST send Content-Type header with '
131 res.setbodybytes(_('client MUST send Content-Type header with '
133 'value: %s\n') % FRAMINGTYPE)
132 'value: %s\n') % FRAMINGTYPE)
134 return
133 return
135
134
136 _processhttpv2request(ui, repo, req, res, permission, command, proto)
135 _processhttpv2request(ui, repo, req, res, permission, command, proto)
137
136
138 def _processhttpv2reflectrequest(ui, repo, req, res):
137 def _processhttpv2reflectrequest(ui, repo, req, res):
139 """Reads unified frame protocol request and dumps out state to client.
138 """Reads unified frame protocol request and dumps out state to client.
140
139
141 This special endpoint can be used to help debug the wire protocol.
140 This special endpoint can be used to help debug the wire protocol.
142
141
143 Instead of routing the request through the normal dispatch mechanism,
142 Instead of routing the request through the normal dispatch mechanism,
144 we instead read all frames, decode them, and feed them into our state
143 we instead read all frames, decode them, and feed them into our state
145 tracker. We then dump the log of all that activity back out to the
144 tracker. We then dump the log of all that activity back out to the
146 client.
145 client.
147 """
146 """
148 import json
147 import json
149
148
150 # Reflection APIs have a history of being abused, accidentally disclosing
149 # Reflection APIs have a history of being abused, accidentally disclosing
151 # sensitive data, etc. So we have a config knob.
150 # sensitive data, etc. So we have a config knob.
152 if not ui.configbool('experimental', 'web.api.debugreflect'):
151 if not ui.configbool('experimental', 'web.api.debugreflect'):
153 res.status = b'404 Not Found'
152 res.status = b'404 Not Found'
154 res.headers[b'Content-Type'] = b'text/plain'
153 res.headers[b'Content-Type'] = b'text/plain'
155 res.setbodybytes(_('debugreflect service not available'))
154 res.setbodybytes(_('debugreflect service not available'))
156 return
155 return
157
156
158 # We assume we have a unified framing protocol request body.
157 # We assume we have a unified framing protocol request body.
159
158
160 reactor = wireprotoframing.serverreactor()
159 reactor = wireprotoframing.serverreactor()
161 states = []
160 states = []
162
161
163 while True:
162 while True:
164 frame = wireprotoframing.readframe(req.bodyfh)
163 frame = wireprotoframing.readframe(req.bodyfh)
165
164
166 if not frame:
165 if not frame:
167 states.append(b'received: <no frame>')
166 states.append(b'received: <no frame>')
168 break
167 break
169
168
170 states.append(b'received: %d %d %d %s' % (frame.typeid, frame.flags,
169 states.append(b'received: %d %d %d %s' % (frame.typeid, frame.flags,
171 frame.requestid,
170 frame.requestid,
172 frame.payload))
171 frame.payload))
173
172
174 action, meta = reactor.onframerecv(frame)
173 action, meta = reactor.onframerecv(frame)
175 states.append(json.dumps((action, meta), sort_keys=True,
174 states.append(json.dumps((action, meta), sort_keys=True,
176 separators=(', ', ': ')))
175 separators=(', ', ': ')))
177
176
178 action, meta = reactor.oninputeof()
177 action, meta = reactor.oninputeof()
179 meta['action'] = action
178 meta['action'] = action
180 states.append(json.dumps(meta, sort_keys=True, separators=(', ',': ')))
179 states.append(json.dumps(meta, sort_keys=True, separators=(', ',': ')))
181
180
182 res.status = b'200 OK'
181 res.status = b'200 OK'
183 res.headers[b'Content-Type'] = b'text/plain'
182 res.headers[b'Content-Type'] = b'text/plain'
184 res.setbodybytes(b'\n'.join(states))
183 res.setbodybytes(b'\n'.join(states))
185
184
186 def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
185 def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
187 """Post-validation handler for HTTPv2 requests.
186 """Post-validation handler for HTTPv2 requests.
188
187
189 Called when the HTTP request contains unified frame-based protocol
188 Called when the HTTP request contains unified frame-based protocol
190 frames for evaluation.
189 frames for evaluation.
191 """
190 """
192 # TODO Some HTTP clients are full duplex and can receive data before
191 # TODO Some HTTP clients are full duplex and can receive data before
193 # the entire request is transmitted. Figure out a way to indicate support
192 # the entire request is transmitted. Figure out a way to indicate support
194 # for that so we can opt into full duplex mode.
193 # for that so we can opt into full duplex mode.
195 reactor = wireprotoframing.serverreactor(deferoutput=True)
194 reactor = wireprotoframing.serverreactor(deferoutput=True)
196 seencommand = False
195 seencommand = False
197
196
198 outstream = reactor.makeoutputstream()
197 outstream = reactor.makeoutputstream()
199
198
200 while True:
199 while True:
201 frame = wireprotoframing.readframe(req.bodyfh)
200 frame = wireprotoframing.readframe(req.bodyfh)
202 if not frame:
201 if not frame:
203 break
202 break
204
203
205 action, meta = reactor.onframerecv(frame)
204 action, meta = reactor.onframerecv(frame)
206
205
207 if action == 'wantframe':
206 if action == 'wantframe':
208 # Need more data before we can do anything.
207 # Need more data before we can do anything.
209 continue
208 continue
210 elif action == 'runcommand':
209 elif action == 'runcommand':
211 sentoutput = _httpv2runcommand(ui, repo, req, res, authedperm,
210 sentoutput = _httpv2runcommand(ui, repo, req, res, authedperm,
212 reqcommand, reactor, outstream,
211 reqcommand, reactor, outstream,
213 meta, issubsequent=seencommand)
212 meta, issubsequent=seencommand)
214
213
215 if sentoutput:
214 if sentoutput:
216 return
215 return
217
216
218 seencommand = True
217 seencommand = True
219
218
220 elif action == 'error':
219 elif action == 'error':
221 # TODO define proper error mechanism.
220 # TODO define proper error mechanism.
222 res.status = b'200 OK'
221 res.status = b'200 OK'
223 res.headers[b'Content-Type'] = b'text/plain'
222 res.headers[b'Content-Type'] = b'text/plain'
224 res.setbodybytes(meta['message'] + b'\n')
223 res.setbodybytes(meta['message'] + b'\n')
225 return
224 return
226 else:
225 else:
227 raise error.ProgrammingError(
226 raise error.ProgrammingError(
228 'unhandled action from frame processor: %s' % action)
227 'unhandled action from frame processor: %s' % action)
229
228
230 action, meta = reactor.oninputeof()
229 action, meta = reactor.oninputeof()
231 if action == 'sendframes':
230 if action == 'sendframes':
232 # We assume we haven't started sending the response yet. If we're
231 # We assume we haven't started sending the response yet. If we're
233 # wrong, the response type will raise an exception.
232 # wrong, the response type will raise an exception.
234 res.status = b'200 OK'
233 res.status = b'200 OK'
235 res.headers[b'Content-Type'] = FRAMINGTYPE
234 res.headers[b'Content-Type'] = FRAMINGTYPE
236 res.setbodygen(meta['framegen'])
235 res.setbodygen(meta['framegen'])
237 elif action == 'noop':
236 elif action == 'noop':
238 pass
237 pass
239 else:
238 else:
240 raise error.ProgrammingError('unhandled action from frame processor: %s'
239 raise error.ProgrammingError('unhandled action from frame processor: %s'
241 % action)
240 % action)
242
241
243 def _httpv2runcommand(ui, repo, req, res, authedperm, reqcommand, reactor,
242 def _httpv2runcommand(ui, repo, req, res, authedperm, reqcommand, reactor,
244 outstream, command, issubsequent):
243 outstream, command, issubsequent):
245 """Dispatch a wire protocol command made from HTTPv2 requests.
244 """Dispatch a wire protocol command made from HTTPv2 requests.
246
245
247 The authenticated permission (``authedperm``) along with the original
246 The authenticated permission (``authedperm``) along with the original
248 command from the URL (``reqcommand``) are passed in.
247 command from the URL (``reqcommand``) are passed in.
249 """
248 """
250 # We already validated that the session has permissions to perform the
249 # We already validated that the session has permissions to perform the
251 # actions in ``authedperm``. In the unified frame protocol, the canonical
250 # actions in ``authedperm``. In the unified frame protocol, the canonical
252 # command to run is expressed in a frame. However, the URL also requested
251 # command to run is expressed in a frame. However, the URL also requested
253 # to run a specific command. We need to be careful that the command we
252 # to run a specific command. We need to be careful that the command we
254 # run doesn't have permissions requirements greater than what was granted
253 # run doesn't have permissions requirements greater than what was granted
255 # by ``authedperm``.
254 # by ``authedperm``.
256 #
255 #
257 # Our rule for this is we only allow one command per HTTP request and
256 # Our rule for this is we only allow one command per HTTP request and
258 # that command must match the command in the URL. However, we make
257 # that command must match the command in the URL. However, we make
259 # an exception for the ``multirequest`` URL. This URL is allowed to
258 # an exception for the ``multirequest`` URL. This URL is allowed to
260 # execute multiple commands. We double check permissions of each command
259 # execute multiple commands. We double check permissions of each command
261 # as it is invoked to ensure there is no privilege escalation.
260 # as it is invoked to ensure there is no privilege escalation.
262 # TODO consider allowing multiple commands to regular command URLs
261 # TODO consider allowing multiple commands to regular command URLs
263 # iff each command is the same.
262 # iff each command is the same.
264
263
265 proto = httpv2protocolhandler(req, ui, args=command['args'])
264 proto = httpv2protocolhandler(req, ui, args=command['args'])
266
265
267 if reqcommand == b'multirequest':
266 if reqcommand == b'multirequest':
268 if not COMMANDS.commandavailable(command['command'], proto):
267 if not COMMANDS.commandavailable(command['command'], proto):
269 # TODO proper error mechanism
268 # TODO proper error mechanism
270 res.status = b'200 OK'
269 res.status = b'200 OK'
271 res.headers[b'Content-Type'] = b'text/plain'
270 res.headers[b'Content-Type'] = b'text/plain'
272 res.setbodybytes(_('wire protocol command not available: %s') %
271 res.setbodybytes(_('wire protocol command not available: %s') %
273 command['command'])
272 command['command'])
274 return True
273 return True
275
274
276 # TODO don't use assert here, since it may be elided by -O.
275 # TODO don't use assert here, since it may be elided by -O.
277 assert authedperm in (b'ro', b'rw')
276 assert authedperm in (b'ro', b'rw')
278 wirecommand = COMMANDS[command['command']]
277 wirecommand = COMMANDS[command['command']]
279 assert wirecommand.permission in ('push', 'pull')
278 assert wirecommand.permission in ('push', 'pull')
280
279
281 if authedperm == b'ro' and wirecommand.permission != 'pull':
280 if authedperm == b'ro' and wirecommand.permission != 'pull':
282 # TODO proper error mechanism
281 # TODO proper error mechanism
283 res.status = b'403 Forbidden'
282 res.status = b'403 Forbidden'
284 res.headers[b'Content-Type'] = b'text/plain'
283 res.headers[b'Content-Type'] = b'text/plain'
285 res.setbodybytes(_('insufficient permissions to execute '
284 res.setbodybytes(_('insufficient permissions to execute '
286 'command: %s') % command['command'])
285 'command: %s') % command['command'])
287 return True
286 return True
288
287
289 # TODO should we also call checkperm() here? Maybe not if we're going
288 # TODO should we also call checkperm() here? Maybe not if we're going
290 # to overhaul that API. The granted scope from the URL check should
289 # to overhaul that API. The granted scope from the URL check should
291 # be good enough.
290 # be good enough.
292
291
293 else:
292 else:
294 # Don't allow multiple commands outside of ``multirequest`` URL.
293 # Don't allow multiple commands outside of ``multirequest`` URL.
295 if issubsequent:
294 if issubsequent:
296 # TODO proper error mechanism
295 # TODO proper error mechanism
297 res.status = b'200 OK'
296 res.status = b'200 OK'
298 res.headers[b'Content-Type'] = b'text/plain'
297 res.headers[b'Content-Type'] = b'text/plain'
299 res.setbodybytes(_('multiple commands cannot be issued to this '
298 res.setbodybytes(_('multiple commands cannot be issued to this '
300 'URL'))
299 'URL'))
301 return True
300 return True
302
301
303 if reqcommand != command['command']:
302 if reqcommand != command['command']:
304 # TODO define proper error mechanism
303 # TODO define proper error mechanism
305 res.status = b'200 OK'
304 res.status = b'200 OK'
306 res.headers[b'Content-Type'] = b'text/plain'
305 res.headers[b'Content-Type'] = b'text/plain'
307 res.setbodybytes(_('command in frame must match command in URL'))
306 res.setbodybytes(_('command in frame must match command in URL'))
308 return True
307 return True
309
308
310 res.status = b'200 OK'
309 res.status = b'200 OK'
311 res.headers[b'Content-Type'] = FRAMINGTYPE
310 res.headers[b'Content-Type'] = FRAMINGTYPE
312
311
313 try:
312 try:
314 objs = dispatch(repo, proto, command['command'], command['redirect'])
313 objs = dispatch(repo, proto, command['command'], command['redirect'])
315
314
316 action, meta = reactor.oncommandresponsereadyobjects(
315 action, meta = reactor.oncommandresponsereadyobjects(
317 outstream, command['requestid'], objs)
316 outstream, command['requestid'], objs)
318
317
319 except error.WireprotoCommandError as e:
318 except error.WireprotoCommandError as e:
320 action, meta = reactor.oncommanderror(
319 action, meta = reactor.oncommanderror(
321 outstream, command['requestid'], e.message, e.messageargs)
320 outstream, command['requestid'], e.message, e.messageargs)
322
321
323 except Exception as e:
322 except Exception as e:
324 action, meta = reactor.onservererror(
323 action, meta = reactor.onservererror(
325 outstream, command['requestid'],
324 outstream, command['requestid'],
326 _('exception when invoking command: %s') %
325 _('exception when invoking command: %s') %
327 stringutil.forcebytestr(e))
326 stringutil.forcebytestr(e))
328
327
329 if action == 'sendframes':
328 if action == 'sendframes':
330 res.setbodygen(meta['framegen'])
329 res.setbodygen(meta['framegen'])
331 return True
330 return True
332 elif action == 'noop':
331 elif action == 'noop':
333 return False
332 return False
334 else:
333 else:
335 raise error.ProgrammingError('unhandled event from reactor: %s' %
334 raise error.ProgrammingError('unhandled event from reactor: %s' %
336 action)
335 action)
337
336
338 def getdispatchrepo(repo, proto, command):
337 def getdispatchrepo(repo, proto, command):
339 return repo.filtered('served')
338 return repo.filtered('served')
340
339
341 def dispatch(repo, proto, command, redirect):
340 def dispatch(repo, proto, command, redirect):
342 """Run a wire protocol command.
341 """Run a wire protocol command.
343
342
344 Returns an iterable of objects that will be sent to the client.
343 Returns an iterable of objects that will be sent to the client.
345 """
344 """
346 repo = getdispatchrepo(repo, proto, command)
345 repo = getdispatchrepo(repo, proto, command)
347
346
348 entry = COMMANDS[command]
347 entry = COMMANDS[command]
349 func = entry.func
348 func = entry.func
350 spec = entry.args
349 spec = entry.args
351
350
352 args = proto.getargs(spec)
351 args = proto.getargs(spec)
353
352
354 # There is some duplicate boilerplate code here for calling the command and
353 # There is some duplicate boilerplate code here for calling the command and
355 # emitting objects. It is either that or a lot of indented code that looks
354 # emitting objects. It is either that or a lot of indented code that looks
356 # like a pyramid (since there are a lot of code paths that result in not
355 # like a pyramid (since there are a lot of code paths that result in not
357 # using the cacher).
356 # using the cacher).
358 callcommand = lambda: func(repo, proto, **pycompat.strkwargs(args))
357 callcommand = lambda: func(repo, proto, **pycompat.strkwargs(args))
359
358
360 # Request is not cacheable. Don't bother instantiating a cacher.
359 # Request is not cacheable. Don't bother instantiating a cacher.
361 if not entry.cachekeyfn:
360 if not entry.cachekeyfn:
362 for o in callcommand():
361 for o in callcommand():
363 yield o
362 yield o
364 return
363 return
365
364
366 if redirect:
365 if redirect:
367 redirecttargets = redirect[b'targets']
366 redirecttargets = redirect[b'targets']
368 redirecthashes = redirect[b'hashes']
367 redirecthashes = redirect[b'hashes']
369 else:
368 else:
370 redirecttargets = []
369 redirecttargets = []
371 redirecthashes = []
370 redirecthashes = []
372
371
373 cacher = makeresponsecacher(repo, proto, command, args,
372 cacher = makeresponsecacher(repo, proto, command, args,
374 cborutil.streamencode,
373 cborutil.streamencode,
375 redirecttargets=redirecttargets,
374 redirecttargets=redirecttargets,
376 redirecthashes=redirecthashes)
375 redirecthashes=redirecthashes)
377
376
378 # But we have no cacher. Do default handling.
377 # But we have no cacher. Do default handling.
379 if not cacher:
378 if not cacher:
380 for o in callcommand():
379 for o in callcommand():
381 yield o
380 yield o
382 return
381 return
383
382
384 with cacher:
383 with cacher:
385 cachekey = entry.cachekeyfn(repo, proto, cacher, **args)
384 cachekey = entry.cachekeyfn(repo, proto, cacher, **args)
386
385
387 # No cache key or the cacher doesn't like it. Do default handling.
386 # No cache key or the cacher doesn't like it. Do default handling.
388 if cachekey is None or not cacher.setcachekey(cachekey):
387 if cachekey is None or not cacher.setcachekey(cachekey):
389 for o in callcommand():
388 for o in callcommand():
390 yield o
389 yield o
391 return
390 return
392
391
393 # Serve it from the cache, if possible.
392 # Serve it from the cache, if possible.
394 cached = cacher.lookup()
393 cached = cacher.lookup()
395
394
396 if cached:
395 if cached:
397 for o in cached['objs']:
396 for o in cached['objs']:
398 yield o
397 yield o
399 return
398 return
400
399
401 # Else call the command and feed its output into the cacher, allowing
400 # Else call the command and feed its output into the cacher, allowing
402 # the cacher to buffer/mutate objects as it desires.
401 # the cacher to buffer/mutate objects as it desires.
403 for o in callcommand():
402 for o in callcommand():
404 for o in cacher.onobject(o):
403 for o in cacher.onobject(o):
405 yield o
404 yield o
406
405
407 for o in cacher.onfinished():
406 for o in cacher.onfinished():
408 yield o
407 yield o
409
408
410 @interfaceutil.implementer(wireprototypes.baseprotocolhandler)
409 @interfaceutil.implementer(wireprototypes.baseprotocolhandler)
411 class httpv2protocolhandler(object):
410 class httpv2protocolhandler(object):
412 def __init__(self, req, ui, args=None):
411 def __init__(self, req, ui, args=None):
413 self._req = req
412 self._req = req
414 self._ui = ui
413 self._ui = ui
415 self._args = args
414 self._args = args
416
415
417 @property
416 @property
418 def name(self):
417 def name(self):
419 return HTTP_WIREPROTO_V2
418 return HTTP_WIREPROTO_V2
420
419
421 def getargs(self, args):
420 def getargs(self, args):
422 # First look for args that were passed but aren't registered on this
421 # First look for args that were passed but aren't registered on this
423 # command.
422 # command.
424 extra = set(self._args) - set(args)
423 extra = set(self._args) - set(args)
425 if extra:
424 if extra:
426 raise error.WireprotoCommandError(
425 raise error.WireprotoCommandError(
427 'unsupported argument to command: %s' %
426 'unsupported argument to command: %s' %
428 ', '.join(sorted(extra)))
427 ', '.join(sorted(extra)))
429
428
430 # And look for required arguments that are missing.
429 # And look for required arguments that are missing.
431 missing = {a for a in args if args[a]['required']} - set(self._args)
430 missing = {a for a in args if args[a]['required']} - set(self._args)
432
431
433 if missing:
432 if missing:
434 raise error.WireprotoCommandError(
433 raise error.WireprotoCommandError(
435 'missing required arguments: %s' % ', '.join(sorted(missing)))
434 'missing required arguments: %s' % ', '.join(sorted(missing)))
436
435
437 # Now derive the arguments to pass to the command, taking into
436 # Now derive the arguments to pass to the command, taking into
438 # account the arguments specified by the client.
437 # account the arguments specified by the client.
439 data = {}
438 data = {}
440 for k, meta in sorted(args.items()):
439 for k, meta in sorted(args.items()):
441 # This argument wasn't passed by the client.
440 # This argument wasn't passed by the client.
442 if k not in self._args:
441 if k not in self._args:
443 data[k] = meta['default']()
442 data[k] = meta['default']()
444 continue
443 continue
445
444
446 v = self._args[k]
445 v = self._args[k]
447
446
448 # Sets may be expressed as lists. Silently normalize.
447 # Sets may be expressed as lists. Silently normalize.
449 if meta['type'] == 'set' and isinstance(v, list):
448 if meta['type'] == 'set' and isinstance(v, list):
450 v = set(v)
449 v = set(v)
451
450
452 # TODO consider more/stronger type validation.
451 # TODO consider more/stronger type validation.
453
452
454 data[k] = v
453 data[k] = v
455
454
456 return data
455 return data
457
456
458 def getprotocaps(self):
457 def getprotocaps(self):
459 # Protocol capabilities are currently not implemented for HTTP V2.
458 # Protocol capabilities are currently not implemented for HTTP V2.
460 return set()
459 return set()
461
460
462 def getpayload(self):
461 def getpayload(self):
463 raise NotImplementedError
462 raise NotImplementedError
464
463
465 @contextlib.contextmanager
464 @contextlib.contextmanager
466 def mayberedirectstdio(self):
465 def mayberedirectstdio(self):
467 raise NotImplementedError
466 raise NotImplementedError
468
467
469 def client(self):
468 def client(self):
470 raise NotImplementedError
469 raise NotImplementedError
471
470
472 def addcapabilities(self, repo, caps):
471 def addcapabilities(self, repo, caps):
473 return caps
472 return caps
474
473
475 def checkperm(self, perm):
474 def checkperm(self, perm):
476 raise NotImplementedError
475 raise NotImplementedError
477
476
478 def httpv2apidescriptor(req, repo):
477 def httpv2apidescriptor(req, repo):
479 proto = httpv2protocolhandler(req, repo.ui)
478 proto = httpv2protocolhandler(req, repo.ui)
480
479
481 return _capabilitiesv2(repo, proto)
480 return _capabilitiesv2(repo, proto)
482
481
483 def _capabilitiesv2(repo, proto):
482 def _capabilitiesv2(repo, proto):
484 """Obtain the set of capabilities for version 2 transports.
483 """Obtain the set of capabilities for version 2 transports.
485
484
486 These capabilities are distinct from the capabilities for version 1
485 These capabilities are distinct from the capabilities for version 1
487 transports.
486 transports.
488 """
487 """
489 compression = []
490 for engine in wireprototypes.supportedcompengines(repo.ui, util.SERVERROLE):
491 compression.append({
492 b'name': engine.wireprotosupport().name,
493 })
494
495 caps = {
488 caps = {
496 'commands': {},
489 'commands': {},
497 'compression': compression,
498 'framingmediatypes': [FRAMINGTYPE],
490 'framingmediatypes': [FRAMINGTYPE],
499 'pathfilterprefixes': set(narrowspec.VALID_PREFIXES),
491 'pathfilterprefixes': set(narrowspec.VALID_PREFIXES),
500 }
492 }
501
493
502 for command, entry in COMMANDS.items():
494 for command, entry in COMMANDS.items():
503 args = {}
495 args = {}
504
496
505 for arg, meta in entry.args.items():
497 for arg, meta in entry.args.items():
506 args[arg] = {
498 args[arg] = {
507 # TODO should this be a normalized type using CBOR's
499 # TODO should this be a normalized type using CBOR's
508 # terminology?
500 # terminology?
509 b'type': meta['type'],
501 b'type': meta['type'],
510 b'required': meta['required'],
502 b'required': meta['required'],
511 }
503 }
512
504
513 if not meta['required']:
505 if not meta['required']:
514 args[arg][b'default'] = meta['default']()
506 args[arg][b'default'] = meta['default']()
515
507
516 if meta['validvalues']:
508 if meta['validvalues']:
517 args[arg][b'validvalues'] = meta['validvalues']
509 args[arg][b'validvalues'] = meta['validvalues']
518
510
519 caps['commands'][command] = {
511 caps['commands'][command] = {
520 'args': args,
512 'args': args,
521 'permissions': [entry.permission],
513 'permissions': [entry.permission],
522 }
514 }
523
515
524 caps['rawrepoformats'] = sorted(repo.requirements &
516 caps['rawrepoformats'] = sorted(repo.requirements &
525 repo.supportedformats)
517 repo.supportedformats)
526
518
527 targets = getadvertisedredirecttargets(repo, proto)
519 targets = getadvertisedredirecttargets(repo, proto)
528 if targets:
520 if targets:
529 caps[b'redirect'] = {
521 caps[b'redirect'] = {
530 b'targets': [],
522 b'targets': [],
531 b'hashes': [b'sha256', b'sha1'],
523 b'hashes': [b'sha256', b'sha1'],
532 }
524 }
533
525
534 for target in targets:
526 for target in targets:
535 entry = {
527 entry = {
536 b'name': target['name'],
528 b'name': target['name'],
537 b'protocol': target['protocol'],
529 b'protocol': target['protocol'],
538 b'uris': target['uris'],
530 b'uris': target['uris'],
539 }
531 }
540
532
541 for key in ('snirequired', 'tlsversions'):
533 for key in ('snirequired', 'tlsversions'):
542 if key in target:
534 if key in target:
543 entry[key] = target[key]
535 entry[key] = target[key]
544
536
545 caps[b'redirect'][b'targets'].append(entry)
537 caps[b'redirect'][b'targets'].append(entry)
546
538
547 return proto.addcapabilities(repo, caps)
539 return proto.addcapabilities(repo, caps)
548
540
549 def getadvertisedredirecttargets(repo, proto):
541 def getadvertisedredirecttargets(repo, proto):
550 """Obtain a list of content redirect targets.
542 """Obtain a list of content redirect targets.
551
543
552 Returns a list containing potential redirect targets that will be
544 Returns a list containing potential redirect targets that will be
553 advertised in capabilities data. Each dict MUST have the following
545 advertised in capabilities data. Each dict MUST have the following
554 keys:
546 keys:
555
547
556 name
548 name
557 The name of this redirect target. This is the identifier clients use
549 The name of this redirect target. This is the identifier clients use
558 to refer to a target. It is transferred as part of every command
550 to refer to a target. It is transferred as part of every command
559 request.
551 request.
560
552
561 protocol
553 protocol
562 Network protocol used by this target. Typically this is the string
554 Network protocol used by this target. Typically this is the string
563 in front of the ``://`` in a URL. e.g. ``https``.
555 in front of the ``://`` in a URL. e.g. ``https``.
564
556
565 uris
557 uris
566 List of representative URIs for this target. Clients can use the
558 List of representative URIs for this target. Clients can use the
567 URIs to test parsing for compatibility or for ordering preference
559 URIs to test parsing for compatibility or for ordering preference
568 for which target to use.
560 for which target to use.
569
561
570 The following optional keys are recognized:
562 The following optional keys are recognized:
571
563
572 snirequired
564 snirequired
573 Bool indicating if Server Name Indication (SNI) is required to
565 Bool indicating if Server Name Indication (SNI) is required to
574 connect to this target.
566 connect to this target.
575
567
576 tlsversions
568 tlsversions
577 List of bytes indicating which TLS versions are supported by this
569 List of bytes indicating which TLS versions are supported by this
578 target.
570 target.
579
571
580 By default, clients reflect the target order advertised by servers
572 By default, clients reflect the target order advertised by servers
581 and servers will use the first client-advertised target when picking
573 and servers will use the first client-advertised target when picking
582 a redirect target. So targets should be advertised in the order the
574 a redirect target. So targets should be advertised in the order the
583 server prefers they be used.
575 server prefers they be used.
584 """
576 """
585 return []
577 return []
586
578
587 def wireprotocommand(name, args=None, permission='push', cachekeyfn=None):
579 def wireprotocommand(name, args=None, permission='push', cachekeyfn=None):
588 """Decorator to declare a wire protocol command.
580 """Decorator to declare a wire protocol command.
589
581
590 ``name`` is the name of the wire protocol command being provided.
582 ``name`` is the name of the wire protocol command being provided.
591
583
592 ``args`` is a dict defining arguments accepted by the command. Keys are
584 ``args`` is a dict defining arguments accepted by the command. Keys are
593 the argument name. Values are dicts with the following keys:
585 the argument name. Values are dicts with the following keys:
594
586
595 ``type``
587 ``type``
596 The argument data type. Must be one of the following string
588 The argument data type. Must be one of the following string
597 literals: ``bytes``, ``int``, ``list``, ``dict``, ``set``,
589 literals: ``bytes``, ``int``, ``list``, ``dict``, ``set``,
598 or ``bool``.
590 or ``bool``.
599
591
600 ``default``
592 ``default``
601 A callable returning the default value for this argument. If not
593 A callable returning the default value for this argument. If not
602 specified, ``None`` will be the default value.
594 specified, ``None`` will be the default value.
603
595
604 ``example``
596 ``example``
605 An example value for this argument.
597 An example value for this argument.
606
598
607 ``validvalues``
599 ``validvalues``
608 Set of recognized values for this argument.
600 Set of recognized values for this argument.
609
601
610 ``permission`` defines the permission type needed to run this command.
602 ``permission`` defines the permission type needed to run this command.
611 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
603 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
612 respectively. Default is to assume command requires ``push`` permissions
604 respectively. Default is to assume command requires ``push`` permissions
613 because otherwise commands not declaring their permissions could modify
605 because otherwise commands not declaring their permissions could modify
614 a repository that is supposed to be read-only.
606 a repository that is supposed to be read-only.
615
607
616 ``cachekeyfn`` defines an optional callable that can derive the
608 ``cachekeyfn`` defines an optional callable that can derive the
617 cache key for this request.
609 cache key for this request.
618
610
619 Wire protocol commands are generators of objects to be serialized and
611 Wire protocol commands are generators of objects to be serialized and
620 sent to the client.
612 sent to the client.
621
613
622 If a command raises an uncaught exception, this will be translated into
614 If a command raises an uncaught exception, this will be translated into
623 a command error.
615 a command error.
624
616
625 All commands can opt in to being cacheable by defining a function
617 All commands can opt in to being cacheable by defining a function
626 (``cachekeyfn``) that is called to derive a cache key. This function
618 (``cachekeyfn``) that is called to derive a cache key. This function
627 receives the same arguments as the command itself plus a ``cacher``
619 receives the same arguments as the command itself plus a ``cacher``
628 argument containing the active cacher for the request and returns a bytes
620 argument containing the active cacher for the request and returns a bytes
629 containing the key in a cache the response to this command may be cached
621 containing the key in a cache the response to this command may be cached
630 under.
622 under.
631 """
623 """
632 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
624 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
633 if v['version'] == 2}
625 if v['version'] == 2}
634
626
635 if permission not in ('push', 'pull'):
627 if permission not in ('push', 'pull'):
636 raise error.ProgrammingError('invalid wire protocol permission; '
628 raise error.ProgrammingError('invalid wire protocol permission; '
637 'got %s; expected "push" or "pull"' %
629 'got %s; expected "push" or "pull"' %
638 permission)
630 permission)
639
631
640 if args is None:
632 if args is None:
641 args = {}
633 args = {}
642
634
643 if not isinstance(args, dict):
635 if not isinstance(args, dict):
644 raise error.ProgrammingError('arguments for version 2 commands '
636 raise error.ProgrammingError('arguments for version 2 commands '
645 'must be declared as dicts')
637 'must be declared as dicts')
646
638
647 for arg, meta in args.items():
639 for arg, meta in args.items():
648 if arg == '*':
640 if arg == '*':
649 raise error.ProgrammingError('* argument name not allowed on '
641 raise error.ProgrammingError('* argument name not allowed on '
650 'version 2 commands')
642 'version 2 commands')
651
643
652 if not isinstance(meta, dict):
644 if not isinstance(meta, dict):
653 raise error.ProgrammingError('arguments for version 2 commands '
645 raise error.ProgrammingError('arguments for version 2 commands '
654 'must declare metadata as a dict')
646 'must declare metadata as a dict')
655
647
656 if 'type' not in meta:
648 if 'type' not in meta:
657 raise error.ProgrammingError('%s argument for command %s does not '
649 raise error.ProgrammingError('%s argument for command %s does not '
658 'declare type field' % (arg, name))
650 'declare type field' % (arg, name))
659
651
660 if meta['type'] not in ('bytes', 'int', 'list', 'dict', 'set', 'bool'):
652 if meta['type'] not in ('bytes', 'int', 'list', 'dict', 'set', 'bool'):
661 raise error.ProgrammingError('%s argument for command %s has '
653 raise error.ProgrammingError('%s argument for command %s has '
662 'illegal type: %s' % (arg, name,
654 'illegal type: %s' % (arg, name,
663 meta['type']))
655 meta['type']))
664
656
665 if 'example' not in meta:
657 if 'example' not in meta:
666 raise error.ProgrammingError('%s argument for command %s does not '
658 raise error.ProgrammingError('%s argument for command %s does not '
667 'declare example field' % (arg, name))
659 'declare example field' % (arg, name))
668
660
669 meta['required'] = 'default' not in meta
661 meta['required'] = 'default' not in meta
670
662
671 meta.setdefault('default', lambda: None)
663 meta.setdefault('default', lambda: None)
672 meta.setdefault('validvalues', None)
664 meta.setdefault('validvalues', None)
673
665
674 def register(func):
666 def register(func):
675 if name in COMMANDS:
667 if name in COMMANDS:
676 raise error.ProgrammingError('%s command already registered '
668 raise error.ProgrammingError('%s command already registered '
677 'for version 2' % name)
669 'for version 2' % name)
678
670
679 COMMANDS[name] = wireprototypes.commandentry(
671 COMMANDS[name] = wireprototypes.commandentry(
680 func, args=args, transports=transports, permission=permission,
672 func, args=args, transports=transports, permission=permission,
681 cachekeyfn=cachekeyfn)
673 cachekeyfn=cachekeyfn)
682
674
683 return func
675 return func
684
676
685 return register
677 return register
686
678
687 def makecommandcachekeyfn(command, localversion=None, allargs=False):
679 def makecommandcachekeyfn(command, localversion=None, allargs=False):
688 """Construct a cache key derivation function with common features.
680 """Construct a cache key derivation function with common features.
689
681
690 By default, the cache key is a hash of:
682 By default, the cache key is a hash of:
691
683
692 * The command name.
684 * The command name.
693 * A global cache version number.
685 * A global cache version number.
694 * A local cache version number (passed via ``localversion``).
686 * A local cache version number (passed via ``localversion``).
695 * All the arguments passed to the command.
687 * All the arguments passed to the command.
696 * The media type used.
688 * The media type used.
697 * Wire protocol version string.
689 * Wire protocol version string.
698 * The repository path.
690 * The repository path.
699 """
691 """
700 if not allargs:
692 if not allargs:
701 raise error.ProgrammingError('only allargs=True is currently supported')
693 raise error.ProgrammingError('only allargs=True is currently supported')
702
694
703 if localversion is None:
695 if localversion is None:
704 raise error.ProgrammingError('must set localversion argument value')
696 raise error.ProgrammingError('must set localversion argument value')
705
697
706 def cachekeyfn(repo, proto, cacher, **args):
698 def cachekeyfn(repo, proto, cacher, **args):
707 spec = COMMANDS[command]
699 spec = COMMANDS[command]
708
700
709 # Commands that mutate the repo can not be cached.
701 # Commands that mutate the repo can not be cached.
710 if spec.permission == 'push':
702 if spec.permission == 'push':
711 return None
703 return None
712
704
713 # TODO config option to disable caching.
705 # TODO config option to disable caching.
714
706
715 # Our key derivation strategy is to construct a data structure
707 # Our key derivation strategy is to construct a data structure
716 # holding everything that could influence cacheability and to hash
708 # holding everything that could influence cacheability and to hash
717 # the CBOR representation of that. Using CBOR seems like it might
709 # the CBOR representation of that. Using CBOR seems like it might
718 # be overkill. However, simpler hashing mechanisms are prone to
710 # be overkill. However, simpler hashing mechanisms are prone to
719 # duplicate input issues. e.g. if you just concatenate two values,
711 # duplicate input issues. e.g. if you just concatenate two values,
720 # "foo"+"bar" is identical to "fo"+"obar". Using CBOR provides
712 # "foo"+"bar" is identical to "fo"+"obar". Using CBOR provides
721 # "padding" between values and prevents these problems.
713 # "padding" between values and prevents these problems.
722
714
723 # Seed the hash with various data.
715 # Seed the hash with various data.
724 state = {
716 state = {
725 # To invalidate all cache keys.
717 # To invalidate all cache keys.
726 b'globalversion': GLOBAL_CACHE_VERSION,
718 b'globalversion': GLOBAL_CACHE_VERSION,
727 # More granular cache key invalidation.
719 # More granular cache key invalidation.
728 b'localversion': localversion,
720 b'localversion': localversion,
729 # Cache keys are segmented by command.
721 # Cache keys are segmented by command.
730 b'command': pycompat.sysbytes(command),
722 b'command': pycompat.sysbytes(command),
731 # Throw in the media type and API version strings so changes
723 # Throw in the media type and API version strings so changes
732 # to exchange semantics invalid cache.
724 # to exchange semantics invalid cache.
733 b'mediatype': FRAMINGTYPE,
725 b'mediatype': FRAMINGTYPE,
734 b'version': HTTP_WIREPROTO_V2,
726 b'version': HTTP_WIREPROTO_V2,
735 # So same requests for different repos don't share cache keys.
727 # So same requests for different repos don't share cache keys.
736 b'repo': repo.root,
728 b'repo': repo.root,
737 }
729 }
738
730
739 # The arguments passed to us will have already been normalized.
731 # The arguments passed to us will have already been normalized.
740 # Default values will be set, etc. This is important because it
732 # Default values will be set, etc. This is important because it
741 # means that it doesn't matter if clients send an explicit argument
733 # means that it doesn't matter if clients send an explicit argument
742 # or rely on the default value: it will all normalize to the same
734 # or rely on the default value: it will all normalize to the same
743 # set of arguments on the server and therefore the same cache key.
735 # set of arguments on the server and therefore the same cache key.
744 #
736 #
745 # Arguments by their very nature must support being encoded to CBOR.
737 # Arguments by their very nature must support being encoded to CBOR.
746 # And the CBOR encoder is deterministic. So we hash the arguments
738 # And the CBOR encoder is deterministic. So we hash the arguments
747 # by feeding the CBOR of their representation into the hasher.
739 # by feeding the CBOR of their representation into the hasher.
748 if allargs:
740 if allargs:
749 state[b'args'] = pycompat.byteskwargs(args)
741 state[b'args'] = pycompat.byteskwargs(args)
750
742
751 cacher.adjustcachekeystate(state)
743 cacher.adjustcachekeystate(state)
752
744
753 hasher = hashlib.sha1()
745 hasher = hashlib.sha1()
754 for chunk in cborutil.streamencode(state):
746 for chunk in cborutil.streamencode(state):
755 hasher.update(chunk)
747 hasher.update(chunk)
756
748
757 return pycompat.sysbytes(hasher.hexdigest())
749 return pycompat.sysbytes(hasher.hexdigest())
758
750
759 return cachekeyfn
751 return cachekeyfn
760
752
761 def makeresponsecacher(repo, proto, command, args, objencoderfn,
753 def makeresponsecacher(repo, proto, command, args, objencoderfn,
762 redirecttargets, redirecthashes):
754 redirecttargets, redirecthashes):
763 """Construct a cacher for a cacheable command.
755 """Construct a cacher for a cacheable command.
764
756
765 Returns an ``iwireprotocolcommandcacher`` instance.
757 Returns an ``iwireprotocolcommandcacher`` instance.
766
758
767 Extensions can monkeypatch this function to provide custom caching
759 Extensions can monkeypatch this function to provide custom caching
768 backends.
760 backends.
769 """
761 """
770 return None
762 return None
771
763
772 @wireprotocommand('branchmap', permission='pull')
764 @wireprotocommand('branchmap', permission='pull')
773 def branchmapv2(repo, proto):
765 def branchmapv2(repo, proto):
774 yield {encoding.fromlocal(k): v
766 yield {encoding.fromlocal(k): v
775 for k, v in repo.branchmap().iteritems()}
767 for k, v in repo.branchmap().iteritems()}
776
768
777 @wireprotocommand('capabilities', permission='pull')
769 @wireprotocommand('capabilities', permission='pull')
778 def capabilitiesv2(repo, proto):
770 def capabilitiesv2(repo, proto):
779 yield _capabilitiesv2(repo, proto)
771 yield _capabilitiesv2(repo, proto)
780
772
781 @wireprotocommand(
773 @wireprotocommand(
782 'changesetdata',
774 'changesetdata',
783 args={
775 args={
784 'noderange': {
776 'noderange': {
785 'type': 'list',
777 'type': 'list',
786 'default': lambda: None,
778 'default': lambda: None,
787 'example': [[b'0123456...'], [b'abcdef...']],
779 'example': [[b'0123456...'], [b'abcdef...']],
788 },
780 },
789 'nodes': {
781 'nodes': {
790 'type': 'list',
782 'type': 'list',
791 'default': lambda: None,
783 'default': lambda: None,
792 'example': [b'0123456...'],
784 'example': [b'0123456...'],
793 },
785 },
794 'nodesdepth': {
786 'nodesdepth': {
795 'type': 'int',
787 'type': 'int',
796 'default': lambda: None,
788 'default': lambda: None,
797 'example': 10,
789 'example': 10,
798 },
790 },
799 'fields': {
791 'fields': {
800 'type': 'set',
792 'type': 'set',
801 'default': set,
793 'default': set,
802 'example': {b'parents', b'revision'},
794 'example': {b'parents', b'revision'},
803 'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
795 'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
804 },
796 },
805 },
797 },
806 permission='pull')
798 permission='pull')
807 def changesetdata(repo, proto, noderange, nodes, nodesdepth, fields):
799 def changesetdata(repo, proto, noderange, nodes, nodesdepth, fields):
808 # TODO look for unknown fields and abort when they can't be serviced.
800 # TODO look for unknown fields and abort when they can't be serviced.
809 # This could probably be validated by dispatcher using validvalues.
801 # This could probably be validated by dispatcher using validvalues.
810
802
811 if noderange is None and nodes is None:
803 if noderange is None and nodes is None:
812 raise error.WireprotoCommandError(
804 raise error.WireprotoCommandError(
813 'noderange or nodes must be defined')
805 'noderange or nodes must be defined')
814
806
815 if nodesdepth is not None and nodes is None:
807 if nodesdepth is not None and nodes is None:
816 raise error.WireprotoCommandError(
808 raise error.WireprotoCommandError(
817 'nodesdepth requires the nodes argument')
809 'nodesdepth requires the nodes argument')
818
810
819 if noderange is not None:
811 if noderange is not None:
820 if len(noderange) != 2:
812 if len(noderange) != 2:
821 raise error.WireprotoCommandError(
813 raise error.WireprotoCommandError(
822 'noderange must consist of 2 elements')
814 'noderange must consist of 2 elements')
823
815
824 if not noderange[1]:
816 if not noderange[1]:
825 raise error.WireprotoCommandError(
817 raise error.WireprotoCommandError(
826 'heads in noderange request cannot be empty')
818 'heads in noderange request cannot be empty')
827
819
828 cl = repo.changelog
820 cl = repo.changelog
829 hasnode = cl.hasnode
821 hasnode = cl.hasnode
830
822
831 seen = set()
823 seen = set()
832 outgoing = []
824 outgoing = []
833
825
834 if nodes is not None:
826 if nodes is not None:
835 outgoing = [n for n in nodes if hasnode(n)]
827 outgoing = [n for n in nodes if hasnode(n)]
836
828
837 if nodesdepth:
829 if nodesdepth:
838 outgoing = [cl.node(r) for r in
830 outgoing = [cl.node(r) for r in
839 repo.revs(b'ancestors(%ln, %d)', outgoing,
831 repo.revs(b'ancestors(%ln, %d)', outgoing,
840 nodesdepth - 1)]
832 nodesdepth - 1)]
841
833
842 seen |= set(outgoing)
834 seen |= set(outgoing)
843
835
844 if noderange is not None:
836 if noderange is not None:
845 if noderange[0]:
837 if noderange[0]:
846 common = [n for n in noderange[0] if hasnode(n)]
838 common = [n for n in noderange[0] if hasnode(n)]
847 else:
839 else:
848 common = [nullid]
840 common = [nullid]
849
841
850 for n in discovery.outgoing(repo, common, noderange[1]).missing:
842 for n in discovery.outgoing(repo, common, noderange[1]).missing:
851 if n not in seen:
843 if n not in seen:
852 outgoing.append(n)
844 outgoing.append(n)
853 # Don't need to add to seen here because this is the final
845 # Don't need to add to seen here because this is the final
854 # source of nodes and there should be no duplicates in this
846 # source of nodes and there should be no duplicates in this
855 # list.
847 # list.
856
848
857 seen.clear()
849 seen.clear()
858 publishing = repo.publishing()
850 publishing = repo.publishing()
859
851
860 if outgoing:
852 if outgoing:
861 repo.hook('preoutgoing', throw=True, source='serve')
853 repo.hook('preoutgoing', throw=True, source='serve')
862
854
863 yield {
855 yield {
864 b'totalitems': len(outgoing),
856 b'totalitems': len(outgoing),
865 }
857 }
866
858
867 # The phases of nodes already transferred to the client may have changed
859 # The phases of nodes already transferred to the client may have changed
868 # since the client last requested data. We send phase-only records
860 # since the client last requested data. We send phase-only records
869 # for these revisions, if requested.
861 # for these revisions, if requested.
870 if b'phase' in fields and noderange is not None:
862 if b'phase' in fields and noderange is not None:
871 # TODO skip nodes whose phase will be reflected by a node in the
863 # TODO skip nodes whose phase will be reflected by a node in the
872 # outgoing set. This is purely an optimization to reduce data
864 # outgoing set. This is purely an optimization to reduce data
873 # size.
865 # size.
874 for node in noderange[0]:
866 for node in noderange[0]:
875 yield {
867 yield {
876 b'node': node,
868 b'node': node,
877 b'phase': b'public' if publishing else repo[node].phasestr()
869 b'phase': b'public' if publishing else repo[node].phasestr()
878 }
870 }
879
871
880 nodebookmarks = {}
872 nodebookmarks = {}
881 for mark, node in repo._bookmarks.items():
873 for mark, node in repo._bookmarks.items():
882 nodebookmarks.setdefault(node, set()).add(mark)
874 nodebookmarks.setdefault(node, set()).add(mark)
883
875
884 # It is already topologically sorted by revision number.
876 # It is already topologically sorted by revision number.
885 for node in outgoing:
877 for node in outgoing:
886 d = {
878 d = {
887 b'node': node,
879 b'node': node,
888 }
880 }
889
881
890 if b'parents' in fields:
882 if b'parents' in fields:
891 d[b'parents'] = cl.parents(node)
883 d[b'parents'] = cl.parents(node)
892
884
893 if b'phase' in fields:
885 if b'phase' in fields:
894 if publishing:
886 if publishing:
895 d[b'phase'] = b'public'
887 d[b'phase'] = b'public'
896 else:
888 else:
897 ctx = repo[node]
889 ctx = repo[node]
898 d[b'phase'] = ctx.phasestr()
890 d[b'phase'] = ctx.phasestr()
899
891
900 if b'bookmarks' in fields and node in nodebookmarks:
892 if b'bookmarks' in fields and node in nodebookmarks:
901 d[b'bookmarks'] = sorted(nodebookmarks[node])
893 d[b'bookmarks'] = sorted(nodebookmarks[node])
902 del nodebookmarks[node]
894 del nodebookmarks[node]
903
895
904 followingmeta = []
896 followingmeta = []
905 followingdata = []
897 followingdata = []
906
898
907 if b'revision' in fields:
899 if b'revision' in fields:
908 revisiondata = cl.revision(node, raw=True)
900 revisiondata = cl.revision(node, raw=True)
909 followingmeta.append((b'revision', len(revisiondata)))
901 followingmeta.append((b'revision', len(revisiondata)))
910 followingdata.append(revisiondata)
902 followingdata.append(revisiondata)
911
903
912 # TODO make it possible for extensions to wrap a function or register
904 # TODO make it possible for extensions to wrap a function or register
913 # a handler to service custom fields.
905 # a handler to service custom fields.
914
906
915 if followingmeta:
907 if followingmeta:
916 d[b'fieldsfollowing'] = followingmeta
908 d[b'fieldsfollowing'] = followingmeta
917
909
918 yield d
910 yield d
919
911
920 for extra in followingdata:
912 for extra in followingdata:
921 yield extra
913 yield extra
922
914
923 # If requested, send bookmarks from nodes that didn't have revision
915 # If requested, send bookmarks from nodes that didn't have revision
924 # data sent so receiver is aware of any bookmark updates.
916 # data sent so receiver is aware of any bookmark updates.
925 if b'bookmarks' in fields:
917 if b'bookmarks' in fields:
926 for node, marks in sorted(nodebookmarks.iteritems()):
918 for node, marks in sorted(nodebookmarks.iteritems()):
927 yield {
919 yield {
928 b'node': node,
920 b'node': node,
929 b'bookmarks': sorted(marks),
921 b'bookmarks': sorted(marks),
930 }
922 }
931
923
932 class FileAccessError(Exception):
924 class FileAccessError(Exception):
933 """Represents an error accessing a specific file."""
925 """Represents an error accessing a specific file."""
934
926
935 def __init__(self, path, msg, args):
927 def __init__(self, path, msg, args):
936 self.path = path
928 self.path = path
937 self.msg = msg
929 self.msg = msg
938 self.args = args
930 self.args = args
939
931
940 def getfilestore(repo, proto, path):
932 def getfilestore(repo, proto, path):
941 """Obtain a file storage object for use with wire protocol.
933 """Obtain a file storage object for use with wire protocol.
942
934
943 Exists as a standalone function so extensions can monkeypatch to add
935 Exists as a standalone function so extensions can monkeypatch to add
944 access control.
936 access control.
945 """
937 """
946 # This seems to work even if the file doesn't exist. So catch
938 # This seems to work even if the file doesn't exist. So catch
947 # "empty" files and return an error.
939 # "empty" files and return an error.
948 fl = repo.file(path)
940 fl = repo.file(path)
949
941
950 if not len(fl):
942 if not len(fl):
951 raise FileAccessError(path, 'unknown file: %s', (path,))
943 raise FileAccessError(path, 'unknown file: %s', (path,))
952
944
953 return fl
945 return fl
954
946
955 @wireprotocommand(
947 @wireprotocommand(
956 'filedata',
948 'filedata',
957 args={
949 args={
958 'haveparents': {
950 'haveparents': {
959 'type': 'bool',
951 'type': 'bool',
960 'default': lambda: False,
952 'default': lambda: False,
961 'example': True,
953 'example': True,
962 },
954 },
963 'nodes': {
955 'nodes': {
964 'type': 'list',
956 'type': 'list',
965 'example': [b'0123456...'],
957 'example': [b'0123456...'],
966 },
958 },
967 'fields': {
959 'fields': {
968 'type': 'set',
960 'type': 'set',
969 'default': set,
961 'default': set,
970 'example': {b'parents', b'revision'},
962 'example': {b'parents', b'revision'},
971 'validvalues': {b'parents', b'revision'},
963 'validvalues': {b'parents', b'revision'},
972 },
964 },
973 'path': {
965 'path': {
974 'type': 'bytes',
966 'type': 'bytes',
975 'example': b'foo.txt',
967 'example': b'foo.txt',
976 }
968 }
977 },
969 },
978 permission='pull',
970 permission='pull',
979 # TODO censoring a file revision won't invalidate the cache.
971 # TODO censoring a file revision won't invalidate the cache.
980 # Figure out a way to take censoring into account when deriving
972 # Figure out a way to take censoring into account when deriving
981 # the cache key.
973 # the cache key.
982 cachekeyfn=makecommandcachekeyfn('filedata', 1, allargs=True))
974 cachekeyfn=makecommandcachekeyfn('filedata', 1, allargs=True))
983 def filedata(repo, proto, haveparents, nodes, fields, path):
975 def filedata(repo, proto, haveparents, nodes, fields, path):
984 try:
976 try:
985 # Extensions may wish to access the protocol handler.
977 # Extensions may wish to access the protocol handler.
986 store = getfilestore(repo, proto, path)
978 store = getfilestore(repo, proto, path)
987 except FileAccessError as e:
979 except FileAccessError as e:
988 raise error.WireprotoCommandError(e.msg, e.args)
980 raise error.WireprotoCommandError(e.msg, e.args)
989
981
990 # Validate requested nodes.
982 # Validate requested nodes.
991 for node in nodes:
983 for node in nodes:
992 try:
984 try:
993 store.rev(node)
985 store.rev(node)
994 except error.LookupError:
986 except error.LookupError:
995 raise error.WireprotoCommandError('unknown file node: %s',
987 raise error.WireprotoCommandError('unknown file node: %s',
996 (hex(node),))
988 (hex(node),))
997
989
998 revisions = store.emitrevisions(nodes,
990 revisions = store.emitrevisions(nodes,
999 revisiondata=b'revision' in fields,
991 revisiondata=b'revision' in fields,
1000 assumehaveparentrevisions=haveparents)
992 assumehaveparentrevisions=haveparents)
1001
993
1002 yield {
994 yield {
1003 b'totalitems': len(nodes),
995 b'totalitems': len(nodes),
1004 }
996 }
1005
997
1006 for revision in revisions:
998 for revision in revisions:
1007 d = {
999 d = {
1008 b'node': revision.node,
1000 b'node': revision.node,
1009 }
1001 }
1010
1002
1011 if b'parents' in fields:
1003 if b'parents' in fields:
1012 d[b'parents'] = [revision.p1node, revision.p2node]
1004 d[b'parents'] = [revision.p1node, revision.p2node]
1013
1005
1014 followingmeta = []
1006 followingmeta = []
1015 followingdata = []
1007 followingdata = []
1016
1008
1017 if b'revision' in fields:
1009 if b'revision' in fields:
1018 if revision.revision is not None:
1010 if revision.revision is not None:
1019 followingmeta.append((b'revision', len(revision.revision)))
1011 followingmeta.append((b'revision', len(revision.revision)))
1020 followingdata.append(revision.revision)
1012 followingdata.append(revision.revision)
1021 else:
1013 else:
1022 d[b'deltabasenode'] = revision.basenode
1014 d[b'deltabasenode'] = revision.basenode
1023 followingmeta.append((b'delta', len(revision.delta)))
1015 followingmeta.append((b'delta', len(revision.delta)))
1024 followingdata.append(revision.delta)
1016 followingdata.append(revision.delta)
1025
1017
1026 if followingmeta:
1018 if followingmeta:
1027 d[b'fieldsfollowing'] = followingmeta
1019 d[b'fieldsfollowing'] = followingmeta
1028
1020
1029 yield d
1021 yield d
1030
1022
1031 for extra in followingdata:
1023 for extra in followingdata:
1032 yield extra
1024 yield extra
1033
1025
1034 @wireprotocommand(
1026 @wireprotocommand(
1035 'heads',
1027 'heads',
1036 args={
1028 args={
1037 'publiconly': {
1029 'publiconly': {
1038 'type': 'bool',
1030 'type': 'bool',
1039 'default': lambda: False,
1031 'default': lambda: False,
1040 'example': False,
1032 'example': False,
1041 },
1033 },
1042 },
1034 },
1043 permission='pull')
1035 permission='pull')
1044 def headsv2(repo, proto, publiconly):
1036 def headsv2(repo, proto, publiconly):
1045 if publiconly:
1037 if publiconly:
1046 repo = repo.filtered('immutable')
1038 repo = repo.filtered('immutable')
1047
1039
1048 yield repo.heads()
1040 yield repo.heads()
1049
1041
1050 @wireprotocommand(
1042 @wireprotocommand(
1051 'known',
1043 'known',
1052 args={
1044 args={
1053 'nodes': {
1045 'nodes': {
1054 'type': 'list',
1046 'type': 'list',
1055 'default': list,
1047 'default': list,
1056 'example': [b'deadbeef'],
1048 'example': [b'deadbeef'],
1057 },
1049 },
1058 },
1050 },
1059 permission='pull')
1051 permission='pull')
1060 def knownv2(repo, proto, nodes):
1052 def knownv2(repo, proto, nodes):
1061 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
1053 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
1062 yield result
1054 yield result
1063
1055
1064 @wireprotocommand(
1056 @wireprotocommand(
1065 'listkeys',
1057 'listkeys',
1066 args={
1058 args={
1067 'namespace': {
1059 'namespace': {
1068 'type': 'bytes',
1060 'type': 'bytes',
1069 'example': b'ns',
1061 'example': b'ns',
1070 },
1062 },
1071 },
1063 },
1072 permission='pull')
1064 permission='pull')
1073 def listkeysv2(repo, proto, namespace):
1065 def listkeysv2(repo, proto, namespace):
1074 keys = repo.listkeys(encoding.tolocal(namespace))
1066 keys = repo.listkeys(encoding.tolocal(namespace))
1075 keys = {encoding.fromlocal(k): encoding.fromlocal(v)
1067 keys = {encoding.fromlocal(k): encoding.fromlocal(v)
1076 for k, v in keys.iteritems()}
1068 for k, v in keys.iteritems()}
1077
1069
1078 yield keys
1070 yield keys
1079
1071
1080 @wireprotocommand(
1072 @wireprotocommand(
1081 'lookup',
1073 'lookup',
1082 args={
1074 args={
1083 'key': {
1075 'key': {
1084 'type': 'bytes',
1076 'type': 'bytes',
1085 'example': b'foo',
1077 'example': b'foo',
1086 },
1078 },
1087 },
1079 },
1088 permission='pull')
1080 permission='pull')
1089 def lookupv2(repo, proto, key):
1081 def lookupv2(repo, proto, key):
1090 key = encoding.tolocal(key)
1082 key = encoding.tolocal(key)
1091
1083
1092 # TODO handle exception.
1084 # TODO handle exception.
1093 node = repo.lookup(key)
1085 node = repo.lookup(key)
1094
1086
1095 yield node
1087 yield node
1096
1088
1097 @wireprotocommand(
1089 @wireprotocommand(
1098 'manifestdata',
1090 'manifestdata',
1099 args={
1091 args={
1100 'nodes': {
1092 'nodes': {
1101 'type': 'list',
1093 'type': 'list',
1102 'example': [b'0123456...'],
1094 'example': [b'0123456...'],
1103 },
1095 },
1104 'haveparents': {
1096 'haveparents': {
1105 'type': 'bool',
1097 'type': 'bool',
1106 'default': lambda: False,
1098 'default': lambda: False,
1107 'example': True,
1099 'example': True,
1108 },
1100 },
1109 'fields': {
1101 'fields': {
1110 'type': 'set',
1102 'type': 'set',
1111 'default': set,
1103 'default': set,
1112 'example': {b'parents', b'revision'},
1104 'example': {b'parents', b'revision'},
1113 'validvalues': {b'parents', b'revision'},
1105 'validvalues': {b'parents', b'revision'},
1114 },
1106 },
1115 'tree': {
1107 'tree': {
1116 'type': 'bytes',
1108 'type': 'bytes',
1117 'example': b'',
1109 'example': b'',
1118 },
1110 },
1119 },
1111 },
1120 permission='pull',
1112 permission='pull',
1121 cachekeyfn=makecommandcachekeyfn('manifestdata', 1, allargs=True))
1113 cachekeyfn=makecommandcachekeyfn('manifestdata', 1, allargs=True))
1122 def manifestdata(repo, proto, haveparents, nodes, fields, tree):
1114 def manifestdata(repo, proto, haveparents, nodes, fields, tree):
1123 store = repo.manifestlog.getstorage(tree)
1115 store = repo.manifestlog.getstorage(tree)
1124
1116
1125 # Validate the node is known and abort on unknown revisions.
1117 # Validate the node is known and abort on unknown revisions.
1126 for node in nodes:
1118 for node in nodes:
1127 try:
1119 try:
1128 store.rev(node)
1120 store.rev(node)
1129 except error.LookupError:
1121 except error.LookupError:
1130 raise error.WireprotoCommandError(
1122 raise error.WireprotoCommandError(
1131 'unknown node: %s', (node,))
1123 'unknown node: %s', (node,))
1132
1124
1133 revisions = store.emitrevisions(nodes,
1125 revisions = store.emitrevisions(nodes,
1134 revisiondata=b'revision' in fields,
1126 revisiondata=b'revision' in fields,
1135 assumehaveparentrevisions=haveparents)
1127 assumehaveparentrevisions=haveparents)
1136
1128
1137 yield {
1129 yield {
1138 b'totalitems': len(nodes),
1130 b'totalitems': len(nodes),
1139 }
1131 }
1140
1132
1141 for revision in revisions:
1133 for revision in revisions:
1142 d = {
1134 d = {
1143 b'node': revision.node,
1135 b'node': revision.node,
1144 }
1136 }
1145
1137
1146 if b'parents' in fields:
1138 if b'parents' in fields:
1147 d[b'parents'] = [revision.p1node, revision.p2node]
1139 d[b'parents'] = [revision.p1node, revision.p2node]
1148
1140
1149 followingmeta = []
1141 followingmeta = []
1150 followingdata = []
1142 followingdata = []
1151
1143
1152 if b'revision' in fields:
1144 if b'revision' in fields:
1153 if revision.revision is not None:
1145 if revision.revision is not None:
1154 followingmeta.append((b'revision', len(revision.revision)))
1146 followingmeta.append((b'revision', len(revision.revision)))
1155 followingdata.append(revision.revision)
1147 followingdata.append(revision.revision)
1156 else:
1148 else:
1157 d[b'deltabasenode'] = revision.basenode
1149 d[b'deltabasenode'] = revision.basenode
1158 followingmeta.append((b'delta', len(revision.delta)))
1150 followingmeta.append((b'delta', len(revision.delta)))
1159 followingdata.append(revision.delta)
1151 followingdata.append(revision.delta)
1160
1152
1161 if followingmeta:
1153 if followingmeta:
1162 d[b'fieldsfollowing'] = followingmeta
1154 d[b'fieldsfollowing'] = followingmeta
1163
1155
1164 yield d
1156 yield d
1165
1157
1166 for extra in followingdata:
1158 for extra in followingdata:
1167 yield extra
1159 yield extra
1168
1160
1169 @wireprotocommand(
1161 @wireprotocommand(
1170 'pushkey',
1162 'pushkey',
1171 args={
1163 args={
1172 'namespace': {
1164 'namespace': {
1173 'type': 'bytes',
1165 'type': 'bytes',
1174 'example': b'ns',
1166 'example': b'ns',
1175 },
1167 },
1176 'key': {
1168 'key': {
1177 'type': 'bytes',
1169 'type': 'bytes',
1178 'example': b'key',
1170 'example': b'key',
1179 },
1171 },
1180 'old': {
1172 'old': {
1181 'type': 'bytes',
1173 'type': 'bytes',
1182 'example': b'old',
1174 'example': b'old',
1183 },
1175 },
1184 'new': {
1176 'new': {
1185 'type': 'bytes',
1177 'type': 'bytes',
1186 'example': 'new',
1178 'example': 'new',
1187 },
1179 },
1188 },
1180 },
1189 permission='push')
1181 permission='push')
1190 def pushkeyv2(repo, proto, namespace, key, old, new):
1182 def pushkeyv2(repo, proto, namespace, key, old, new):
1191 # TODO handle ui output redirection
1183 # TODO handle ui output redirection
1192 yield repo.pushkey(encoding.tolocal(namespace),
1184 yield repo.pushkey(encoding.tolocal(namespace),
1193 encoding.tolocal(key),
1185 encoding.tolocal(key),
1194 encoding.tolocal(old),
1186 encoding.tolocal(old),
1195 encoding.tolocal(new))
1187 encoding.tolocal(new))
@@ -1,754 +1,754
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-0002\r\n
257 s> x-hgupgrade-1: exp-http-v2-0002\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 --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
299 $ hg --config experimental.httppeer.advertise-v2=true --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-0002\r\n
306 s> x-hgupgrade-1: exp-http-v2-0002\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-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\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-0002\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\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-0002/ro/heads HTTP/1.1\r\n
320 s> POST /api/exp-http-v2-0002/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-0005\r\n
322 s> accept: application/mercurial-exp-framing-0005\r\n
323 s> content-type: application/mercurial-exp-framing-0005\r\n
323 s> content-type: application/mercurial-exp-framing-0005\r\n
324 s> content-length: 20\r\n
324 s> content-length: 20\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> \x0c\x00\x00\x01\x00\x01\x01\x11\xa1DnameEheads
328 s> \x0c\x00\x00\x01\x00\x01\x01\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-0005\r\n
333 s> Content-Type: application/mercurial-exp-framing-0005\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> 13\r\n
336 s> 13\r\n
337 s> \x0b\x00\x00\x01\x00\x02\x011
337 s> \x0b\x00\x00\x01\x00\x02\x011
338 s> \xa1FstatusBok
338 s> \xa1FstatusBok
339 s> \r\n
339 s> \r\n
340 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
340 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
341 s> 1e\r\n
341 s> 1e\r\n
342 s> \x16\x00\x00\x01\x00\x02\x001
342 s> \x16\x00\x00\x01\x00\x02\x001
343 s> \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
343 s> \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
344 s> \r\n
344 s> \r\n
345 received frame(size=22; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
345 received frame(size=22; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
346 s> 8\r\n
346 s> 8\r\n
347 s> \x00\x00\x00\x01\x00\x02\x002
347 s> \x00\x00\x00\x01\x00\x02\x002
348 s> \r\n
348 s> \r\n
349 s> 0\r\n
349 s> 0\r\n
350 s> \r\n
350 s> \r\n
351 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
351 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
352 response: [
352 response: [
353 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
353 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
354 ]
354 ]
355 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
355 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
356
356
357 $ killdaemons.py
357 $ killdaemons.py
358
358
359 HTTP client follows HTTP redirect on handshake to new repo
359 HTTP client follows HTTP redirect on handshake to new repo
360
360
361 $ cd $TESTTMP
361 $ cd $TESTTMP
362
362
363 $ hg init redirector
363 $ hg init redirector
364 $ hg init redirected
364 $ hg init redirected
365 $ cd redirected
365 $ cd redirected
366 $ touch foo
366 $ touch foo
367 $ hg -q commit -A -m initial
367 $ hg -q commit -A -m initial
368 $ cd ..
368 $ cd ..
369
369
370 $ cat > paths.conf << EOF
370 $ cat > paths.conf << EOF
371 > [paths]
371 > [paths]
372 > / = $TESTTMP/*
372 > / = $TESTTMP/*
373 > EOF
373 > EOF
374
374
375 $ cat > redirectext.py << EOF
375 $ cat > redirectext.py << EOF
376 > from mercurial import extensions, wireprotoserver
376 > from mercurial import extensions, wireprotoserver
377 > def wrappedcallhttp(orig, repo, req, res, proto, cmd):
377 > def wrappedcallhttp(orig, repo, req, res, proto, cmd):
378 > path = req.advertisedurl[len(req.advertisedbaseurl):]
378 > path = req.advertisedurl[len(req.advertisedbaseurl):]
379 > if not path.startswith(b'/redirector'):
379 > if not path.startswith(b'/redirector'):
380 > return orig(repo, req, res, proto, cmd)
380 > return orig(repo, req, res, proto, cmd)
381 > relpath = path[len(b'/redirector'):]
381 > relpath = path[len(b'/redirector'):]
382 > res.status = b'301 Redirect'
382 > res.status = b'301 Redirect'
383 > newurl = b'%s/redirected%s' % (req.baseurl, relpath)
383 > newurl = b'%s/redirected%s' % (req.baseurl, relpath)
384 > if not repo.ui.configbool('testing', 'redirectqs', True) and b'?' in newurl:
384 > if not repo.ui.configbool('testing', 'redirectqs', True) and b'?' in newurl:
385 > newurl = newurl[0:newurl.index(b'?')]
385 > newurl = newurl[0:newurl.index(b'?')]
386 > res.headers[b'Location'] = newurl
386 > res.headers[b'Location'] = newurl
387 > res.headers[b'Content-Type'] = b'text/plain'
387 > res.headers[b'Content-Type'] = b'text/plain'
388 > res.setbodybytes(b'redirected')
388 > res.setbodybytes(b'redirected')
389 > return True
389 > return True
390 >
390 >
391 > extensions.wrapfunction(wireprotoserver, '_callhttp', wrappedcallhttp)
391 > extensions.wrapfunction(wireprotoserver, '_callhttp', wrappedcallhttp)
392 > EOF
392 > EOF
393
393
394 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
394 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
395 > --config server.compressionengines=zlib \
395 > --config server.compressionengines=zlib \
396 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
396 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
397 $ cat hg.pid > $DAEMON_PIDS
397 $ cat hg.pid > $DAEMON_PIDS
398
398
399 Verify our HTTP 301 is served properly
399 Verify our HTTP 301 is served properly
400
400
401 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
401 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
402 > httprequest GET /redirector?cmd=capabilities
402 > httprequest GET /redirector?cmd=capabilities
403 > user-agent: test
403 > user-agent: test
404 > EOF
404 > EOF
405 using raw connection to peer
405 using raw connection to peer
406 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
406 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
407 s> Accept-Encoding: identity\r\n
407 s> Accept-Encoding: identity\r\n
408 s> user-agent: test\r\n
408 s> user-agent: test\r\n
409 s> host: $LOCALIP:$HGPORT\r\n (glob)
409 s> host: $LOCALIP:$HGPORT\r\n (glob)
410 s> \r\n
410 s> \r\n
411 s> makefile('rb', None)
411 s> makefile('rb', None)
412 s> HTTP/1.1 301 Redirect\r\n
412 s> HTTP/1.1 301 Redirect\r\n
413 s> Server: testing stub value\r\n
413 s> Server: testing stub value\r\n
414 s> Date: $HTTP_DATE$\r\n
414 s> Date: $HTTP_DATE$\r\n
415 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
415 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
416 s> Content-Type: text/plain\r\n
416 s> Content-Type: text/plain\r\n
417 s> Content-Length: 10\r\n
417 s> Content-Length: 10\r\n
418 s> \r\n
418 s> \r\n
419 s> redirected
419 s> redirected
420 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
420 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
421 s> Accept-Encoding: identity\r\n
421 s> Accept-Encoding: identity\r\n
422 s> user-agent: test\r\n
422 s> user-agent: test\r\n
423 s> host: $LOCALIP:$HGPORT\r\n (glob)
423 s> host: $LOCALIP:$HGPORT\r\n (glob)
424 s> \r\n
424 s> \r\n
425 s> makefile('rb', None)
425 s> makefile('rb', None)
426 s> HTTP/1.1 200 Script output follows\r\n
426 s> HTTP/1.1 200 Script output follows\r\n
427 s> Server: testing stub value\r\n
427 s> Server: testing stub value\r\n
428 s> Date: $HTTP_DATE$\r\n
428 s> Date: $HTTP_DATE$\r\n
429 s> Content-Type: application/mercurial-0.1\r\n
429 s> Content-Type: application/mercurial-0.1\r\n
430 s> Content-Length: 467\r\n
430 s> Content-Length: 467\r\n
431 s> \r\n
431 s> \r\n
432 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
432 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
433
433
434 Test with the HTTP peer
434 Test with the HTTP peer
435
435
436 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
436 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
437 > command heads
437 > command heads
438 > EOF
438 > EOF
439 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
439 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
440 s> Accept-Encoding: identity\r\n
440 s> Accept-Encoding: identity\r\n
441 s> accept: application/mercurial-0.1\r\n
441 s> accept: application/mercurial-0.1\r\n
442 s> host: $LOCALIP:$HGPORT\r\n (glob)
442 s> host: $LOCALIP:$HGPORT\r\n (glob)
443 s> user-agent: Mercurial debugwireproto\r\n
443 s> user-agent: Mercurial debugwireproto\r\n
444 s> \r\n
444 s> \r\n
445 s> makefile('rb', None)
445 s> makefile('rb', None)
446 s> HTTP/1.1 301 Redirect\r\n
446 s> HTTP/1.1 301 Redirect\r\n
447 s> Server: testing stub value\r\n
447 s> Server: testing stub value\r\n
448 s> Date: $HTTP_DATE$\r\n
448 s> Date: $HTTP_DATE$\r\n
449 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
449 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
450 s> Content-Type: text/plain\r\n
450 s> Content-Type: text/plain\r\n
451 s> Content-Length: 10\r\n
451 s> Content-Length: 10\r\n
452 s> \r\n
452 s> \r\n
453 s> redirected
453 s> redirected
454 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
454 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
455 s> Accept-Encoding: identity\r\n
455 s> Accept-Encoding: identity\r\n
456 s> accept: application/mercurial-0.1\r\n
456 s> accept: application/mercurial-0.1\r\n
457 s> host: $LOCALIP:$HGPORT\r\n (glob)
457 s> host: $LOCALIP:$HGPORT\r\n (glob)
458 s> user-agent: Mercurial debugwireproto\r\n
458 s> user-agent: Mercurial debugwireproto\r\n
459 s> \r\n
459 s> \r\n
460 s> makefile('rb', None)
460 s> makefile('rb', None)
461 s> HTTP/1.1 200 Script output follows\r\n
461 s> HTTP/1.1 200 Script output follows\r\n
462 s> Server: testing stub value\r\n
462 s> Server: testing stub value\r\n
463 s> Date: $HTTP_DATE$\r\n
463 s> Date: $HTTP_DATE$\r\n
464 s> Content-Type: application/mercurial-0.1\r\n
464 s> Content-Type: application/mercurial-0.1\r\n
465 s> Content-Length: 467\r\n
465 s> Content-Length: 467\r\n
466 s> \r\n
466 s> \r\n
467 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
467 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
468 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
468 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
469 sending heads command
469 sending heads command
470 s> GET /redirected?cmd=heads HTTP/1.1\r\n
470 s> GET /redirected?cmd=heads HTTP/1.1\r\n
471 s> Accept-Encoding: identity\r\n
471 s> Accept-Encoding: identity\r\n
472 s> vary: X-HgProto-1\r\n
472 s> vary: X-HgProto-1\r\n
473 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
473 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
474 s> accept: application/mercurial-0.1\r\n
474 s> accept: application/mercurial-0.1\r\n
475 s> host: $LOCALIP:$HGPORT\r\n (glob)
475 s> host: $LOCALIP:$HGPORT\r\n (glob)
476 s> user-agent: Mercurial debugwireproto\r\n
476 s> user-agent: Mercurial debugwireproto\r\n
477 s> \r\n
477 s> \r\n
478 s> makefile('rb', None)
478 s> makefile('rb', None)
479 s> HTTP/1.1 200 Script output follows\r\n
479 s> HTTP/1.1 200 Script output follows\r\n
480 s> Server: testing stub value\r\n
480 s> Server: testing stub value\r\n
481 s> Date: $HTTP_DATE$\r\n
481 s> Date: $HTTP_DATE$\r\n
482 s> Content-Type: application/mercurial-0.1\r\n
482 s> Content-Type: application/mercurial-0.1\r\n
483 s> Content-Length: 41\r\n
483 s> Content-Length: 41\r\n
484 s> \r\n
484 s> \r\n
485 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
485 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
486 response: [
486 response: [
487 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
487 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
488 ]
488 ]
489 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
489 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
490
490
491 $ killdaemons.py
491 $ killdaemons.py
492
492
493 Now test a variation where we strip the query string from the redirect URL.
493 Now test a variation where we strip the query string from the redirect URL.
494 (SCM Manager apparently did this and clients would recover from it)
494 (SCM Manager apparently did this and clients would recover from it)
495
495
496 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
496 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
497 > --config server.compressionengines=zlib \
497 > --config server.compressionengines=zlib \
498 > --config testing.redirectqs=false \
498 > --config testing.redirectqs=false \
499 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
499 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
500 $ cat hg.pid > $DAEMON_PIDS
500 $ cat hg.pid > $DAEMON_PIDS
501
501
502 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
502 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
503 > httprequest GET /redirector?cmd=capabilities
503 > httprequest GET /redirector?cmd=capabilities
504 > user-agent: test
504 > user-agent: test
505 > EOF
505 > EOF
506 using raw connection to peer
506 using raw connection to peer
507 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
507 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
508 s> Accept-Encoding: identity\r\n
508 s> Accept-Encoding: identity\r\n
509 s> user-agent: test\r\n
509 s> user-agent: test\r\n
510 s> host: $LOCALIP:$HGPORT\r\n (glob)
510 s> host: $LOCALIP:$HGPORT\r\n (glob)
511 s> \r\n
511 s> \r\n
512 s> makefile('rb', None)
512 s> makefile('rb', None)
513 s> HTTP/1.1 301 Redirect\r\n
513 s> HTTP/1.1 301 Redirect\r\n
514 s> Server: testing stub value\r\n
514 s> Server: testing stub value\r\n
515 s> Date: $HTTP_DATE$\r\n
515 s> Date: $HTTP_DATE$\r\n
516 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
516 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
517 s> Content-Type: text/plain\r\n
517 s> Content-Type: text/plain\r\n
518 s> Content-Length: 10\r\n
518 s> Content-Length: 10\r\n
519 s> \r\n
519 s> \r\n
520 s> redirected
520 s> redirected
521 s> GET /redirected HTTP/1.1\r\n
521 s> GET /redirected HTTP/1.1\r\n
522 s> Accept-Encoding: identity\r\n
522 s> Accept-Encoding: identity\r\n
523 s> user-agent: test\r\n
523 s> user-agent: test\r\n
524 s> host: $LOCALIP:$HGPORT\r\n (glob)
524 s> host: $LOCALIP:$HGPORT\r\n (glob)
525 s> \r\n
525 s> \r\n
526 s> makefile('rb', None)
526 s> makefile('rb', None)
527 s> HTTP/1.1 200 Script output follows\r\n
527 s> HTTP/1.1 200 Script output follows\r\n
528 s> Server: testing stub value\r\n
528 s> Server: testing stub value\r\n
529 s> Date: $HTTP_DATE$\r\n
529 s> Date: $HTTP_DATE$\r\n
530 s> ETag: W/"*"\r\n (glob)
530 s> ETag: W/"*"\r\n (glob)
531 s> Content-Type: text/html; charset=ascii\r\n
531 s> Content-Type: text/html; charset=ascii\r\n
532 s> Transfer-Encoding: chunked\r\n
532 s> Transfer-Encoding: chunked\r\n
533 s> \r\n
533 s> \r\n
534 s> 414\r\n
534 s> 414\r\n
535 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
535 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
536 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
536 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
537 s> <head>\n
537 s> <head>\n
538 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
538 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
539 s> <meta name="robots" content="index, nofollow" />\n
539 s> <meta name="robots" content="index, nofollow" />\n
540 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
540 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
541 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
541 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
542 s> \n
542 s> \n
543 s> <title>redirected: log</title>\n
543 s> <title>redirected: log</title>\n
544 s> <link rel="alternate" type="application/atom+xml"\n
544 s> <link rel="alternate" type="application/atom+xml"\n
545 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
545 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
546 s> <link rel="alternate" type="application/rss+xml"\n
546 s> <link rel="alternate" type="application/rss+xml"\n
547 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
547 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
548 s> </head>\n
548 s> </head>\n
549 s> <body>\n
549 s> <body>\n
550 s> \n
550 s> \n
551 s> <div class="container">\n
551 s> <div class="container">\n
552 s> <div class="menu">\n
552 s> <div class="menu">\n
553 s> <div class="logo">\n
553 s> <div class="logo">\n
554 s> <a href="https://mercurial-scm.org/">\n
554 s> <a href="https://mercurial-scm.org/">\n
555 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
555 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
556 s> </div>\n
556 s> </div>\n
557 s> <ul>\n
557 s> <ul>\n
558 s> <li class="active">log</li>\n
558 s> <li class="active">log</li>\n
559 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
559 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
560 s> <li><a href="/redirected/tags">tags</a></li>\n
560 s> <li><a href="/redirected/tags">tags</a></li>\n
561 s> <li><a href="
561 s> <li><a href="
562 s> \r\n
562 s> \r\n
563 s> 810\r\n
563 s> 810\r\n
564 s> /redirected/bookmarks">bookmarks</a></li>\n
564 s> /redirected/bookmarks">bookmarks</a></li>\n
565 s> <li><a href="/redirected/branches">branches</a></li>\n
565 s> <li><a href="/redirected/branches">branches</a></li>\n
566 s> </ul>\n
566 s> </ul>\n
567 s> <ul>\n
567 s> <ul>\n
568 s> <li><a href="/redirected/rev/tip">changeset</a></li>\n
568 s> <li><a href="/redirected/rev/tip">changeset</a></li>\n
569 s> <li><a href="/redirected/file/tip">browse</a></li>\n
569 s> <li><a href="/redirected/file/tip">browse</a></li>\n
570 s> </ul>\n
570 s> </ul>\n
571 s> <ul>\n
571 s> <ul>\n
572 s> \n
572 s> \n
573 s> </ul>\n
573 s> </ul>\n
574 s> <ul>\n
574 s> <ul>\n
575 s> <li><a href="/redirected/help">help</a></li>\n
575 s> <li><a href="/redirected/help">help</a></li>\n
576 s> </ul>\n
576 s> </ul>\n
577 s> <div class="atom-logo">\n
577 s> <div class="atom-logo">\n
578 s> <a href="/redirected/atom-log" title="subscribe to atom feed">\n
578 s> <a href="/redirected/atom-log" title="subscribe to atom feed">\n
579 s> <img class="atom-logo" src="/redirected/static/feed-icon-14x14.png" alt="atom feed" />\n
579 s> <img class="atom-logo" src="/redirected/static/feed-icon-14x14.png" alt="atom feed" />\n
580 s> </a>\n
580 s> </a>\n
581 s> </div>\n
581 s> </div>\n
582 s> </div>\n
582 s> </div>\n
583 s> \n
583 s> \n
584 s> <div class="main">\n
584 s> <div class="main">\n
585 s> <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/redirected">redirected</a> </h2>\n
585 s> <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/redirected">redirected</a> </h2>\n
586 s> <h3>log</h3>\n
586 s> <h3>log</h3>\n
587 s> \n
587 s> \n
588 s> \n
588 s> \n
589 s> <form class="search" action="/redirected/log">\n
589 s> <form class="search" action="/redirected/log">\n
590 s> \n
590 s> \n
591 s> <p><input name="rev" id="search1" type="text" size="30" value="" /></p>\n
591 s> <p><input name="rev" id="search1" type="text" size="30" value="" /></p>\n
592 s> <div id="hint">Find changesets by keywords (author, files, the commit message), revision\n
592 s> <div id="hint">Find changesets by keywords (author, files, the commit message), revision\n
593 s> number or hash, or <a href="/redirected/help/revsets">revset expression</a>.</div>\n
593 s> number or hash, or <a href="/redirected/help/revsets">revset expression</a>.</div>\n
594 s> </form>\n
594 s> </form>\n
595 s> \n
595 s> \n
596 s> <div class="navigate">\n
596 s> <div class="navigate">\n
597 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
597 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
598 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
598 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
599 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
599 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
600 s> </div>\n
600 s> </div>\n
601 s> \n
601 s> \n
602 s> <table class="bigtable">\n
602 s> <table class="bigtable">\n
603 s> <thead>\n
603 s> <thead>\n
604 s> <tr>\n
604 s> <tr>\n
605 s> <th class="age">age</th>\n
605 s> <th class="age">age</th>\n
606 s> <th class="author">author</th>\n
606 s> <th class="author">author</th>\n
607 s> <th class="description">description</th>\n
607 s> <th class="description">description</th>\n
608 s> </tr>\n
608 s> </tr>\n
609 s> </thead>\n
609 s> </thead>\n
610 s> <tbody class="stripes2">\n
610 s> <tbody class="stripes2">\n
611 s> <tr>\n
611 s> <tr>\n
612 s> <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>\n
612 s> <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>\n
613 s> <td class="author">test</td>\n
613 s> <td class="author">test</td>\n
614 s> <td class="description">\n
614 s> <td class="description">\n
615 s> <a href="/redirected/rev/96ee1d7354c4">initial</a>\n
615 s> <a href="/redirected/rev/96ee1d7354c4">initial</a>\n
616 s> <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span> \n
616 s> <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span> \n
617 s> </td>\n
617 s> </td>\n
618 s> </tr>\n
618 s> </tr>\n
619 s> \n
619 s> \n
620 s> </tbody>\n
620 s> </tbody>\n
621 s> </table>\n
621 s> </table>\n
622 s> \n
622 s> \n
623 s> <div class="navigate">\n
623 s> <div class="navigate">\n
624 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
624 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
625 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
625 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
626 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
626 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
627 s> </div>\n
627 s> </div>\n
628 s> \n
628 s> \n
629 s> <script type="text/javascript">\n
629 s> <script type="text/javascript">\n
630 s> ajaxScrollInit(\n
630 s> ajaxScrollInit(\n
631 s> \'/redirected/shortlog/%next%\',\n
631 s> \'/redirected/shortlog/%next%\',\n
632 s> \'\', <!-- NEXTHASH\n
632 s> \'\', <!-- NEXTHASH\n
633 s> function (htmlText) {
633 s> function (htmlText) {
634 s> \r\n
634 s> \r\n
635 s> 14a\r\n
635 s> 14a\r\n
636 s> \n
636 s> \n
637 s> var m = htmlText.match(/\'(\\w+)\', <!-- NEXTHASH/);\n
637 s> var m = htmlText.match(/\'(\\w+)\', <!-- NEXTHASH/);\n
638 s> return m ? m[1] : null;\n
638 s> return m ? m[1] : null;\n
639 s> },\n
639 s> },\n
640 s> \'.bigtable > tbody\',\n
640 s> \'.bigtable > tbody\',\n
641 s> \'<tr class="%class%">\\\n
641 s> \'<tr class="%class%">\\\n
642 s> <td colspan="3" style="text-align: center;">%text%</td>\\\n
642 s> <td colspan="3" style="text-align: center;">%text%</td>\\\n
643 s> </tr>\'\n
643 s> </tr>\'\n
644 s> );\n
644 s> );\n
645 s> </script>\n
645 s> </script>\n
646 s> \n
646 s> \n
647 s> </div>\n
647 s> </div>\n
648 s> </div>\n
648 s> </div>\n
649 s> \n
649 s> \n
650 s> \n
650 s> \n
651 s> \n
651 s> \n
652 s> </body>\n
652 s> </body>\n
653 s> </html>\n
653 s> </html>\n
654 s> \n
654 s> \n
655 s> \r\n
655 s> \r\n
656 s> 0\r\n
656 s> 0\r\n
657 s> \r\n
657 s> \r\n
658
658
659 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
659 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
660 > command heads
660 > command heads
661 > EOF
661 > EOF
662 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
662 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
663 s> Accept-Encoding: identity\r\n
663 s> Accept-Encoding: identity\r\n
664 s> accept: application/mercurial-0.1\r\n
664 s> accept: application/mercurial-0.1\r\n
665 s> host: $LOCALIP:$HGPORT\r\n (glob)
665 s> host: $LOCALIP:$HGPORT\r\n (glob)
666 s> user-agent: Mercurial debugwireproto\r\n
666 s> user-agent: Mercurial debugwireproto\r\n
667 s> \r\n
667 s> \r\n
668 s> makefile('rb', None)
668 s> makefile('rb', None)
669 s> HTTP/1.1 301 Redirect\r\n
669 s> HTTP/1.1 301 Redirect\r\n
670 s> Server: testing stub value\r\n
670 s> Server: testing stub value\r\n
671 s> Date: $HTTP_DATE$\r\n
671 s> Date: $HTTP_DATE$\r\n
672 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
672 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
673 s> Content-Type: text/plain\r\n
673 s> Content-Type: text/plain\r\n
674 s> Content-Length: 10\r\n
674 s> Content-Length: 10\r\n
675 s> \r\n
675 s> \r\n
676 s> redirected
676 s> redirected
677 s> GET /redirected HTTP/1.1\r\n
677 s> GET /redirected HTTP/1.1\r\n
678 s> Accept-Encoding: identity\r\n
678 s> Accept-Encoding: identity\r\n
679 s> accept: application/mercurial-0.1\r\n
679 s> accept: application/mercurial-0.1\r\n
680 s> host: $LOCALIP:$HGPORT\r\n (glob)
680 s> host: $LOCALIP:$HGPORT\r\n (glob)
681 s> user-agent: Mercurial debugwireproto\r\n
681 s> user-agent: Mercurial debugwireproto\r\n
682 s> \r\n
682 s> \r\n
683 s> makefile('rb', None)
683 s> makefile('rb', None)
684 s> HTTP/1.1 200 Script output follows\r\n
684 s> HTTP/1.1 200 Script output follows\r\n
685 s> Server: testing stub value\r\n
685 s> Server: testing stub value\r\n
686 s> Date: $HTTP_DATE$\r\n
686 s> Date: $HTTP_DATE$\r\n
687 s> ETag: W/"*"\r\n (glob)
687 s> ETag: W/"*"\r\n (glob)
688 s> Content-Type: text/html; charset=ascii\r\n
688 s> Content-Type: text/html; charset=ascii\r\n
689 s> Transfer-Encoding: chunked\r\n
689 s> Transfer-Encoding: chunked\r\n
690 s> \r\n
690 s> \r\n
691 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
691 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
692 s> 414\r\n
692 s> 414\r\n
693 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
693 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
694 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
694 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
695 s> <head>\n
695 s> <head>\n
696 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
696 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
697 s> <meta name="robots" content="index, nofollow" />\n
697 s> <meta name="robots" content="index, nofollow" />\n
698 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
698 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
699 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
699 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
700 s> \n
700 s> \n
701 s> <title>redirected: log</title>\n
701 s> <title>redirected: log</title>\n
702 s> <link rel="alternate" type="application/atom+xml"\n
702 s> <link rel="alternate" type="application/atom+xml"\n
703 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
703 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
704 s> <link rel="alternate" type="application/rss+xml"\n
704 s> <link rel="alternate" type="application/rss+xml"\n
705 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
705 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
706 s> </head>\n
706 s> </head>\n
707 s> <body>\n
707 s> <body>\n
708 s> \n
708 s> \n
709 s> <div class="container">\n
709 s> <div class="container">\n
710 s> <div class="menu">\n
710 s> <div class="menu">\n
711 s> <div class="logo">\n
711 s> <div class="logo">\n
712 s> <a href="https://mercurial-scm.org/">\n
712 s> <a href="https://mercurial-scm.org/">\n
713 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
713 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
714 s> </div>\n
714 s> </div>\n
715 s> <ul>\n
715 s> <ul>\n
716 s> <li class="active">log</li>\n
716 s> <li class="active">log</li>\n
717 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
717 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
718 s> <li><a href="/redirected/tags">tags</a
718 s> <li><a href="/redirected/tags">tags</a
719 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
719 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
720 s> Accept-Encoding: identity\r\n
720 s> Accept-Encoding: identity\r\n
721 s> accept: application/mercurial-0.1\r\n
721 s> accept: application/mercurial-0.1\r\n
722 s> host: $LOCALIP:$HGPORT\r\n (glob)
722 s> host: $LOCALIP:$HGPORT\r\n (glob)
723 s> user-agent: Mercurial debugwireproto\r\n
723 s> user-agent: Mercurial debugwireproto\r\n
724 s> \r\n
724 s> \r\n
725 s> makefile('rb', None)
725 s> makefile('rb', None)
726 s> HTTP/1.1 200 Script output follows\r\n
726 s> HTTP/1.1 200 Script output follows\r\n
727 s> Server: testing stub value\r\n
727 s> Server: testing stub value\r\n
728 s> Date: $HTTP_DATE$\r\n
728 s> Date: $HTTP_DATE$\r\n
729 s> Content-Type: application/mercurial-0.1\r\n
729 s> Content-Type: application/mercurial-0.1\r\n
730 s> Content-Length: 467\r\n
730 s> Content-Length: 467\r\n
731 s> \r\n
731 s> \r\n
732 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
732 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
733 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
733 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
734 sending heads command
734 sending heads command
735 s> GET /redirected?cmd=heads HTTP/1.1\r\n
735 s> GET /redirected?cmd=heads HTTP/1.1\r\n
736 s> Accept-Encoding: identity\r\n
736 s> Accept-Encoding: identity\r\n
737 s> vary: X-HgProto-1\r\n
737 s> vary: X-HgProto-1\r\n
738 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
738 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
739 s> accept: application/mercurial-0.1\r\n
739 s> accept: application/mercurial-0.1\r\n
740 s> host: $LOCALIP:$HGPORT\r\n (glob)
740 s> host: $LOCALIP:$HGPORT\r\n (glob)
741 s> user-agent: Mercurial debugwireproto\r\n
741 s> user-agent: Mercurial debugwireproto\r\n
742 s> \r\n
742 s> \r\n
743 s> makefile('rb', None)
743 s> makefile('rb', None)
744 s> HTTP/1.1 200 Script output follows\r\n
744 s> HTTP/1.1 200 Script output follows\r\n
745 s> Server: testing stub value\r\n
745 s> Server: testing stub value\r\n
746 s> Date: $HTTP_DATE$\r\n
746 s> Date: $HTTP_DATE$\r\n
747 s> Content-Type: application/mercurial-0.1\r\n
747 s> Content-Type: application/mercurial-0.1\r\n
748 s> Content-Length: 41\r\n
748 s> Content-Length: 41\r\n
749 s> \r\n
749 s> \r\n
750 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
750 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
751 response: [
751 response: [
752 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
752 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
753 ]
753 ]
754 (sent 4 HTTP requests and * bytes; received * bytes in responses) (glob)
754 (sent 4 HTTP requests and * bytes; received * bytes in responses) (glob)
@@ -1,430 +1,422
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 c045a581599d58608efd3d93d8129841f2af04a0 (glob)
124 *> cache miss for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
125 *> storing cache entry for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
125 *> storing cache entry for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
126 *> cacher constructed for manifestdata (glob)
126 *> cacher constructed for manifestdata (glob)
127 *> cache hit for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
127 *> cache hit for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
128 *> cacher constructed for manifestdata (glob)
128 *> cacher constructed for manifestdata (glob)
129 *> cache miss for 6ed2f740a1cdd12c9e99c4f27695543143c26a11 (glob)
129 *> cache miss for 6ed2f740a1cdd12c9e99c4f27695543143c26a11 (glob)
130 *> storing cache entry for 6ed2f740a1cdd12c9e99c4f27695543143c26a11 (glob)
130 *> storing cache entry for 6ed2f740a1cdd12c9e99c4f27695543143c26a11 (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 c045a581599d58608efd3d93d8129841f2af04a0 (glob)
191 *> cache miss for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
192 *> storing cache entry for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
192 *> storing cache entry for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
193 *> cacher constructed for manifestdata (glob)
193 *> cacher constructed for manifestdata (glob)
194 *> cache hit for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
194 *> cache hit for c045a581599d58608efd3d93d8129841f2af04a0 (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'noderange': {
238 b'noderange': {
239 b'default': None,
239 b'default': None,
240 b'required': False,
240 b'required': False,
241 b'type': b'list'
241 b'type': b'list'
242 },
242 },
243 b'nodes': {
243 b'nodes': {
244 b'default': None,
244 b'default': None,
245 b'required': False,
245 b'required': False,
246 b'type': b'list'
246 b'type': b'list'
247 },
247 },
248 b'nodesdepth': {
248 b'nodesdepth': {
249 b'default': None,
249 b'default': None,
250 b'required': False,
250 b'required': False,
251 b'type': b'int'
251 b'type': b'int'
252 }
252 }
253 },
253 },
254 b'permissions': [
254 b'permissions': [
255 b'pull'
255 b'pull'
256 ]
256 ]
257 },
257 },
258 b'filedata': {
258 b'filedata': {
259 b'args': {
259 b'args': {
260 b'fields': {
260 b'fields': {
261 b'default': set([]),
261 b'default': set([]),
262 b'required': False,
262 b'required': False,
263 b'type': b'set',
263 b'type': b'set',
264 b'validvalues': set([
264 b'validvalues': set([
265 b'parents',
265 b'parents',
266 b'revision'
266 b'revision'
267 ])
267 ])
268 },
268 },
269 b'haveparents': {
269 b'haveparents': {
270 b'default': False,
270 b'default': False,
271 b'required': False,
271 b'required': False,
272 b'type': b'bool'
272 b'type': b'bool'
273 },
273 },
274 b'nodes': {
274 b'nodes': {
275 b'required': True,
275 b'required': True,
276 b'type': b'list'
276 b'type': b'list'
277 },
277 },
278 b'path': {
278 b'path': {
279 b'required': True,
279 b'required': True,
280 b'type': b'bytes'
280 b'type': b'bytes'
281 }
281 }
282 },
282 },
283 b'permissions': [
283 b'permissions': [
284 b'pull'
284 b'pull'
285 ]
285 ]
286 },
286 },
287 b'heads': {
287 b'heads': {
288 b'args': {
288 b'args': {
289 b'publiconly': {
289 b'publiconly': {
290 b'default': False,
290 b'default': False,
291 b'required': False,
291 b'required': False,
292 b'type': b'bool'
292 b'type': b'bool'
293 }
293 }
294 },
294 },
295 b'permissions': [
295 b'permissions': [
296 b'pull'
296 b'pull'
297 ]
297 ]
298 },
298 },
299 b'known': {
299 b'known': {
300 b'args': {
300 b'args': {
301 b'nodes': {
301 b'nodes': {
302 b'default': [],
302 b'default': [],
303 b'required': False,
303 b'required': False,
304 b'type': b'list'
304 b'type': b'list'
305 }
305 }
306 },
306 },
307 b'permissions': [
307 b'permissions': [
308 b'pull'
308 b'pull'
309 ]
309 ]
310 },
310 },
311 b'listkeys': {
311 b'listkeys': {
312 b'args': {
312 b'args': {
313 b'namespace': {
313 b'namespace': {
314 b'required': True,
314 b'required': True,
315 b'type': b'bytes'
315 b'type': b'bytes'
316 }
316 }
317 },
317 },
318 b'permissions': [
318 b'permissions': [
319 b'pull'
319 b'pull'
320 ]
320 ]
321 },
321 },
322 b'lookup': {
322 b'lookup': {
323 b'args': {
323 b'args': {
324 b'key': {
324 b'key': {
325 b'required': True,
325 b'required': True,
326 b'type': b'bytes'
326 b'type': b'bytes'
327 }
327 }
328 },
328 },
329 b'permissions': [
329 b'permissions': [
330 b'pull'
330 b'pull'
331 ]
331 ]
332 },
332 },
333 b'manifestdata': {
333 b'manifestdata': {
334 b'args': {
334 b'args': {
335 b'fields': {
335 b'fields': {
336 b'default': set([]),
336 b'default': set([]),
337 b'required': False,
337 b'required': False,
338 b'type': b'set',
338 b'type': b'set',
339 b'validvalues': set([
339 b'validvalues': set([
340 b'parents',
340 b'parents',
341 b'revision'
341 b'revision'
342 ])
342 ])
343 },
343 },
344 b'haveparents': {
344 b'haveparents': {
345 b'default': False,
345 b'default': False,
346 b'required': False,
346 b'required': False,
347 b'type': b'bool'
347 b'type': b'bool'
348 },
348 },
349 b'nodes': {
349 b'nodes': {
350 b'required': True,
350 b'required': True,
351 b'type': b'list'
351 b'type': b'list'
352 },
352 },
353 b'tree': {
353 b'tree': {
354 b'required': True,
354 b'required': True,
355 b'type': b'bytes'
355 b'type': b'bytes'
356 }
356 }
357 },
357 },
358 b'permissions': [
358 b'permissions': [
359 b'pull'
359 b'pull'
360 ]
360 ]
361 },
361 },
362 b'pushkey': {
362 b'pushkey': {
363 b'args': {
363 b'args': {
364 b'key': {
364 b'key': {
365 b'required': True,
365 b'required': True,
366 b'type': b'bytes'
366 b'type': b'bytes'
367 },
367 },
368 b'namespace': {
368 b'namespace': {
369 b'required': True,
369 b'required': True,
370 b'type': b'bytes'
370 b'type': b'bytes'
371 },
371 },
372 b'new': {
372 b'new': {
373 b'required': True,
373 b'required': True,
374 b'type': b'bytes'
374 b'type': b'bytes'
375 },
375 },
376 b'old': {
376 b'old': {
377 b'required': True,
377 b'required': True,
378 b'type': b'bytes'
378 b'type': b'bytes'
379 }
379 }
380 },
380 },
381 b'permissions': [
381 b'permissions': [
382 b'push'
382 b'push'
383 ]
383 ]
384 }
384 }
385 },
385 },
386 b'compression': [
387 {
388 b'name': b'zstd'
389 },
390 {
391 b'name': b'zlib'
392 }
393 ],
394 b'framingmediatypes': [
386 b'framingmediatypes': [
395 b'application/mercurial-exp-framing-0005'
387 b'application/mercurial-exp-framing-0005'
396 ],
388 ],
397 b'pathfilterprefixes': set([
389 b'pathfilterprefixes': set([
398 b'path:',
390 b'path:',
399 b'rootfilesin:'
391 b'rootfilesin:'
400 ]),
392 ]),
401 b'rawrepoformats': [
393 b'rawrepoformats': [
402 b'generaldelta',
394 b'generaldelta',
403 b'revlogv1'
395 b'revlogv1'
404 ]
396 ]
405 }
397 }
406 ]
398 ]
407
399
408 $ test -f .hg/blackbox.log
400 $ test -f .hg/blackbox.log
409 [1]
401 [1]
410
402
411 An error is not cached
403 An error is not cached
412
404
413 $ sendhttpv2peer << EOF
405 $ sendhttpv2peer << EOF
414 > command manifestdata
406 > command manifestdata
415 > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
407 > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
416 > tree eval:b''
408 > tree eval:b''
417 > fields eval:[b'parents']
409 > fields eval:[b'parents']
418 > EOF
410 > EOF
419 creating http peer for wire protocol version 2
411 creating http peer for wire protocol version 2
420 sending manifestdata command
412 sending manifestdata command
421 abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa! (esc)
413 abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa! (esc)
422 [255]
414 [255]
423
415
424 $ cat .hg/blackbox.log
416 $ cat .hg/blackbox.log
425 *> cacher constructed for manifestdata (glob)
417 *> cacher constructed for manifestdata (glob)
426 *> cache miss for 9d1bb421d99e913d45f2d099aa49728514292dd2 (glob)
418 *> cache miss for 9d1bb421d99e913d45f2d099aa49728514292dd2 (glob)
427 *> cacher exiting due to error (glob)
419 *> cacher exiting due to error (glob)
428
420
429 $ killdaemons.py
421 $ killdaemons.py
430 $ rm .hg/blackbox.log
422 $ rm .hg/blackbox.log
@@ -1,673 +1,663
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-0002 foo bar
201 > x-hgupgrade-1: exp-http-v2-0002 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-0002 foo bar\r\n
209 s> x-hgupgrade-1: exp-http-v2-0002 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-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\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-0002\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\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-0002': {
224 b'exp-http-v2-0002': {
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'noderange': {
251 b'noderange': {
252 b'default': None,
252 b'default': None,
253 b'required': False,
253 b'required': False,
254 b'type': b'list'
254 b'type': b'list'
255 },
255 },
256 b'nodes': {
256 b'nodes': {
257 b'default': None,
257 b'default': None,
258 b'required': False,
258 b'required': False,
259 b'type': b'list'
259 b'type': b'list'
260 },
260 },
261 b'nodesdepth': {
261 b'nodesdepth': {
262 b'default': None,
262 b'default': None,
263 b'required': False,
263 b'required': False,
264 b'type': b'int'
264 b'type': b'int'
265 }
265 }
266 },
266 },
267 b'permissions': [
267 b'permissions': [
268 b'pull'
268 b'pull'
269 ]
269 ]
270 },
270 },
271 b'filedata': {
271 b'filedata': {
272 b'args': {
272 b'args': {
273 b'fields': {
273 b'fields': {
274 b'default': set([]),
274 b'default': set([]),
275 b'required': False,
275 b'required': False,
276 b'type': b'set',
276 b'type': b'set',
277 b'validvalues': set([
277 b'validvalues': set([
278 b'parents',
278 b'parents',
279 b'revision'
279 b'revision'
280 ])
280 ])
281 },
281 },
282 b'haveparents': {
282 b'haveparents': {
283 b'default': False,
283 b'default': False,
284 b'required': False,
284 b'required': False,
285 b'type': b'bool'
285 b'type': b'bool'
286 },
286 },
287 b'nodes': {
287 b'nodes': {
288 b'required': True,
288 b'required': True,
289 b'type': b'list'
289 b'type': b'list'
290 },
290 },
291 b'path': {
291 b'path': {
292 b'required': True,
292 b'required': True,
293 b'type': b'bytes'
293 b'type': b'bytes'
294 }
294 }
295 },
295 },
296 b'permissions': [
296 b'permissions': [
297 b'pull'
297 b'pull'
298 ]
298 ]
299 },
299 },
300 b'heads': {
300 b'heads': {
301 b'args': {
301 b'args': {
302 b'publiconly': {
302 b'publiconly': {
303 b'default': False,
303 b'default': False,
304 b'required': False,
304 b'required': False,
305 b'type': b'bool'
305 b'type': b'bool'
306 }
306 }
307 },
307 },
308 b'permissions': [
308 b'permissions': [
309 b'pull'
309 b'pull'
310 ]
310 ]
311 },
311 },
312 b'known': {
312 b'known': {
313 b'args': {
313 b'args': {
314 b'nodes': {
314 b'nodes': {
315 b'default': [],
315 b'default': [],
316 b'required': False,
316 b'required': False,
317 b'type': b'list'
317 b'type': b'list'
318 }
318 }
319 },
319 },
320 b'permissions': [
320 b'permissions': [
321 b'pull'
321 b'pull'
322 ]
322 ]
323 },
323 },
324 b'listkeys': {
324 b'listkeys': {
325 b'args': {
325 b'args': {
326 b'namespace': {
326 b'namespace': {
327 b'required': True,
327 b'required': True,
328 b'type': b'bytes'
328 b'type': b'bytes'
329 }
329 }
330 },
330 },
331 b'permissions': [
331 b'permissions': [
332 b'pull'
332 b'pull'
333 ]
333 ]
334 },
334 },
335 b'lookup': {
335 b'lookup': {
336 b'args': {
336 b'args': {
337 b'key': {
337 b'key': {
338 b'required': True,
338 b'required': True,
339 b'type': b'bytes'
339 b'type': b'bytes'
340 }
340 }
341 },
341 },
342 b'permissions': [
342 b'permissions': [
343 b'pull'
343 b'pull'
344 ]
344 ]
345 },
345 },
346 b'manifestdata': {
346 b'manifestdata': {
347 b'args': {
347 b'args': {
348 b'fields': {
348 b'fields': {
349 b'default': set([]),
349 b'default': set([]),
350 b'required': False,
350 b'required': False,
351 b'type': b'set',
351 b'type': b'set',
352 b'validvalues': set([
352 b'validvalues': set([
353 b'parents',
353 b'parents',
354 b'revision'
354 b'revision'
355 ])
355 ])
356 },
356 },
357 b'haveparents': {
357 b'haveparents': {
358 b'default': False,
358 b'default': False,
359 b'required': False,
359 b'required': False,
360 b'type': b'bool'
360 b'type': b'bool'
361 },
361 },
362 b'nodes': {
362 b'nodes': {
363 b'required': True,
363 b'required': True,
364 b'type': b'list'
364 b'type': b'list'
365 },
365 },
366 b'tree': {
366 b'tree': {
367 b'required': True,
367 b'required': True,
368 b'type': b'bytes'
368 b'type': b'bytes'
369 }
369 }
370 },
370 },
371 b'permissions': [
371 b'permissions': [
372 b'pull'
372 b'pull'
373 ]
373 ]
374 },
374 },
375 b'pushkey': {
375 b'pushkey': {
376 b'args': {
376 b'args': {
377 b'key': {
377 b'key': {
378 b'required': True,
378 b'required': True,
379 b'type': b'bytes'
379 b'type': b'bytes'
380 },
380 },
381 b'namespace': {
381 b'namespace': {
382 b'required': True,
382 b'required': True,
383 b'type': b'bytes'
383 b'type': b'bytes'
384 },
384 },
385 b'new': {
385 b'new': {
386 b'required': True,
386 b'required': True,
387 b'type': b'bytes'
387 b'type': b'bytes'
388 },
388 },
389 b'old': {
389 b'old': {
390 b'required': True,
390 b'required': True,
391 b'type': b'bytes'
391 b'type': b'bytes'
392 }
392 }
393 },
393 },
394 b'permissions': [
394 b'permissions': [
395 b'push'
395 b'push'
396 ]
396 ]
397 }
397 }
398 },
398 },
399 b'compression': [
400 {
401 b'name': b'zlib'
402 }
403 ],
404 b'framingmediatypes': [
399 b'framingmediatypes': [
405 b'application/mercurial-exp-framing-0005'
400 b'application/mercurial-exp-framing-0005'
406 ],
401 ],
407 b'pathfilterprefixes': set([
402 b'pathfilterprefixes': set([
408 b'path:',
403 b'path:',
409 b'rootfilesin:'
404 b'rootfilesin:'
410 ]),
405 ]),
411 b'rawrepoformats': [
406 b'rawrepoformats': [
412 b'generaldelta',
407 b'generaldelta',
413 b'revlogv1'
408 b'revlogv1'
414 ]
409 ]
415 }
410 }
416 },
411 },
417 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'
412 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'
418 }
413 }
419 ]
414 ]
420
415
421 capabilities command returns expected info
416 capabilities command returns expected info
422
417
423 $ sendhttpv2peerhandshake << EOF
418 $ sendhttpv2peerhandshake << EOF
424 > command capabilities
419 > command capabilities
425 > EOF
420 > EOF
426 creating http peer for wire protocol version 2
421 creating http peer for wire protocol version 2
427 s> GET /?cmd=capabilities HTTP/1.1\r\n
422 s> GET /?cmd=capabilities HTTP/1.1\r\n
428 s> Accept-Encoding: identity\r\n
423 s> Accept-Encoding: identity\r\n
429 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
424 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
430 s> x-hgproto-1: cbor\r\n
425 s> x-hgproto-1: cbor\r\n
431 s> x-hgupgrade-1: exp-http-v2-0002\r\n
426 s> x-hgupgrade-1: exp-http-v2-0002\r\n
432 s> accept: application/mercurial-0.1\r\n
427 s> accept: application/mercurial-0.1\r\n
433 s> host: $LOCALIP:$HGPORT\r\n (glob)
428 s> host: $LOCALIP:$HGPORT\r\n (glob)
434 s> user-agent: Mercurial debugwireproto\r\n
429 s> user-agent: Mercurial debugwireproto\r\n
435 s> \r\n
430 s> \r\n
436 s> makefile('rb', None)
431 s> makefile('rb', None)
437 s> HTTP/1.1 200 OK\r\n
432 s> HTTP/1.1 200 OK\r\n
438 s> Server: testing stub value\r\n
433 s> Server: testing stub value\r\n
439 s> Date: $HTTP_DATE$\r\n
434 s> Date: $HTTP_DATE$\r\n
440 s> Content-Type: application/mercurial-cbor\r\n
435 s> Content-Type: application/mercurial-cbor\r\n
441 s> Content-Length: *\r\n (glob)
436 s> Content-Length: *\r\n (glob)
442 s> \r\n
437 s> \r\n
443 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\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
438 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\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
444 sending capabilities command
439 sending capabilities command
445 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
440 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
446 s> Accept-Encoding: identity\r\n
441 s> Accept-Encoding: identity\r\n
447 s> accept: application/mercurial-exp-framing-0005\r\n
442 s> accept: application/mercurial-exp-framing-0005\r\n
448 s> content-type: application/mercurial-exp-framing-0005\r\n
443 s> content-type: application/mercurial-exp-framing-0005\r\n
449 s> content-length: 27\r\n
444 s> content-length: 27\r\n
450 s> host: $LOCALIP:$HGPORT\r\n (glob)
445 s> host: $LOCALIP:$HGPORT\r\n (glob)
451 s> user-agent: Mercurial debugwireproto\r\n
446 s> user-agent: Mercurial debugwireproto\r\n
452 s> \r\n
447 s> \r\n
453 s> \x13\x00\x00\x01\x00\x01\x01\x11\xa1DnameLcapabilities
448 s> \x13\x00\x00\x01\x00\x01\x01\x11\xa1DnameLcapabilities
454 s> makefile('rb', None)
449 s> makefile('rb', None)
455 s> HTTP/1.1 200 OK\r\n
450 s> HTTP/1.1 200 OK\r\n
456 s> Server: testing stub value\r\n
451 s> Server: testing stub value\r\n
457 s> Date: $HTTP_DATE$\r\n
452 s> Date: $HTTP_DATE$\r\n
458 s> Content-Type: application/mercurial-exp-framing-0005\r\n
453 s> Content-Type: application/mercurial-exp-framing-0005\r\n
459 s> Transfer-Encoding: chunked\r\n
454 s> Transfer-Encoding: chunked\r\n
460 s> \r\n
455 s> \r\n
461 s> 13\r\n
456 s> 13\r\n
462 s> \x0b\x00\x00\x01\x00\x02\x011
457 s> \x0b\x00\x00\x01\x00\x02\x011
463 s> \xa1FstatusBok
458 s> \xa1FstatusBok
464 s> \r\n
459 s> \r\n
465 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
460 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
466 s> 520\r\n
461 s> 508\r\n
467 s> \x18\x05\x00\x01\x00\x02\x001
462 s> \x00\x05\x00\x01\x00\x02\x001
468 s> \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1
463 s> \xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1
469 s> \r\n
464 s> \r\n
470 received frame(size=1304; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
465 received frame(size=1280; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
471 s> 8\r\n
466 s> 8\r\n
472 s> \x00\x00\x00\x01\x00\x02\x002
467 s> \x00\x00\x00\x01\x00\x02\x002
473 s> \r\n
468 s> \r\n
474 s> 0\r\n
469 s> 0\r\n
475 s> \r\n
470 s> \r\n
476 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
471 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
477 response: gen[
472 response: gen[
478 {
473 {
479 b'commands': {
474 b'commands': {
480 b'branchmap': {
475 b'branchmap': {
481 b'args': {},
476 b'args': {},
482 b'permissions': [
477 b'permissions': [
483 b'pull'
478 b'pull'
484 ]
479 ]
485 },
480 },
486 b'capabilities': {
481 b'capabilities': {
487 b'args': {},
482 b'args': {},
488 b'permissions': [
483 b'permissions': [
489 b'pull'
484 b'pull'
490 ]
485 ]
491 },
486 },
492 b'changesetdata': {
487 b'changesetdata': {
493 b'args': {
488 b'args': {
494 b'fields': {
489 b'fields': {
495 b'default': set([]),
490 b'default': set([]),
496 b'required': False,
491 b'required': False,
497 b'type': b'set',
492 b'type': b'set',
498 b'validvalues': set([
493 b'validvalues': set([
499 b'bookmarks',
494 b'bookmarks',
500 b'parents',
495 b'parents',
501 b'phase',
496 b'phase',
502 b'revision'
497 b'revision'
503 ])
498 ])
504 },
499 },
505 b'noderange': {
500 b'noderange': {
506 b'default': None,
501 b'default': None,
507 b'required': False,
502 b'required': False,
508 b'type': b'list'
503 b'type': b'list'
509 },
504 },
510 b'nodes': {
505 b'nodes': {
511 b'default': None,
506 b'default': None,
512 b'required': False,
507 b'required': False,
513 b'type': b'list'
508 b'type': b'list'
514 },
509 },
515 b'nodesdepth': {
510 b'nodesdepth': {
516 b'default': None,
511 b'default': None,
517 b'required': False,
512 b'required': False,
518 b'type': b'int'
513 b'type': b'int'
519 }
514 }
520 },
515 },
521 b'permissions': [
516 b'permissions': [
522 b'pull'
517 b'pull'
523 ]
518 ]
524 },
519 },
525 b'filedata': {
520 b'filedata': {
526 b'args': {
521 b'args': {
527 b'fields': {
522 b'fields': {
528 b'default': set([]),
523 b'default': set([]),
529 b'required': False,
524 b'required': False,
530 b'type': b'set',
525 b'type': b'set',
531 b'validvalues': set([
526 b'validvalues': set([
532 b'parents',
527 b'parents',
533 b'revision'
528 b'revision'
534 ])
529 ])
535 },
530 },
536 b'haveparents': {
531 b'haveparents': {
537 b'default': False,
532 b'default': False,
538 b'required': False,
533 b'required': False,
539 b'type': b'bool'
534 b'type': b'bool'
540 },
535 },
541 b'nodes': {
536 b'nodes': {
542 b'required': True,
537 b'required': True,
543 b'type': b'list'
538 b'type': b'list'
544 },
539 },
545 b'path': {
540 b'path': {
546 b'required': True,
541 b'required': True,
547 b'type': b'bytes'
542 b'type': b'bytes'
548 }
543 }
549 },
544 },
550 b'permissions': [
545 b'permissions': [
551 b'pull'
546 b'pull'
552 ]
547 ]
553 },
548 },
554 b'heads': {
549 b'heads': {
555 b'args': {
550 b'args': {
556 b'publiconly': {
551 b'publiconly': {
557 b'default': False,
552 b'default': False,
558 b'required': False,
553 b'required': False,
559 b'type': b'bool'
554 b'type': b'bool'
560 }
555 }
561 },
556 },
562 b'permissions': [
557 b'permissions': [
563 b'pull'
558 b'pull'
564 ]
559 ]
565 },
560 },
566 b'known': {
561 b'known': {
567 b'args': {
562 b'args': {
568 b'nodes': {
563 b'nodes': {
569 b'default': [],
564 b'default': [],
570 b'required': False,
565 b'required': False,
571 b'type': b'list'
566 b'type': b'list'
572 }
567 }
573 },
568 },
574 b'permissions': [
569 b'permissions': [
575 b'pull'
570 b'pull'
576 ]
571 ]
577 },
572 },
578 b'listkeys': {
573 b'listkeys': {
579 b'args': {
574 b'args': {
580 b'namespace': {
575 b'namespace': {
581 b'required': True,
576 b'required': True,
582 b'type': b'bytes'
577 b'type': b'bytes'
583 }
578 }
584 },
579 },
585 b'permissions': [
580 b'permissions': [
586 b'pull'
581 b'pull'
587 ]
582 ]
588 },
583 },
589 b'lookup': {
584 b'lookup': {
590 b'args': {
585 b'args': {
591 b'key': {
586 b'key': {
592 b'required': True,
587 b'required': True,
593 b'type': b'bytes'
588 b'type': b'bytes'
594 }
589 }
595 },
590 },
596 b'permissions': [
591 b'permissions': [
597 b'pull'
592 b'pull'
598 ]
593 ]
599 },
594 },
600 b'manifestdata': {
595 b'manifestdata': {
601 b'args': {
596 b'args': {
602 b'fields': {
597 b'fields': {
603 b'default': set([]),
598 b'default': set([]),
604 b'required': False,
599 b'required': False,
605 b'type': b'set',
600 b'type': b'set',
606 b'validvalues': set([
601 b'validvalues': set([
607 b'parents',
602 b'parents',
608 b'revision'
603 b'revision'
609 ])
604 ])
610 },
605 },
611 b'haveparents': {
606 b'haveparents': {
612 b'default': False,
607 b'default': False,
613 b'required': False,
608 b'required': False,
614 b'type': b'bool'
609 b'type': b'bool'
615 },
610 },
616 b'nodes': {
611 b'nodes': {
617 b'required': True,
612 b'required': True,
618 b'type': b'list'
613 b'type': b'list'
619 },
614 },
620 b'tree': {
615 b'tree': {
621 b'required': True,
616 b'required': True,
622 b'type': b'bytes'
617 b'type': b'bytes'
623 }
618 }
624 },
619 },
625 b'permissions': [
620 b'permissions': [
626 b'pull'
621 b'pull'
627 ]
622 ]
628 },
623 },
629 b'pushkey': {
624 b'pushkey': {
630 b'args': {
625 b'args': {
631 b'key': {
626 b'key': {
632 b'required': True,
627 b'required': True,
633 b'type': b'bytes'
628 b'type': b'bytes'
634 },
629 },
635 b'namespace': {
630 b'namespace': {
636 b'required': True,
631 b'required': True,
637 b'type': b'bytes'
632 b'type': b'bytes'
638 },
633 },
639 b'new': {
634 b'new': {
640 b'required': True,
635 b'required': True,
641 b'type': b'bytes'
636 b'type': b'bytes'
642 },
637 },
643 b'old': {
638 b'old': {
644 b'required': True,
639 b'required': True,
645 b'type': b'bytes'
640 b'type': b'bytes'
646 }
641 }
647 },
642 },
648 b'permissions': [
643 b'permissions': [
649 b'push'
644 b'push'
650 ]
645 ]
651 }
646 }
652 },
647 },
653 b'compression': [
654 {
655 b'name': b'zlib'
656 }
657 ],
658 b'framingmediatypes': [
648 b'framingmediatypes': [
659 b'application/mercurial-exp-framing-0005'
649 b'application/mercurial-exp-framing-0005'
660 ],
650 ],
661 b'pathfilterprefixes': set([
651 b'pathfilterprefixes': set([
662 b'path:',
652 b'path:',
663 b'rootfilesin:'
653 b'rootfilesin:'
664 ]),
654 ]),
665 b'rawrepoformats': [
655 b'rawrepoformats': [
666 b'generaldelta',
656 b'generaldelta',
667 b'revlogv1'
657 b'revlogv1'
668 ]
658 ]
669 }
659 }
670 ]
660 ]
671 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
661 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
672
662
673 $ cat error.log
663 $ cat error.log
@@ -1,1320 +1,1288
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 > [extensions]
14 > [extensions]
15 > simplecache = $TESTDIR/wireprotosimplecache.py
15 > simplecache = $TESTDIR/wireprotosimplecache.py
16 > [simplecache]
16 > [simplecache]
17 > cacheapi = true
17 > cacheapi = true
18 > EOF
18 > EOF
19
19
20 $ echo a0 > a
20 $ echo a0 > a
21 $ echo b0 > b
21 $ echo b0 > b
22 $ hg -q commit -A -m 'commit 0'
22 $ hg -q commit -A -m 'commit 0'
23 $ echo a1 > a
23 $ echo a1 > a
24 $ hg commit -m 'commit 1'
24 $ hg commit -m 'commit 1'
25
25
26 $ hg --debug debugindex -m
26 $ hg --debug debugindex -m
27 rev linkrev nodeid p1 p2
27 rev linkrev nodeid p1 p2
28 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
28 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
29 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
29 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
30
30
31 $ hg --config simplecache.redirectsfile=redirects.py serve -p $HGPORT -d --pid-file hg.pid -E error.log
31 $ hg --config simplecache.redirectsfile=redirects.py serve -p $HGPORT -d --pid-file hg.pid -E error.log
32 $ cat hg.pid > $DAEMON_PIDS
32 $ cat hg.pid > $DAEMON_PIDS
33
33
34 $ cat > redirects.py << EOF
34 $ cat > redirects.py << EOF
35 > [
35 > [
36 > {
36 > {
37 > b'name': b'target-a',
37 > b'name': b'target-a',
38 > b'protocol': b'http',
38 > b'protocol': b'http',
39 > b'snirequired': False,
39 > b'snirequired': False,
40 > b'tlsversions': [b'1.2', b'1.3'],
40 > b'tlsversions': [b'1.2', b'1.3'],
41 > b'uris': [b'http://example.com/'],
41 > b'uris': [b'http://example.com/'],
42 > },
42 > },
43 > ]
43 > ]
44 > EOF
44 > EOF
45
45
46 Redirect targets advertised when configured
46 Redirect targets advertised when configured
47
47
48 $ sendhttpv2peerhandshake << EOF
48 $ sendhttpv2peerhandshake << EOF
49 > command capabilities
49 > command capabilities
50 > EOF
50 > EOF
51 creating http peer for wire protocol version 2
51 creating http peer for wire protocol version 2
52 s> GET /?cmd=capabilities HTTP/1.1\r\n
52 s> GET /?cmd=capabilities HTTP/1.1\r\n
53 s> Accept-Encoding: identity\r\n
53 s> Accept-Encoding: identity\r\n
54 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
54 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
55 s> x-hgproto-1: cbor\r\n
55 s> x-hgproto-1: cbor\r\n
56 s> x-hgupgrade-1: exp-http-v2-0002\r\n
56 s> x-hgupgrade-1: exp-http-v2-0002\r\n
57 s> accept: application/mercurial-0.1\r\n
57 s> accept: application/mercurial-0.1\r\n
58 s> host: $LOCALIP:$HGPORT\r\n (glob)
58 s> host: $LOCALIP:$HGPORT\r\n (glob)
59 s> user-agent: Mercurial debugwireproto\r\n
59 s> user-agent: Mercurial debugwireproto\r\n
60 s> \r\n
60 s> \r\n
61 s> makefile('rb', None)
61 s> makefile('rb', None)
62 s> HTTP/1.1 200 OK\r\n
62 s> HTTP/1.1 200 OK\r\n
63 s> Server: testing stub value\r\n
63 s> Server: testing stub value\r\n
64 s> Date: $HTTP_DATE$\r\n
64 s> Date: $HTTP_DATE$\r\n
65 s> Content-Type: application/mercurial-cbor\r\n
65 s> Content-Type: application/mercurial-cbor\r\n
66 s> Content-Length: 1970\r\n
66 s> Content-Length: 1935\r\n
67 s> \r\n
67 s> \r\n
68 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa6Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xd8batch 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
68 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xd8batch 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
69 (remote redirect target target-a is compatible)
69 (remote redirect target target-a is compatible)
70 sending capabilities command
70 sending capabilities command
71 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
71 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
72 s> Accept-Encoding: identity\r\n
72 s> Accept-Encoding: identity\r\n
73 s> accept: application/mercurial-exp-framing-0005\r\n
73 s> accept: application/mercurial-exp-framing-0005\r\n
74 s> content-type: application/mercurial-exp-framing-0005\r\n
74 s> content-type: application/mercurial-exp-framing-0005\r\n
75 s> content-length: 75\r\n
75 s> content-length: 75\r\n
76 s> host: $LOCALIP:$HGPORT\r\n (glob)
76 s> host: $LOCALIP:$HGPORT\r\n (glob)
77 s> user-agent: Mercurial debugwireproto\r\n
77 s> user-agent: Mercurial debugwireproto\r\n
78 s> \r\n
78 s> \r\n
79 s> C\x00\x00\x01\x00\x01\x01\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
79 s> C\x00\x00\x01\x00\x01\x01\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
80 s> makefile('rb', None)
80 s> makefile('rb', None)
81 s> HTTP/1.1 200 OK\r\n
81 s> HTTP/1.1 200 OK\r\n
82 s> Server: testing stub value\r\n
82 s> Server: testing stub value\r\n
83 s> Date: $HTTP_DATE$\r\n
83 s> Date: $HTTP_DATE$\r\n
84 s> Content-Type: application/mercurial-exp-framing-0005\r\n
84 s> Content-Type: application/mercurial-exp-framing-0005\r\n
85 s> Transfer-Encoding: chunked\r\n
85 s> Transfer-Encoding: chunked\r\n
86 s> \r\n
86 s> \r\n
87 s> 13\r\n
87 s> 13\r\n
88 s> \x0b\x00\x00\x01\x00\x02\x011
88 s> \x0b\x00\x00\x01\x00\x02\x011
89 s> \xa1FstatusBok
89 s> \xa1FstatusBok
90 s> \r\n
90 s> \r\n
91 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
91 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
92 s> 5ab\r\n
92 s> 588\r\n
93 s> \xa3\x05\x00\x01\x00\x02\x001
93 s> \x80\x05\x00\x01\x00\x02\x001
94 s> \xa6Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/
94 s> \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/
95 s> \r\n
95 s> \r\n
96 received frame(size=1443; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
96 received frame(size=1408; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
97 s> 8\r\n
97 s> 8\r\n
98 s> \x00\x00\x00\x01\x00\x02\x002
98 s> \x00\x00\x00\x01\x00\x02\x002
99 s> \r\n
99 s> \r\n
100 s> 0\r\n
100 s> 0\r\n
101 s> \r\n
101 s> \r\n
102 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
102 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
103 response: gen[
103 response: gen[
104 {
104 {
105 b'commands': {
105 b'commands': {
106 b'branchmap': {
106 b'branchmap': {
107 b'args': {},
107 b'args': {},
108 b'permissions': [
108 b'permissions': [
109 b'pull'
109 b'pull'
110 ]
110 ]
111 },
111 },
112 b'capabilities': {
112 b'capabilities': {
113 b'args': {},
113 b'args': {},
114 b'permissions': [
114 b'permissions': [
115 b'pull'
115 b'pull'
116 ]
116 ]
117 },
117 },
118 b'changesetdata': {
118 b'changesetdata': {
119 b'args': {
119 b'args': {
120 b'fields': {
120 b'fields': {
121 b'default': set([]),
121 b'default': set([]),
122 b'required': False,
122 b'required': False,
123 b'type': b'set',
123 b'type': b'set',
124 b'validvalues': set([
124 b'validvalues': set([
125 b'bookmarks',
125 b'bookmarks',
126 b'parents',
126 b'parents',
127 b'phase',
127 b'phase',
128 b'revision'
128 b'revision'
129 ])
129 ])
130 },
130 },
131 b'noderange': {
131 b'noderange': {
132 b'default': None,
132 b'default': None,
133 b'required': False,
133 b'required': False,
134 b'type': b'list'
134 b'type': b'list'
135 },
135 },
136 b'nodes': {
136 b'nodes': {
137 b'default': None,
137 b'default': None,
138 b'required': False,
138 b'required': False,
139 b'type': b'list'
139 b'type': b'list'
140 },
140 },
141 b'nodesdepth': {
141 b'nodesdepth': {
142 b'default': None,
142 b'default': None,
143 b'required': False,
143 b'required': False,
144 b'type': b'int'
144 b'type': b'int'
145 }
145 }
146 },
146 },
147 b'permissions': [
147 b'permissions': [
148 b'pull'
148 b'pull'
149 ]
149 ]
150 },
150 },
151 b'filedata': {
151 b'filedata': {
152 b'args': {
152 b'args': {
153 b'fields': {
153 b'fields': {
154 b'default': set([]),
154 b'default': set([]),
155 b'required': False,
155 b'required': False,
156 b'type': b'set',
156 b'type': b'set',
157 b'validvalues': set([
157 b'validvalues': set([
158 b'parents',
158 b'parents',
159 b'revision'
159 b'revision'
160 ])
160 ])
161 },
161 },
162 b'haveparents': {
162 b'haveparents': {
163 b'default': False,
163 b'default': False,
164 b'required': False,
164 b'required': False,
165 b'type': b'bool'
165 b'type': b'bool'
166 },
166 },
167 b'nodes': {
167 b'nodes': {
168 b'required': True,
168 b'required': True,
169 b'type': b'list'
169 b'type': b'list'
170 },
170 },
171 b'path': {
171 b'path': {
172 b'required': True,
172 b'required': True,
173 b'type': b'bytes'
173 b'type': b'bytes'
174 }
174 }
175 },
175 },
176 b'permissions': [
176 b'permissions': [
177 b'pull'
177 b'pull'
178 ]
178 ]
179 },
179 },
180 b'heads': {
180 b'heads': {
181 b'args': {
181 b'args': {
182 b'publiconly': {
182 b'publiconly': {
183 b'default': False,
183 b'default': False,
184 b'required': False,
184 b'required': False,
185 b'type': b'bool'
185 b'type': b'bool'
186 }
186 }
187 },
187 },
188 b'permissions': [
188 b'permissions': [
189 b'pull'
189 b'pull'
190 ]
190 ]
191 },
191 },
192 b'known': {
192 b'known': {
193 b'args': {
193 b'args': {
194 b'nodes': {
194 b'nodes': {
195 b'default': [],
195 b'default': [],
196 b'required': False,
196 b'required': False,
197 b'type': b'list'
197 b'type': b'list'
198 }
198 }
199 },
199 },
200 b'permissions': [
200 b'permissions': [
201 b'pull'
201 b'pull'
202 ]
202 ]
203 },
203 },
204 b'listkeys': {
204 b'listkeys': {
205 b'args': {
205 b'args': {
206 b'namespace': {
206 b'namespace': {
207 b'required': True,
207 b'required': True,
208 b'type': b'bytes'
208 b'type': b'bytes'
209 }
209 }
210 },
210 },
211 b'permissions': [
211 b'permissions': [
212 b'pull'
212 b'pull'
213 ]
213 ]
214 },
214 },
215 b'lookup': {
215 b'lookup': {
216 b'args': {
216 b'args': {
217 b'key': {
217 b'key': {
218 b'required': True,
218 b'required': True,
219 b'type': b'bytes'
219 b'type': b'bytes'
220 }
220 }
221 },
221 },
222 b'permissions': [
222 b'permissions': [
223 b'pull'
223 b'pull'
224 ]
224 ]
225 },
225 },
226 b'manifestdata': {
226 b'manifestdata': {
227 b'args': {
227 b'args': {
228 b'fields': {
228 b'fields': {
229 b'default': set([]),
229 b'default': set([]),
230 b'required': False,
230 b'required': False,
231 b'type': b'set',
231 b'type': b'set',
232 b'validvalues': set([
232 b'validvalues': set([
233 b'parents',
233 b'parents',
234 b'revision'
234 b'revision'
235 ])
235 ])
236 },
236 },
237 b'haveparents': {
237 b'haveparents': {
238 b'default': False,
238 b'default': False,
239 b'required': False,
239 b'required': False,
240 b'type': b'bool'
240 b'type': b'bool'
241 },
241 },
242 b'nodes': {
242 b'nodes': {
243 b'required': True,
243 b'required': True,
244 b'type': b'list'
244 b'type': b'list'
245 },
245 },
246 b'tree': {
246 b'tree': {
247 b'required': True,
247 b'required': True,
248 b'type': b'bytes'
248 b'type': b'bytes'
249 }
249 }
250 },
250 },
251 b'permissions': [
251 b'permissions': [
252 b'pull'
252 b'pull'
253 ]
253 ]
254 },
254 },
255 b'pushkey': {
255 b'pushkey': {
256 b'args': {
256 b'args': {
257 b'key': {
257 b'key': {
258 b'required': True,
258 b'required': True,
259 b'type': b'bytes'
259 b'type': b'bytes'
260 },
260 },
261 b'namespace': {
261 b'namespace': {
262 b'required': True,
262 b'required': True,
263 b'type': b'bytes'
263 b'type': b'bytes'
264 },
264 },
265 b'new': {
265 b'new': {
266 b'required': True,
266 b'required': True,
267 b'type': b'bytes'
267 b'type': b'bytes'
268 },
268 },
269 b'old': {
269 b'old': {
270 b'required': True,
270 b'required': True,
271 b'type': b'bytes'
271 b'type': b'bytes'
272 }
272 }
273 },
273 },
274 b'permissions': [
274 b'permissions': [
275 b'push'
275 b'push'
276 ]
276 ]
277 }
277 }
278 },
278 },
279 b'compression': [
280 {
281 b'name': b'zstd'
282 },
283 {
284 b'name': b'zlib'
285 }
286 ],
287 b'framingmediatypes': [
279 b'framingmediatypes': [
288 b'application/mercurial-exp-framing-0005'
280 b'application/mercurial-exp-framing-0005'
289 ],
281 ],
290 b'pathfilterprefixes': set([
282 b'pathfilterprefixes': set([
291 b'path:',
283 b'path:',
292 b'rootfilesin:'
284 b'rootfilesin:'
293 ]),
285 ]),
294 b'rawrepoformats': [
286 b'rawrepoformats': [
295 b'generaldelta',
287 b'generaldelta',
296 b'revlogv1'
288 b'revlogv1'
297 ],
289 ],
298 b'redirect': {
290 b'redirect': {
299 b'hashes': [
291 b'hashes': [
300 b'sha256',
292 b'sha256',
301 b'sha1'
293 b'sha1'
302 ],
294 ],
303 b'targets': [
295 b'targets': [
304 {
296 {
305 b'name': b'target-a',
297 b'name': b'target-a',
306 b'protocol': b'http',
298 b'protocol': b'http',
307 b'snirequired': False,
299 b'snirequired': False,
308 b'tlsversions': [
300 b'tlsversions': [
309 b'1.2',
301 b'1.2',
310 b'1.3'
302 b'1.3'
311 ],
303 ],
312 b'uris': [
304 b'uris': [
313 b'http://example.com/'
305 b'http://example.com/'
314 ]
306 ]
315 }
307 }
316 ]
308 ]
317 }
309 }
318 }
310 }
319 ]
311 ]
320 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
312 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
321
313
322 Unknown protocol is filtered from compatible targets
314 Unknown protocol is filtered from compatible targets
323
315
324 $ cat > redirects.py << EOF
316 $ cat > redirects.py << EOF
325 > [
317 > [
326 > {
318 > {
327 > b'name': b'target-a',
319 > b'name': b'target-a',
328 > b'protocol': b'http',
320 > b'protocol': b'http',
329 > b'uris': [b'http://example.com/'],
321 > b'uris': [b'http://example.com/'],
330 > },
322 > },
331 > {
323 > {
332 > b'name': b'target-b',
324 > b'name': b'target-b',
333 > b'protocol': b'unknown',
325 > b'protocol': b'unknown',
334 > b'uris': [b'unknown://example.com/'],
326 > b'uris': [b'unknown://example.com/'],
335 > },
327 > },
336 > ]
328 > ]
337 > EOF
329 > EOF
338
330
339 $ sendhttpv2peerhandshake << EOF
331 $ sendhttpv2peerhandshake << EOF
340 > command capabilities
332 > command capabilities
341 > EOF
333 > EOF
342 creating http peer for wire protocol version 2
334 creating http peer for wire protocol version 2
343 s> GET /?cmd=capabilities HTTP/1.1\r\n
335 s> GET /?cmd=capabilities HTTP/1.1\r\n
344 s> Accept-Encoding: identity\r\n
336 s> Accept-Encoding: identity\r\n
345 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
337 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
346 s> x-hgproto-1: cbor\r\n
338 s> x-hgproto-1: cbor\r\n
347 s> x-hgupgrade-1: exp-http-v2-0002\r\n
339 s> x-hgupgrade-1: exp-http-v2-0002\r\n
348 s> accept: application/mercurial-0.1\r\n
340 s> accept: application/mercurial-0.1\r\n
349 s> host: $LOCALIP:$HGPORT\r\n (glob)
341 s> host: $LOCALIP:$HGPORT\r\n (glob)
350 s> user-agent: Mercurial debugwireproto\r\n
342 s> user-agent: Mercurial debugwireproto\r\n
351 s> \r\n
343 s> \r\n
352 s> makefile('rb', None)
344 s> makefile('rb', None)
353 s> HTTP/1.1 200 OK\r\n
345 s> HTTP/1.1 200 OK\r\n
354 s> Server: testing stub value\r\n
346 s> Server: testing stub value\r\n
355 s> Date: $HTTP_DATE$\r\n
347 s> Date: $HTTP_DATE$\r\n
356 s> Content-Type: application/mercurial-cbor\r\n
348 s> Content-Type: application/mercurial-cbor\r\n
357 s> Content-Length: 1997\r\n
349 s> Content-Length: 1962\r\n
358 s> \r\n
350 s> \r\n
359 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa6Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/Nv1capabilitiesY\x01\xd8batch 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
351 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/Nv1capabilitiesY\x01\xd8batch 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
360 (remote redirect target target-a is compatible)
352 (remote redirect target target-a is compatible)
361 (remote redirect target target-b uses unsupported protocol: unknown)
353 (remote redirect target target-b uses unsupported protocol: unknown)
362 sending capabilities command
354 sending capabilities command
363 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
355 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
364 s> Accept-Encoding: identity\r\n
356 s> Accept-Encoding: identity\r\n
365 s> accept: application/mercurial-exp-framing-0005\r\n
357 s> accept: application/mercurial-exp-framing-0005\r\n
366 s> content-type: application/mercurial-exp-framing-0005\r\n
358 s> content-type: application/mercurial-exp-framing-0005\r\n
367 s> content-length: 75\r\n
359 s> content-length: 75\r\n
368 s> host: $LOCALIP:$HGPORT\r\n (glob)
360 s> host: $LOCALIP:$HGPORT\r\n (glob)
369 s> user-agent: Mercurial debugwireproto\r\n
361 s> user-agent: Mercurial debugwireproto\r\n
370 s> \r\n
362 s> \r\n
371 s> C\x00\x00\x01\x00\x01\x01\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
363 s> C\x00\x00\x01\x00\x01\x01\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
372 s> makefile('rb', None)
364 s> makefile('rb', None)
373 s> HTTP/1.1 200 OK\r\n
365 s> HTTP/1.1 200 OK\r\n
374 s> Server: testing stub value\r\n
366 s> Server: testing stub value\r\n
375 s> Date: $HTTP_DATE$\r\n
367 s> Date: $HTTP_DATE$\r\n
376 s> Content-Type: application/mercurial-exp-framing-0005\r\n
368 s> Content-Type: application/mercurial-exp-framing-0005\r\n
377 s> Transfer-Encoding: chunked\r\n
369 s> Transfer-Encoding: chunked\r\n
378 s> \r\n
370 s> \r\n
379 s> 13\r\n
371 s> 13\r\n
380 s> \x0b\x00\x00\x01\x00\x02\x011
372 s> \x0b\x00\x00\x01\x00\x02\x011
381 s> \xa1FstatusBok
373 s> \xa1FstatusBok
382 s> \r\n
374 s> \r\n
383 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
375 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
384 s> 5c6\r\n
376 s> 5a3\r\n
385 s> \xbe\x05\x00\x01\x00\x02\x001
377 s> \x9b\x05\x00\x01\x00\x02\x001
386 s> \xa6Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/
378 s> \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/
387 s> \r\n
379 s> \r\n
388 received frame(size=1470; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
380 received frame(size=1435; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
389 s> 8\r\n
381 s> 8\r\n
390 s> \x00\x00\x00\x01\x00\x02\x002
382 s> \x00\x00\x00\x01\x00\x02\x002
391 s> \r\n
383 s> \r\n
392 s> 0\r\n
384 s> 0\r\n
393 s> \r\n
385 s> \r\n
394 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
386 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
395 response: gen[
387 response: gen[
396 {
388 {
397 b'commands': {
389 b'commands': {
398 b'branchmap': {
390 b'branchmap': {
399 b'args': {},
391 b'args': {},
400 b'permissions': [
392 b'permissions': [
401 b'pull'
393 b'pull'
402 ]
394 ]
403 },
395 },
404 b'capabilities': {
396 b'capabilities': {
405 b'args': {},
397 b'args': {},
406 b'permissions': [
398 b'permissions': [
407 b'pull'
399 b'pull'
408 ]
400 ]
409 },
401 },
410 b'changesetdata': {
402 b'changesetdata': {
411 b'args': {
403 b'args': {
412 b'fields': {
404 b'fields': {
413 b'default': set([]),
405 b'default': set([]),
414 b'required': False,
406 b'required': False,
415 b'type': b'set',
407 b'type': b'set',
416 b'validvalues': set([
408 b'validvalues': set([
417 b'bookmarks',
409 b'bookmarks',
418 b'parents',
410 b'parents',
419 b'phase',
411 b'phase',
420 b'revision'
412 b'revision'
421 ])
413 ])
422 },
414 },
423 b'noderange': {
415 b'noderange': {
424 b'default': None,
416 b'default': None,
425 b'required': False,
417 b'required': False,
426 b'type': b'list'
418 b'type': b'list'
427 },
419 },
428 b'nodes': {
420 b'nodes': {
429 b'default': None,
421 b'default': None,
430 b'required': False,
422 b'required': False,
431 b'type': b'list'
423 b'type': b'list'
432 },
424 },
433 b'nodesdepth': {
425 b'nodesdepth': {
434 b'default': None,
426 b'default': None,
435 b'required': False,
427 b'required': False,
436 b'type': b'int'
428 b'type': b'int'
437 }
429 }
438 },
430 },
439 b'permissions': [
431 b'permissions': [
440 b'pull'
432 b'pull'
441 ]
433 ]
442 },
434 },
443 b'filedata': {
435 b'filedata': {
444 b'args': {
436 b'args': {
445 b'fields': {
437 b'fields': {
446 b'default': set([]),
438 b'default': set([]),
447 b'required': False,
439 b'required': False,
448 b'type': b'set',
440 b'type': b'set',
449 b'validvalues': set([
441 b'validvalues': set([
450 b'parents',
442 b'parents',
451 b'revision'
443 b'revision'
452 ])
444 ])
453 },
445 },
454 b'haveparents': {
446 b'haveparents': {
455 b'default': False,
447 b'default': False,
456 b'required': False,
448 b'required': False,
457 b'type': b'bool'
449 b'type': b'bool'
458 },
450 },
459 b'nodes': {
451 b'nodes': {
460 b'required': True,
452 b'required': True,
461 b'type': b'list'
453 b'type': b'list'
462 },
454 },
463 b'path': {
455 b'path': {
464 b'required': True,
456 b'required': True,
465 b'type': b'bytes'
457 b'type': b'bytes'
466 }
458 }
467 },
459 },
468 b'permissions': [
460 b'permissions': [
469 b'pull'
461 b'pull'
470 ]
462 ]
471 },
463 },
472 b'heads': {
464 b'heads': {
473 b'args': {
465 b'args': {
474 b'publiconly': {
466 b'publiconly': {
475 b'default': False,
467 b'default': False,
476 b'required': False,
468 b'required': False,
477 b'type': b'bool'
469 b'type': b'bool'
478 }
470 }
479 },
471 },
480 b'permissions': [
472 b'permissions': [
481 b'pull'
473 b'pull'
482 ]
474 ]
483 },
475 },
484 b'known': {
476 b'known': {
485 b'args': {
477 b'args': {
486 b'nodes': {
478 b'nodes': {
487 b'default': [],
479 b'default': [],
488 b'required': False,
480 b'required': False,
489 b'type': b'list'
481 b'type': b'list'
490 }
482 }
491 },
483 },
492 b'permissions': [
484 b'permissions': [
493 b'pull'
485 b'pull'
494 ]
486 ]
495 },
487 },
496 b'listkeys': {
488 b'listkeys': {
497 b'args': {
489 b'args': {
498 b'namespace': {
490 b'namespace': {
499 b'required': True,
491 b'required': True,
500 b'type': b'bytes'
492 b'type': b'bytes'
501 }
493 }
502 },
494 },
503 b'permissions': [
495 b'permissions': [
504 b'pull'
496 b'pull'
505 ]
497 ]
506 },
498 },
507 b'lookup': {
499 b'lookup': {
508 b'args': {
500 b'args': {
509 b'key': {
501 b'key': {
510 b'required': True,
502 b'required': True,
511 b'type': b'bytes'
503 b'type': b'bytes'
512 }
504 }
513 },
505 },
514 b'permissions': [
506 b'permissions': [
515 b'pull'
507 b'pull'
516 ]
508 ]
517 },
509 },
518 b'manifestdata': {
510 b'manifestdata': {
519 b'args': {
511 b'args': {
520 b'fields': {
512 b'fields': {
521 b'default': set([]),
513 b'default': set([]),
522 b'required': False,
514 b'required': False,
523 b'type': b'set',
515 b'type': b'set',
524 b'validvalues': set([
516 b'validvalues': set([
525 b'parents',
517 b'parents',
526 b'revision'
518 b'revision'
527 ])
519 ])
528 },
520 },
529 b'haveparents': {
521 b'haveparents': {
530 b'default': False,
522 b'default': False,
531 b'required': False,
523 b'required': False,
532 b'type': b'bool'
524 b'type': b'bool'
533 },
525 },
534 b'nodes': {
526 b'nodes': {
535 b'required': True,
527 b'required': True,
536 b'type': b'list'
528 b'type': b'list'
537 },
529 },
538 b'tree': {
530 b'tree': {
539 b'required': True,
531 b'required': True,
540 b'type': b'bytes'
532 b'type': b'bytes'
541 }
533 }
542 },
534 },
543 b'permissions': [
535 b'permissions': [
544 b'pull'
536 b'pull'
545 ]
537 ]
546 },
538 },
547 b'pushkey': {
539 b'pushkey': {
548 b'args': {
540 b'args': {
549 b'key': {
541 b'key': {
550 b'required': True,
542 b'required': True,
551 b'type': b'bytes'
543 b'type': b'bytes'
552 },
544 },
553 b'namespace': {
545 b'namespace': {
554 b'required': True,
546 b'required': True,
555 b'type': b'bytes'
547 b'type': b'bytes'
556 },
548 },
557 b'new': {
549 b'new': {
558 b'required': True,
550 b'required': True,
559 b'type': b'bytes'
551 b'type': b'bytes'
560 },
552 },
561 b'old': {
553 b'old': {
562 b'required': True,
554 b'required': True,
563 b'type': b'bytes'
555 b'type': b'bytes'
564 }
556 }
565 },
557 },
566 b'permissions': [
558 b'permissions': [
567 b'push'
559 b'push'
568 ]
560 ]
569 }
561 }
570 },
562 },
571 b'compression': [
572 {
573 b'name': b'zstd'
574 },
575 {
576 b'name': b'zlib'
577 }
578 ],
579 b'framingmediatypes': [
563 b'framingmediatypes': [
580 b'application/mercurial-exp-framing-0005'
564 b'application/mercurial-exp-framing-0005'
581 ],
565 ],
582 b'pathfilterprefixes': set([
566 b'pathfilterprefixes': set([
583 b'path:',
567 b'path:',
584 b'rootfilesin:'
568 b'rootfilesin:'
585 ]),
569 ]),
586 b'rawrepoformats': [
570 b'rawrepoformats': [
587 b'generaldelta',
571 b'generaldelta',
588 b'revlogv1'
572 b'revlogv1'
589 ],
573 ],
590 b'redirect': {
574 b'redirect': {
591 b'hashes': [
575 b'hashes': [
592 b'sha256',
576 b'sha256',
593 b'sha1'
577 b'sha1'
594 ],
578 ],
595 b'targets': [
579 b'targets': [
596 {
580 {
597 b'name': b'target-a',
581 b'name': b'target-a',
598 b'protocol': b'http',
582 b'protocol': b'http',
599 b'uris': [
583 b'uris': [
600 b'http://example.com/'
584 b'http://example.com/'
601 ]
585 ]
602 },
586 },
603 {
587 {
604 b'name': b'target-b',
588 b'name': b'target-b',
605 b'protocol': b'unknown',
589 b'protocol': b'unknown',
606 b'uris': [
590 b'uris': [
607 b'unknown://example.com/'
591 b'unknown://example.com/'
608 ]
592 ]
609 }
593 }
610 ]
594 ]
611 }
595 }
612 }
596 }
613 ]
597 ]
614 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
598 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
615
599
616 Missing SNI support filters targets that require SNI
600 Missing SNI support filters targets that require SNI
617
601
618 $ cat > nosni.py << EOF
602 $ cat > nosni.py << EOF
619 > from mercurial import sslutil
603 > from mercurial import sslutil
620 > sslutil.hassni = False
604 > sslutil.hassni = False
621 > EOF
605 > EOF
622 $ cat >> $HGRCPATH << EOF
606 $ cat >> $HGRCPATH << EOF
623 > [extensions]
607 > [extensions]
624 > nosni=`pwd`/nosni.py
608 > nosni=`pwd`/nosni.py
625 > EOF
609 > EOF
626
610
627 $ cat > redirects.py << EOF
611 $ cat > redirects.py << EOF
628 > [
612 > [
629 > {
613 > {
630 > b'name': b'target-bad-tls',
614 > b'name': b'target-bad-tls',
631 > b'protocol': b'https',
615 > b'protocol': b'https',
632 > b'uris': [b'https://example.com/'],
616 > b'uris': [b'https://example.com/'],
633 > b'snirequired': True,
617 > b'snirequired': True,
634 > },
618 > },
635 > ]
619 > ]
636 > EOF
620 > EOF
637
621
638 $ sendhttpv2peerhandshake << EOF
622 $ sendhttpv2peerhandshake << EOF
639 > command capabilities
623 > command capabilities
640 > EOF
624 > EOF
641 creating http peer for wire protocol version 2
625 creating http peer for wire protocol version 2
642 s> GET /?cmd=capabilities HTTP/1.1\r\n
626 s> GET /?cmd=capabilities HTTP/1.1\r\n
643 s> Accept-Encoding: identity\r\n
627 s> Accept-Encoding: identity\r\n
644 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
628 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
645 s> x-hgproto-1: cbor\r\n
629 s> x-hgproto-1: cbor\r\n
646 s> x-hgupgrade-1: exp-http-v2-0002\r\n
630 s> x-hgupgrade-1: exp-http-v2-0002\r\n
647 s> accept: application/mercurial-0.1\r\n
631 s> accept: application/mercurial-0.1\r\n
648 s> host: $LOCALIP:$HGPORT\r\n (glob)
632 s> host: $LOCALIP:$HGPORT\r\n (glob)
649 s> user-agent: Mercurial debugwireproto\r\n
633 s> user-agent: Mercurial debugwireproto\r\n
650 s> \r\n
634 s> \r\n
651 s> makefile('rb', None)
635 s> makefile('rb', None)
652 s> HTTP/1.1 200 OK\r\n
636 s> HTTP/1.1 200 OK\r\n
653 s> Server: testing stub value\r\n
637 s> Server: testing stub value\r\n
654 s> Date: $HTTP_DATE$\r\n
638 s> Date: $HTTP_DATE$\r\n
655 s> Content-Type: application/mercurial-cbor\r\n
639 s> Content-Type: application/mercurial-cbor\r\n
656 s> Content-Length: 1957\r\n
640 s> Content-Length: 1922\r\n
657 s> \r\n
641 s> \r\n
658 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa6Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd8batch 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
642 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd8batch 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
659 (redirect target target-bad-tls requires SNI, which is unsupported)
643 (redirect target target-bad-tls requires SNI, which is unsupported)
660 sending capabilities command
644 sending capabilities command
661 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
645 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
662 s> Accept-Encoding: identity\r\n
646 s> Accept-Encoding: identity\r\n
663 s> accept: application/mercurial-exp-framing-0005\r\n
647 s> accept: application/mercurial-exp-framing-0005\r\n
664 s> content-type: application/mercurial-exp-framing-0005\r\n
648 s> content-type: application/mercurial-exp-framing-0005\r\n
665 s> content-length: 66\r\n
649 s> content-length: 66\r\n
666 s> host: $LOCALIP:$HGPORT\r\n (glob)
650 s> host: $LOCALIP:$HGPORT\r\n (glob)
667 s> user-agent: Mercurial debugwireproto\r\n
651 s> user-agent: Mercurial debugwireproto\r\n
668 s> \r\n
652 s> \r\n
669 s> :\x00\x00\x01\x00\x01\x01\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
653 s> :\x00\x00\x01\x00\x01\x01\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
670 s> makefile('rb', None)
654 s> makefile('rb', None)
671 s> HTTP/1.1 200 OK\r\n
655 s> HTTP/1.1 200 OK\r\n
672 s> Server: testing stub value\r\n
656 s> Server: testing stub value\r\n
673 s> Date: $HTTP_DATE$\r\n
657 s> Date: $HTTP_DATE$\r\n
674 s> Content-Type: application/mercurial-exp-framing-0005\r\n
658 s> Content-Type: application/mercurial-exp-framing-0005\r\n
675 s> Transfer-Encoding: chunked\r\n
659 s> Transfer-Encoding: chunked\r\n
676 s> \r\n
660 s> \r\n
677 s> 13\r\n
661 s> 13\r\n
678 s> \x0b\x00\x00\x01\x00\x02\x011
662 s> \x0b\x00\x00\x01\x00\x02\x011
679 s> \xa1FstatusBok
663 s> \xa1FstatusBok
680 s> \r\n
664 s> \r\n
681 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
665 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
682 s> 59e\r\n
666 s> 57b\r\n
683 s> \x96\x05\x00\x01\x00\x02\x001
667 s> s\x05\x00\x01\x00\x02\x001
684 s> \xa6Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
668 s> \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
685 s> \r\n
669 s> \r\n
686 received frame(size=1430; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
670 received frame(size=1395; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
687 s> 8\r\n
671 s> 8\r\n
688 s> \x00\x00\x00\x01\x00\x02\x002
672 s> \x00\x00\x00\x01\x00\x02\x002
689 s> \r\n
673 s> \r\n
690 s> 0\r\n
674 s> 0\r\n
691 s> \r\n
675 s> \r\n
692 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
676 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
693 response: gen[
677 response: gen[
694 {
678 {
695 b'commands': {
679 b'commands': {
696 b'branchmap': {
680 b'branchmap': {
697 b'args': {},
681 b'args': {},
698 b'permissions': [
682 b'permissions': [
699 b'pull'
683 b'pull'
700 ]
684 ]
701 },
685 },
702 b'capabilities': {
686 b'capabilities': {
703 b'args': {},
687 b'args': {},
704 b'permissions': [
688 b'permissions': [
705 b'pull'
689 b'pull'
706 ]
690 ]
707 },
691 },
708 b'changesetdata': {
692 b'changesetdata': {
709 b'args': {
693 b'args': {
710 b'fields': {
694 b'fields': {
711 b'default': set([]),
695 b'default': set([]),
712 b'required': False,
696 b'required': False,
713 b'type': b'set',
697 b'type': b'set',
714 b'validvalues': set([
698 b'validvalues': set([
715 b'bookmarks',
699 b'bookmarks',
716 b'parents',
700 b'parents',
717 b'phase',
701 b'phase',
718 b'revision'
702 b'revision'
719 ])
703 ])
720 },
704 },
721 b'noderange': {
705 b'noderange': {
722 b'default': None,
706 b'default': None,
723 b'required': False,
707 b'required': False,
724 b'type': b'list'
708 b'type': b'list'
725 },
709 },
726 b'nodes': {
710 b'nodes': {
727 b'default': None,
711 b'default': None,
728 b'required': False,
712 b'required': False,
729 b'type': b'list'
713 b'type': b'list'
730 },
714 },
731 b'nodesdepth': {
715 b'nodesdepth': {
732 b'default': None,
716 b'default': None,
733 b'required': False,
717 b'required': False,
734 b'type': b'int'
718 b'type': b'int'
735 }
719 }
736 },
720 },
737 b'permissions': [
721 b'permissions': [
738 b'pull'
722 b'pull'
739 ]
723 ]
740 },
724 },
741 b'filedata': {
725 b'filedata': {
742 b'args': {
726 b'args': {
743 b'fields': {
727 b'fields': {
744 b'default': set([]),
728 b'default': set([]),
745 b'required': False,
729 b'required': False,
746 b'type': b'set',
730 b'type': b'set',
747 b'validvalues': set([
731 b'validvalues': set([
748 b'parents',
732 b'parents',
749 b'revision'
733 b'revision'
750 ])
734 ])
751 },
735 },
752 b'haveparents': {
736 b'haveparents': {
753 b'default': False,
737 b'default': False,
754 b'required': False,
738 b'required': False,
755 b'type': b'bool'
739 b'type': b'bool'
756 },
740 },
757 b'nodes': {
741 b'nodes': {
758 b'required': True,
742 b'required': True,
759 b'type': b'list'
743 b'type': b'list'
760 },
744 },
761 b'path': {
745 b'path': {
762 b'required': True,
746 b'required': True,
763 b'type': b'bytes'
747 b'type': b'bytes'
764 }
748 }
765 },
749 },
766 b'permissions': [
750 b'permissions': [
767 b'pull'
751 b'pull'
768 ]
752 ]
769 },
753 },
770 b'heads': {
754 b'heads': {
771 b'args': {
755 b'args': {
772 b'publiconly': {
756 b'publiconly': {
773 b'default': False,
757 b'default': False,
774 b'required': False,
758 b'required': False,
775 b'type': b'bool'
759 b'type': b'bool'
776 }
760 }
777 },
761 },
778 b'permissions': [
762 b'permissions': [
779 b'pull'
763 b'pull'
780 ]
764 ]
781 },
765 },
782 b'known': {
766 b'known': {
783 b'args': {
767 b'args': {
784 b'nodes': {
768 b'nodes': {
785 b'default': [],
769 b'default': [],
786 b'required': False,
770 b'required': False,
787 b'type': b'list'
771 b'type': b'list'
788 }
772 }
789 },
773 },
790 b'permissions': [
774 b'permissions': [
791 b'pull'
775 b'pull'
792 ]
776 ]
793 },
777 },
794 b'listkeys': {
778 b'listkeys': {
795 b'args': {
779 b'args': {
796 b'namespace': {
780 b'namespace': {
797 b'required': True,
781 b'required': True,
798 b'type': b'bytes'
782 b'type': b'bytes'
799 }
783 }
800 },
784 },
801 b'permissions': [
785 b'permissions': [
802 b'pull'
786 b'pull'
803 ]
787 ]
804 },
788 },
805 b'lookup': {
789 b'lookup': {
806 b'args': {
790 b'args': {
807 b'key': {
791 b'key': {
808 b'required': True,
792 b'required': True,
809 b'type': b'bytes'
793 b'type': b'bytes'
810 }
794 }
811 },
795 },
812 b'permissions': [
796 b'permissions': [
813 b'pull'
797 b'pull'
814 ]
798 ]
815 },
799 },
816 b'manifestdata': {
800 b'manifestdata': {
817 b'args': {
801 b'args': {
818 b'fields': {
802 b'fields': {
819 b'default': set([]),
803 b'default': set([]),
820 b'required': False,
804 b'required': False,
821 b'type': b'set',
805 b'type': b'set',
822 b'validvalues': set([
806 b'validvalues': set([
823 b'parents',
807 b'parents',
824 b'revision'
808 b'revision'
825 ])
809 ])
826 },
810 },
827 b'haveparents': {
811 b'haveparents': {
828 b'default': False,
812 b'default': False,
829 b'required': False,
813 b'required': False,
830 b'type': b'bool'
814 b'type': b'bool'
831 },
815 },
832 b'nodes': {
816 b'nodes': {
833 b'required': True,
817 b'required': True,
834 b'type': b'list'
818 b'type': b'list'
835 },
819 },
836 b'tree': {
820 b'tree': {
837 b'required': True,
821 b'required': True,
838 b'type': b'bytes'
822 b'type': b'bytes'
839 }
823 }
840 },
824 },
841 b'permissions': [
825 b'permissions': [
842 b'pull'
826 b'pull'
843 ]
827 ]
844 },
828 },
845 b'pushkey': {
829 b'pushkey': {
846 b'args': {
830 b'args': {
847 b'key': {
831 b'key': {
848 b'required': True,
832 b'required': True,
849 b'type': b'bytes'
833 b'type': b'bytes'
850 },
834 },
851 b'namespace': {
835 b'namespace': {
852 b'required': True,
836 b'required': True,
853 b'type': b'bytes'
837 b'type': b'bytes'
854 },
838 },
855 b'new': {
839 b'new': {
856 b'required': True,
840 b'required': True,
857 b'type': b'bytes'
841 b'type': b'bytes'
858 },
842 },
859 b'old': {
843 b'old': {
860 b'required': True,
844 b'required': True,
861 b'type': b'bytes'
845 b'type': b'bytes'
862 }
846 }
863 },
847 },
864 b'permissions': [
848 b'permissions': [
865 b'push'
849 b'push'
866 ]
850 ]
867 }
851 }
868 },
852 },
869 b'compression': [
870 {
871 b'name': b'zstd'
872 },
873 {
874 b'name': b'zlib'
875 }
876 ],
877 b'framingmediatypes': [
853 b'framingmediatypes': [
878 b'application/mercurial-exp-framing-0005'
854 b'application/mercurial-exp-framing-0005'
879 ],
855 ],
880 b'pathfilterprefixes': set([
856 b'pathfilterprefixes': set([
881 b'path:',
857 b'path:',
882 b'rootfilesin:'
858 b'rootfilesin:'
883 ]),
859 ]),
884 b'rawrepoformats': [
860 b'rawrepoformats': [
885 b'generaldelta',
861 b'generaldelta',
886 b'revlogv1'
862 b'revlogv1'
887 ],
863 ],
888 b'redirect': {
864 b'redirect': {
889 b'hashes': [
865 b'hashes': [
890 b'sha256',
866 b'sha256',
891 b'sha1'
867 b'sha1'
892 ],
868 ],
893 b'targets': [
869 b'targets': [
894 {
870 {
895 b'name': b'target-bad-tls',
871 b'name': b'target-bad-tls',
896 b'protocol': b'https',
872 b'protocol': b'https',
897 b'snirequired': True,
873 b'snirequired': True,
898 b'uris': [
874 b'uris': [
899 b'https://example.com/'
875 b'https://example.com/'
900 ]
876 ]
901 }
877 }
902 ]
878 ]
903 }
879 }
904 }
880 }
905 ]
881 ]
906 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
882 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
907
883
908 $ cat >> $HGRCPATH << EOF
884 $ cat >> $HGRCPATH << EOF
909 > [extensions]
885 > [extensions]
910 > nosni=!
886 > nosni=!
911 > EOF
887 > EOF
912
888
913 Unknown tls value is filtered from compatible targets
889 Unknown tls value is filtered from compatible targets
914
890
915 $ cat > redirects.py << EOF
891 $ cat > redirects.py << EOF
916 > [
892 > [
917 > {
893 > {
918 > b'name': b'target-bad-tls',
894 > b'name': b'target-bad-tls',
919 > b'protocol': b'https',
895 > b'protocol': b'https',
920 > b'uris': [b'https://example.com/'],
896 > b'uris': [b'https://example.com/'],
921 > b'tlsversions': [b'42', b'39'],
897 > b'tlsversions': [b'42', b'39'],
922 > },
898 > },
923 > ]
899 > ]
924 > EOF
900 > EOF
925
901
926 $ sendhttpv2peerhandshake << EOF
902 $ sendhttpv2peerhandshake << EOF
927 > command capabilities
903 > command capabilities
928 > EOF
904 > EOF
929 creating http peer for wire protocol version 2
905 creating http peer for wire protocol version 2
930 s> GET /?cmd=capabilities HTTP/1.1\r\n
906 s> GET /?cmd=capabilities HTTP/1.1\r\n
931 s> Accept-Encoding: identity\r\n
907 s> Accept-Encoding: identity\r\n
932 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
908 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
933 s> x-hgproto-1: cbor\r\n
909 s> x-hgproto-1: cbor\r\n
934 s> x-hgupgrade-1: exp-http-v2-0002\r\n
910 s> x-hgupgrade-1: exp-http-v2-0002\r\n
935 s> accept: application/mercurial-0.1\r\n
911 s> accept: application/mercurial-0.1\r\n
936 s> host: $LOCALIP:$HGPORT\r\n (glob)
912 s> host: $LOCALIP:$HGPORT\r\n (glob)
937 s> user-agent: Mercurial debugwireproto\r\n
913 s> user-agent: Mercurial debugwireproto\r\n
938 s> \r\n
914 s> \r\n
939 s> makefile('rb', None)
915 s> makefile('rb', None)
940 s> HTTP/1.1 200 OK\r\n
916 s> HTTP/1.1 200 OK\r\n
941 s> Server: testing stub value\r\n
917 s> Server: testing stub value\r\n
942 s> Date: $HTTP_DATE$\r\n
918 s> Date: $HTTP_DATE$\r\n
943 s> Content-Type: application/mercurial-cbor\r\n
919 s> Content-Type: application/mercurial-cbor\r\n
944 s> Content-Length: 1963\r\n
920 s> Content-Length: 1928\r\n
945 s> \r\n
921 s> \r\n
946 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa6Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd8batch 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
922 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd8batch 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
947 (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42)
923 (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42)
948 sending capabilities command
924 sending capabilities command
949 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
925 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
950 s> Accept-Encoding: identity\r\n
926 s> Accept-Encoding: identity\r\n
951 s> accept: application/mercurial-exp-framing-0005\r\n
927 s> accept: application/mercurial-exp-framing-0005\r\n
952 s> content-type: application/mercurial-exp-framing-0005\r\n
928 s> content-type: application/mercurial-exp-framing-0005\r\n
953 s> content-length: 66\r\n
929 s> content-length: 66\r\n
954 s> host: $LOCALIP:$HGPORT\r\n (glob)
930 s> host: $LOCALIP:$HGPORT\r\n (glob)
955 s> user-agent: Mercurial debugwireproto\r\n
931 s> user-agent: Mercurial debugwireproto\r\n
956 s> \r\n
932 s> \r\n
957 s> :\x00\x00\x01\x00\x01\x01\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
933 s> :\x00\x00\x01\x00\x01\x01\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
958 s> makefile('rb', None)
934 s> makefile('rb', None)
959 s> HTTP/1.1 200 OK\r\n
935 s> HTTP/1.1 200 OK\r\n
960 s> Server: testing stub value\r\n
936 s> Server: testing stub value\r\n
961 s> Date: $HTTP_DATE$\r\n
937 s> Date: $HTTP_DATE$\r\n
962 s> Content-Type: application/mercurial-exp-framing-0005\r\n
938 s> Content-Type: application/mercurial-exp-framing-0005\r\n
963 s> Transfer-Encoding: chunked\r\n
939 s> Transfer-Encoding: chunked\r\n
964 s> \r\n
940 s> \r\n
965 s> 13\r\n
941 s> 13\r\n
966 s> \x0b\x00\x00\x01\x00\x02\x011
942 s> \x0b\x00\x00\x01\x00\x02\x011
967 s> \xa1FstatusBok
943 s> \xa1FstatusBok
968 s> \r\n
944 s> \r\n
969 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
945 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
970 s> 5a4\r\n
946 s> 581\r\n
971 s> \x9c\x05\x00\x01\x00\x02\x001
947 s> y\x05\x00\x01\x00\x02\x001
972 s> \xa6Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushKcompression\x82\xa1DnameDzstd\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
948 s> \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullGpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0005Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
973 s> \r\n
949 s> \r\n
974 received frame(size=1436; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
950 received frame(size=1401; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
975 s> 8\r\n
951 s> 8\r\n
976 s> \x00\x00\x00\x01\x00\x02\x002
952 s> \x00\x00\x00\x01\x00\x02\x002
977 s> \r\n
953 s> \r\n
978 s> 0\r\n
954 s> 0\r\n
979 s> \r\n
955 s> \r\n
980 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
956 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
981 response: gen[
957 response: gen[
982 {
958 {
983 b'commands': {
959 b'commands': {
984 b'branchmap': {
960 b'branchmap': {
985 b'args': {},
961 b'args': {},
986 b'permissions': [
962 b'permissions': [
987 b'pull'
963 b'pull'
988 ]
964 ]
989 },
965 },
990 b'capabilities': {
966 b'capabilities': {
991 b'args': {},
967 b'args': {},
992 b'permissions': [
968 b'permissions': [
993 b'pull'
969 b'pull'
994 ]
970 ]
995 },
971 },
996 b'changesetdata': {
972 b'changesetdata': {
997 b'args': {
973 b'args': {
998 b'fields': {
974 b'fields': {
999 b'default': set([]),
975 b'default': set([]),
1000 b'required': False,
976 b'required': False,
1001 b'type': b'set',
977 b'type': b'set',
1002 b'validvalues': set([
978 b'validvalues': set([
1003 b'bookmarks',
979 b'bookmarks',
1004 b'parents',
980 b'parents',
1005 b'phase',
981 b'phase',
1006 b'revision'
982 b'revision'
1007 ])
983 ])
1008 },
984 },
1009 b'noderange': {
985 b'noderange': {
1010 b'default': None,
986 b'default': None,
1011 b'required': False,
987 b'required': False,
1012 b'type': b'list'
988 b'type': b'list'
1013 },
989 },
1014 b'nodes': {
990 b'nodes': {
1015 b'default': None,
991 b'default': None,
1016 b'required': False,
992 b'required': False,
1017 b'type': b'list'
993 b'type': b'list'
1018 },
994 },
1019 b'nodesdepth': {
995 b'nodesdepth': {
1020 b'default': None,
996 b'default': None,
1021 b'required': False,
997 b'required': False,
1022 b'type': b'int'
998 b'type': b'int'
1023 }
999 }
1024 },
1000 },
1025 b'permissions': [
1001 b'permissions': [
1026 b'pull'
1002 b'pull'
1027 ]
1003 ]
1028 },
1004 },
1029 b'filedata': {
1005 b'filedata': {
1030 b'args': {
1006 b'args': {
1031 b'fields': {
1007 b'fields': {
1032 b'default': set([]),
1008 b'default': set([]),
1033 b'required': False,
1009 b'required': False,
1034 b'type': b'set',
1010 b'type': b'set',
1035 b'validvalues': set([
1011 b'validvalues': set([
1036 b'parents',
1012 b'parents',
1037 b'revision'
1013 b'revision'
1038 ])
1014 ])
1039 },
1015 },
1040 b'haveparents': {
1016 b'haveparents': {
1041 b'default': False,
1017 b'default': False,
1042 b'required': False,
1018 b'required': False,
1043 b'type': b'bool'
1019 b'type': b'bool'
1044 },
1020 },
1045 b'nodes': {
1021 b'nodes': {
1046 b'required': True,
1022 b'required': True,
1047 b'type': b'list'
1023 b'type': b'list'
1048 },
1024 },
1049 b'path': {
1025 b'path': {
1050 b'required': True,
1026 b'required': True,
1051 b'type': b'bytes'
1027 b'type': b'bytes'
1052 }
1028 }
1053 },
1029 },
1054 b'permissions': [
1030 b'permissions': [
1055 b'pull'
1031 b'pull'
1056 ]
1032 ]
1057 },
1033 },
1058 b'heads': {
1034 b'heads': {
1059 b'args': {
1035 b'args': {
1060 b'publiconly': {
1036 b'publiconly': {
1061 b'default': False,
1037 b'default': False,
1062 b'required': False,
1038 b'required': False,
1063 b'type': b'bool'
1039 b'type': b'bool'
1064 }
1040 }
1065 },
1041 },
1066 b'permissions': [
1042 b'permissions': [
1067 b'pull'
1043 b'pull'
1068 ]
1044 ]
1069 },
1045 },
1070 b'known': {
1046 b'known': {
1071 b'args': {
1047 b'args': {
1072 b'nodes': {
1048 b'nodes': {
1073 b'default': [],
1049 b'default': [],
1074 b'required': False,
1050 b'required': False,
1075 b'type': b'list'
1051 b'type': b'list'
1076 }
1052 }
1077 },
1053 },
1078 b'permissions': [
1054 b'permissions': [
1079 b'pull'
1055 b'pull'
1080 ]
1056 ]
1081 },
1057 },
1082 b'listkeys': {
1058 b'listkeys': {
1083 b'args': {
1059 b'args': {
1084 b'namespace': {
1060 b'namespace': {
1085 b'required': True,
1061 b'required': True,
1086 b'type': b'bytes'
1062 b'type': b'bytes'
1087 }
1063 }
1088 },
1064 },
1089 b'permissions': [
1065 b'permissions': [
1090 b'pull'
1066 b'pull'
1091 ]
1067 ]
1092 },
1068 },
1093 b'lookup': {
1069 b'lookup': {
1094 b'args': {
1070 b'args': {
1095 b'key': {
1071 b'key': {
1096 b'required': True,
1072 b'required': True,
1097 b'type': b'bytes'
1073 b'type': b'bytes'
1098 }
1074 }
1099 },
1075 },
1100 b'permissions': [
1076 b'permissions': [
1101 b'pull'
1077 b'pull'
1102 ]
1078 ]
1103 },
1079 },
1104 b'manifestdata': {
1080 b'manifestdata': {
1105 b'args': {
1081 b'args': {
1106 b'fields': {
1082 b'fields': {
1107 b'default': set([]),
1083 b'default': set([]),
1108 b'required': False,
1084 b'required': False,
1109 b'type': b'set',
1085 b'type': b'set',
1110 b'validvalues': set([
1086 b'validvalues': set([
1111 b'parents',
1087 b'parents',
1112 b'revision'
1088 b'revision'
1113 ])
1089 ])
1114 },
1090 },
1115 b'haveparents': {
1091 b'haveparents': {
1116 b'default': False,
1092 b'default': False,
1117 b'required': False,
1093 b'required': False,
1118 b'type': b'bool'
1094 b'type': b'bool'
1119 },
1095 },
1120 b'nodes': {
1096 b'nodes': {
1121 b'required': True,
1097 b'required': True,
1122 b'type': b'list'
1098 b'type': b'list'
1123 },
1099 },
1124 b'tree': {
1100 b'tree': {
1125 b'required': True,
1101 b'required': True,
1126 b'type': b'bytes'
1102 b'type': b'bytes'
1127 }
1103 }
1128 },
1104 },
1129 b'permissions': [
1105 b'permissions': [
1130 b'pull'
1106 b'pull'
1131 ]
1107 ]
1132 },
1108 },
1133 b'pushkey': {
1109 b'pushkey': {
1134 b'args': {
1110 b'args': {
1135 b'key': {
1111 b'key': {
1136 b'required': True,
1112 b'required': True,
1137 b'type': b'bytes'
1113 b'type': b'bytes'
1138 },
1114 },
1139 b'namespace': {
1115 b'namespace': {
1140 b'required': True,
1116 b'required': True,
1141 b'type': b'bytes'
1117 b'type': b'bytes'
1142 },
1118 },
1143 b'new': {
1119 b'new': {
1144 b'required': True,
1120 b'required': True,
1145 b'type': b'bytes'
1121 b'type': b'bytes'
1146 },
1122 },
1147 b'old': {
1123 b'old': {
1148 b'required': True,
1124 b'required': True,
1149 b'type': b'bytes'
1125 b'type': b'bytes'
1150 }
1126 }
1151 },
1127 },
1152 b'permissions': [
1128 b'permissions': [
1153 b'push'
1129 b'push'
1154 ]
1130 ]
1155 }
1131 }
1156 },
1132 },
1157 b'compression': [
1158 {
1159 b'name': b'zstd'
1160 },
1161 {
1162 b'name': b'zlib'
1163 }
1164 ],
1165 b'framingmediatypes': [
1133 b'framingmediatypes': [
1166 b'application/mercurial-exp-framing-0005'
1134 b'application/mercurial-exp-framing-0005'
1167 ],
1135 ],
1168 b'pathfilterprefixes': set([
1136 b'pathfilterprefixes': set([
1169 b'path:',
1137 b'path:',
1170 b'rootfilesin:'
1138 b'rootfilesin:'
1171 ]),
1139 ]),
1172 b'rawrepoformats': [
1140 b'rawrepoformats': [
1173 b'generaldelta',
1141 b'generaldelta',
1174 b'revlogv1'
1142 b'revlogv1'
1175 ],
1143 ],
1176 b'redirect': {
1144 b'redirect': {
1177 b'hashes': [
1145 b'hashes': [
1178 b'sha256',
1146 b'sha256',
1179 b'sha1'
1147 b'sha1'
1180 ],
1148 ],
1181 b'targets': [
1149 b'targets': [
1182 {
1150 {
1183 b'name': b'target-bad-tls',
1151 b'name': b'target-bad-tls',
1184 b'protocol': b'https',
1152 b'protocol': b'https',
1185 b'tlsversions': [
1153 b'tlsversions': [
1186 b'42',
1154 b'42',
1187 b'39'
1155 b'39'
1188 ],
1156 ],
1189 b'uris': [
1157 b'uris': [
1190 b'https://example.com/'
1158 b'https://example.com/'
1191 ]
1159 ]
1192 }
1160 }
1193 ]
1161 ]
1194 }
1162 }
1195 }
1163 }
1196 ]
1164 ]
1197 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1165 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1198
1166
1199 Set up the server to issue content redirects to its built-in API server.
1167 Set up the server to issue content redirects to its built-in API server.
1200
1168
1201 $ cat > redirects.py << EOF
1169 $ cat > redirects.py << EOF
1202 > [
1170 > [
1203 > {
1171 > {
1204 > b'name': b'local',
1172 > b'name': b'local',
1205 > b'protocol': b'http',
1173 > b'protocol': b'http',
1206 > b'uris': [b'http://example.com/'],
1174 > b'uris': [b'http://example.com/'],
1207 > },
1175 > },
1208 > ]
1176 > ]
1209 > EOF
1177 > EOF
1210
1178
1211 Request to eventual cache URL should return 404 (validating the cache server works)
1179 Request to eventual cache URL should return 404 (validating the cache server works)
1212
1180
1213 $ sendhttpraw << EOF
1181 $ sendhttpraw << EOF
1214 > httprequest GET api/simplecache/missingkey
1182 > httprequest GET api/simplecache/missingkey
1215 > user-agent: test
1183 > user-agent: test
1216 > EOF
1184 > EOF
1217 using raw connection to peer
1185 using raw connection to peer
1218 s> GET /api/simplecache/missingkey HTTP/1.1\r\n
1186 s> GET /api/simplecache/missingkey HTTP/1.1\r\n
1219 s> Accept-Encoding: identity\r\n
1187 s> Accept-Encoding: identity\r\n
1220 s> user-agent: test\r\n
1188 s> user-agent: test\r\n
1221 s> host: $LOCALIP:$HGPORT\r\n (glob)
1189 s> host: $LOCALIP:$HGPORT\r\n (glob)
1222 s> \r\n
1190 s> \r\n
1223 s> makefile('rb', None)
1191 s> makefile('rb', None)
1224 s> HTTP/1.1 404 Not Found\r\n
1192 s> HTTP/1.1 404 Not Found\r\n
1225 s> Server: testing stub value\r\n
1193 s> Server: testing stub value\r\n
1226 s> Date: $HTTP_DATE$\r\n
1194 s> Date: $HTTP_DATE$\r\n
1227 s> Content-Type: text/plain\r\n
1195 s> Content-Type: text/plain\r\n
1228 s> Content-Length: 22\r\n
1196 s> Content-Length: 22\r\n
1229 s> \r\n
1197 s> \r\n
1230 s> key not found in cache
1198 s> key not found in cache
1231
1199
1232 Send a cacheable request
1200 Send a cacheable request
1233
1201
1234 $ sendhttpv2peer << EOF
1202 $ sendhttpv2peer << EOF
1235 > command manifestdata
1203 > command manifestdata
1236 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1204 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1237 > tree eval:b''
1205 > tree eval:b''
1238 > fields eval:[b'parents']
1206 > fields eval:[b'parents']
1239 > EOF
1207 > EOF
1240 creating http peer for wire protocol version 2
1208 creating http peer for wire protocol version 2
1241 sending manifestdata command
1209 sending manifestdata command
1242 response: gen[
1210 response: gen[
1243 {
1211 {
1244 b'totalitems': 1
1212 b'totalitems': 1
1245 },
1213 },
1246 {
1214 {
1247 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1215 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1248 b'parents': [
1216 b'parents': [
1249 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1217 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1250 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1218 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1251 ]
1219 ]
1252 }
1220 }
1253 ]
1221 ]
1254
1222
1255 Cached entry should be available on server
1223 Cached entry should be available on server
1256
1224
1257 $ sendhttpraw << EOF
1225 $ sendhttpraw << EOF
1258 > httprequest GET api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0
1226 > httprequest GET api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0
1259 > user-agent: test
1227 > user-agent: test
1260 > EOF
1228 > EOF
1261 using raw connection to peer
1229 using raw connection to peer
1262 s> GET /api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0 HTTP/1.1\r\n
1230 s> GET /api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0 HTTP/1.1\r\n
1263 s> Accept-Encoding: identity\r\n
1231 s> Accept-Encoding: identity\r\n
1264 s> user-agent: test\r\n
1232 s> user-agent: test\r\n
1265 s> host: $LOCALIP:$HGPORT\r\n (glob)
1233 s> host: $LOCALIP:$HGPORT\r\n (glob)
1266 s> \r\n
1234 s> \r\n
1267 s> makefile('rb', None)
1235 s> makefile('rb', None)
1268 s> HTTP/1.1 200 OK\r\n
1236 s> HTTP/1.1 200 OK\r\n
1269 s> Server: testing stub value\r\n
1237 s> Server: testing stub value\r\n
1270 s> Date: $HTTP_DATE$\r\n
1238 s> Date: $HTTP_DATE$\r\n
1271 s> Content-Type: application/mercurial-cbor\r\n
1239 s> Content-Type: application/mercurial-cbor\r\n
1272 s> Content-Length: 91\r\n
1240 s> Content-Length: 91\r\n
1273 s> \r\n
1241 s> \r\n
1274 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
1242 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
1275 cbor> [
1243 cbor> [
1276 {
1244 {
1277 b'totalitems': 1
1245 b'totalitems': 1
1278 },
1246 },
1279 {
1247 {
1280 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1248 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1281 b'parents': [
1249 b'parents': [
1282 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1250 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1283 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1251 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1284 ]
1252 ]
1285 }
1253 }
1286 ]
1254 ]
1287
1255
1288 2nd request should result in content redirect response
1256 2nd request should result in content redirect response
1289
1257
1290 $ sendhttpv2peer << EOF
1258 $ sendhttpv2peer << EOF
1291 > command manifestdata
1259 > command manifestdata
1292 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1260 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1293 > tree eval:b''
1261 > tree eval:b''
1294 > fields eval:[b'parents']
1262 > fields eval:[b'parents']
1295 > EOF
1263 > EOF
1296 creating http peer for wire protocol version 2
1264 creating http peer for wire protocol version 2
1297 sending manifestdata command
1265 sending manifestdata command
1298 response: gen[
1266 response: gen[
1299 {
1267 {
1300 b'totalitems': 1
1268 b'totalitems': 1
1301 },
1269 },
1302 {
1270 {
1303 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1271 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1304 b'parents': [
1272 b'parents': [
1305 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1273 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1306 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1274 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1307 ]
1275 ]
1308 }
1276 }
1309 ]
1277 ]
1310
1278
1311 $ cat error.log
1279 $ cat error.log
1312 $ killdaemons.py
1280 $ killdaemons.py
1313
1281
1314 $ cat .hg/blackbox.log
1282 $ cat .hg/blackbox.log
1315 *> cacher constructed for manifestdata (glob)
1283 *> cacher constructed for manifestdata (glob)
1316 *> cache miss for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
1284 *> cache miss for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
1317 *> storing cache entry for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
1285 *> storing cache entry for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
1318 *> cacher constructed for manifestdata (glob)
1286 *> cacher constructed for manifestdata (glob)
1319 *> cache hit for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
1287 *> cache hit for c045a581599d58608efd3d93d8129841f2af04a0 (glob)
1320 *> sending content redirect for c045a581599d58608efd3d93d8129841f2af04a0 to http://*:$HGPORT/api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0 (glob)
1288 *> sending content redirect for c045a581599d58608efd3d93d8129841f2af04a0 to http://*:$HGPORT/api/simplecache/c045a581599d58608efd3d93d8129841f2af04a0 (glob)
General Comments 0
You need to be logged in to leave comments. Login now