##// END OF EJS Templates
wireprotov2: advertise recommended batch size for requests...
Gregory Szorc -
r40208:30f70d11 default
parent child Browse files
Show More
@@ -1,1421 +1,1424 b''
1 # configitems.py - centralized declaration of configuration option
1 # configitems.py - centralized declaration of configuration option
2 #
2 #
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import functools
10 import functools
11 import re
11 import re
12
12
13 from . import (
13 from . import (
14 encoding,
14 encoding,
15 error,
15 error,
16 )
16 )
17
17
18 def loadconfigtable(ui, extname, configtable):
18 def loadconfigtable(ui, extname, configtable):
19 """update config item known to the ui with the extension ones"""
19 """update config item known to the ui with the extension ones"""
20 for section, items in sorted(configtable.items()):
20 for section, items in sorted(configtable.items()):
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownkeys = set(knownitems)
22 knownkeys = set(knownitems)
23 newkeys = set(items)
23 newkeys = set(items)
24 for key in sorted(knownkeys & newkeys):
24 for key in sorted(knownkeys & newkeys):
25 msg = "extension '%s' overwrite config item '%s.%s'"
25 msg = "extension '%s' overwrite config item '%s.%s'"
26 msg %= (extname, section, key)
26 msg %= (extname, section, key)
27 ui.develwarn(msg, config='warn-config')
27 ui.develwarn(msg, config='warn-config')
28
28
29 knownitems.update(items)
29 knownitems.update(items)
30
30
31 class configitem(object):
31 class configitem(object):
32 """represent a known config item
32 """represent a known config item
33
33
34 :section: the official config section where to find this item,
34 :section: the official config section where to find this item,
35 :name: the official name within the section,
35 :name: the official name within the section,
36 :default: default value for this item,
36 :default: default value for this item,
37 :alias: optional list of tuples as alternatives,
37 :alias: optional list of tuples as alternatives,
38 :generic: this is a generic definition, match name using regular expression.
38 :generic: this is a generic definition, match name using regular expression.
39 """
39 """
40
40
41 def __init__(self, section, name, default=None, alias=(),
41 def __init__(self, section, name, default=None, alias=(),
42 generic=False, priority=0):
42 generic=False, priority=0):
43 self.section = section
43 self.section = section
44 self.name = name
44 self.name = name
45 self.default = default
45 self.default = default
46 self.alias = list(alias)
46 self.alias = list(alias)
47 self.generic = generic
47 self.generic = generic
48 self.priority = priority
48 self.priority = priority
49 self._re = None
49 self._re = None
50 if generic:
50 if generic:
51 self._re = re.compile(self.name)
51 self._re = re.compile(self.name)
52
52
53 class itemregister(dict):
53 class itemregister(dict):
54 """A specialized dictionary that can handle wild-card selection"""
54 """A specialized dictionary that can handle wild-card selection"""
55
55
56 def __init__(self):
56 def __init__(self):
57 super(itemregister, self).__init__()
57 super(itemregister, self).__init__()
58 self._generics = set()
58 self._generics = set()
59
59
60 def update(self, other):
60 def update(self, other):
61 super(itemregister, self).update(other)
61 super(itemregister, self).update(other)
62 self._generics.update(other._generics)
62 self._generics.update(other._generics)
63
63
64 def __setitem__(self, key, item):
64 def __setitem__(self, key, item):
65 super(itemregister, self).__setitem__(key, item)
65 super(itemregister, self).__setitem__(key, item)
66 if item.generic:
66 if item.generic:
67 self._generics.add(item)
67 self._generics.add(item)
68
68
69 def get(self, key):
69 def get(self, key):
70 baseitem = super(itemregister, self).get(key)
70 baseitem = super(itemregister, self).get(key)
71 if baseitem is not None and not baseitem.generic:
71 if baseitem is not None and not baseitem.generic:
72 return baseitem
72 return baseitem
73
73
74 # search for a matching generic item
74 # search for a matching generic item
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
76 for item in generics:
76 for item in generics:
77 # we use 'match' instead of 'search' to make the matching simpler
77 # we use 'match' instead of 'search' to make the matching simpler
78 # for people unfamiliar with regular expression. Having the match
78 # for people unfamiliar with regular expression. Having the match
79 # rooted to the start of the string will produce less surprising
79 # rooted to the start of the string will produce less surprising
80 # result for user writing simple regex for sub-attribute.
80 # result for user writing simple regex for sub-attribute.
81 #
81 #
82 # For example using "color\..*" match produces an unsurprising
82 # For example using "color\..*" match produces an unsurprising
83 # result, while using search could suddenly match apparently
83 # result, while using search could suddenly match apparently
84 # unrelated configuration that happens to contains "color."
84 # unrelated configuration that happens to contains "color."
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
86 # some match to avoid the need to prefix most pattern with "^".
86 # some match to avoid the need to prefix most pattern with "^".
87 # The "^" seems more error prone.
87 # The "^" seems more error prone.
88 if item._re.match(key):
88 if item._re.match(key):
89 return item
89 return item
90
90
91 return None
91 return None
92
92
93 coreitems = {}
93 coreitems = {}
94
94
95 def _register(configtable, *args, **kwargs):
95 def _register(configtable, *args, **kwargs):
96 item = configitem(*args, **kwargs)
96 item = configitem(*args, **kwargs)
97 section = configtable.setdefault(item.section, itemregister())
97 section = configtable.setdefault(item.section, itemregister())
98 if item.name in section:
98 if item.name in section:
99 msg = "duplicated config item registration for '%s.%s'"
99 msg = "duplicated config item registration for '%s.%s'"
100 raise error.ProgrammingError(msg % (item.section, item.name))
100 raise error.ProgrammingError(msg % (item.section, item.name))
101 section[item.name] = item
101 section[item.name] = item
102
102
103 # special value for case where the default is derived from other values
103 # special value for case where the default is derived from other values
104 dynamicdefault = object()
104 dynamicdefault = object()
105
105
106 # Registering actual config items
106 # Registering actual config items
107
107
108 def getitemregister(configtable):
108 def getitemregister(configtable):
109 f = functools.partial(_register, configtable)
109 f = functools.partial(_register, configtable)
110 # export pseudo enum as configitem.*
110 # export pseudo enum as configitem.*
111 f.dynamicdefault = dynamicdefault
111 f.dynamicdefault = dynamicdefault
112 return f
112 return f
113
113
114 coreconfigitem = getitemregister(coreitems)
114 coreconfigitem = getitemregister(coreitems)
115
115
116 coreconfigitem('alias', '.*',
116 coreconfigitem('alias', '.*',
117 default=dynamicdefault,
117 default=dynamicdefault,
118 generic=True,
118 generic=True,
119 )
119 )
120 coreconfigitem('annotate', 'nodates',
120 coreconfigitem('annotate', 'nodates',
121 default=False,
121 default=False,
122 )
122 )
123 coreconfigitem('annotate', 'showfunc',
123 coreconfigitem('annotate', 'showfunc',
124 default=False,
124 default=False,
125 )
125 )
126 coreconfigitem('annotate', 'unified',
126 coreconfigitem('annotate', 'unified',
127 default=None,
127 default=None,
128 )
128 )
129 coreconfigitem('annotate', 'git',
129 coreconfigitem('annotate', 'git',
130 default=False,
130 default=False,
131 )
131 )
132 coreconfigitem('annotate', 'ignorews',
132 coreconfigitem('annotate', 'ignorews',
133 default=False,
133 default=False,
134 )
134 )
135 coreconfigitem('annotate', 'ignorewsamount',
135 coreconfigitem('annotate', 'ignorewsamount',
136 default=False,
136 default=False,
137 )
137 )
138 coreconfigitem('annotate', 'ignoreblanklines',
138 coreconfigitem('annotate', 'ignoreblanklines',
139 default=False,
139 default=False,
140 )
140 )
141 coreconfigitem('annotate', 'ignorewseol',
141 coreconfigitem('annotate', 'ignorewseol',
142 default=False,
142 default=False,
143 )
143 )
144 coreconfigitem('annotate', 'nobinary',
144 coreconfigitem('annotate', 'nobinary',
145 default=False,
145 default=False,
146 )
146 )
147 coreconfigitem('annotate', 'noprefix',
147 coreconfigitem('annotate', 'noprefix',
148 default=False,
148 default=False,
149 )
149 )
150 coreconfigitem('annotate', 'word-diff',
150 coreconfigitem('annotate', 'word-diff',
151 default=False,
151 default=False,
152 )
152 )
153 coreconfigitem('auth', 'cookiefile',
153 coreconfigitem('auth', 'cookiefile',
154 default=None,
154 default=None,
155 )
155 )
156 # bookmarks.pushing: internal hack for discovery
156 # bookmarks.pushing: internal hack for discovery
157 coreconfigitem('bookmarks', 'pushing',
157 coreconfigitem('bookmarks', 'pushing',
158 default=list,
158 default=list,
159 )
159 )
160 # bundle.mainreporoot: internal hack for bundlerepo
160 # bundle.mainreporoot: internal hack for bundlerepo
161 coreconfigitem('bundle', 'mainreporoot',
161 coreconfigitem('bundle', 'mainreporoot',
162 default='',
162 default='',
163 )
163 )
164 coreconfigitem('censor', 'policy',
164 coreconfigitem('censor', 'policy',
165 default='abort',
165 default='abort',
166 )
166 )
167 coreconfigitem('chgserver', 'idletimeout',
167 coreconfigitem('chgserver', 'idletimeout',
168 default=3600,
168 default=3600,
169 )
169 )
170 coreconfigitem('chgserver', 'skiphash',
170 coreconfigitem('chgserver', 'skiphash',
171 default=False,
171 default=False,
172 )
172 )
173 coreconfigitem('cmdserver', 'log',
173 coreconfigitem('cmdserver', 'log',
174 default=None,
174 default=None,
175 )
175 )
176 coreconfigitem('color', '.*',
176 coreconfigitem('color', '.*',
177 default=None,
177 default=None,
178 generic=True,
178 generic=True,
179 )
179 )
180 coreconfigitem('color', 'mode',
180 coreconfigitem('color', 'mode',
181 default='auto',
181 default='auto',
182 )
182 )
183 coreconfigitem('color', 'pagermode',
183 coreconfigitem('color', 'pagermode',
184 default=dynamicdefault,
184 default=dynamicdefault,
185 )
185 )
186 coreconfigitem('commands', 'grep.all-files',
186 coreconfigitem('commands', 'grep.all-files',
187 default=False,
187 default=False,
188 )
188 )
189 coreconfigitem('commands', 'resolve.confirm',
189 coreconfigitem('commands', 'resolve.confirm',
190 default=False,
190 default=False,
191 )
191 )
192 coreconfigitem('commands', 'resolve.explicit-re-merge',
192 coreconfigitem('commands', 'resolve.explicit-re-merge',
193 default=False,
193 default=False,
194 )
194 )
195 coreconfigitem('commands', 'resolve.mark-check',
195 coreconfigitem('commands', 'resolve.mark-check',
196 default='none',
196 default='none',
197 )
197 )
198 coreconfigitem('commands', 'show.aliasprefix',
198 coreconfigitem('commands', 'show.aliasprefix',
199 default=list,
199 default=list,
200 )
200 )
201 coreconfigitem('commands', 'status.relative',
201 coreconfigitem('commands', 'status.relative',
202 default=False,
202 default=False,
203 )
203 )
204 coreconfigitem('commands', 'status.skipstates',
204 coreconfigitem('commands', 'status.skipstates',
205 default=[],
205 default=[],
206 )
206 )
207 coreconfigitem('commands', 'status.terse',
207 coreconfigitem('commands', 'status.terse',
208 default='',
208 default='',
209 )
209 )
210 coreconfigitem('commands', 'status.verbose',
210 coreconfigitem('commands', 'status.verbose',
211 default=False,
211 default=False,
212 )
212 )
213 coreconfigitem('commands', 'update.check',
213 coreconfigitem('commands', 'update.check',
214 default=None,
214 default=None,
215 )
215 )
216 coreconfigitem('commands', 'update.requiredest',
216 coreconfigitem('commands', 'update.requiredest',
217 default=False,
217 default=False,
218 )
218 )
219 coreconfigitem('committemplate', '.*',
219 coreconfigitem('committemplate', '.*',
220 default=None,
220 default=None,
221 generic=True,
221 generic=True,
222 )
222 )
223 coreconfigitem('convert', 'bzr.saverev',
223 coreconfigitem('convert', 'bzr.saverev',
224 default=True,
224 default=True,
225 )
225 )
226 coreconfigitem('convert', 'cvsps.cache',
226 coreconfigitem('convert', 'cvsps.cache',
227 default=True,
227 default=True,
228 )
228 )
229 coreconfigitem('convert', 'cvsps.fuzz',
229 coreconfigitem('convert', 'cvsps.fuzz',
230 default=60,
230 default=60,
231 )
231 )
232 coreconfigitem('convert', 'cvsps.logencoding',
232 coreconfigitem('convert', 'cvsps.logencoding',
233 default=None,
233 default=None,
234 )
234 )
235 coreconfigitem('convert', 'cvsps.mergefrom',
235 coreconfigitem('convert', 'cvsps.mergefrom',
236 default=None,
236 default=None,
237 )
237 )
238 coreconfigitem('convert', 'cvsps.mergeto',
238 coreconfigitem('convert', 'cvsps.mergeto',
239 default=None,
239 default=None,
240 )
240 )
241 coreconfigitem('convert', 'git.committeractions',
241 coreconfigitem('convert', 'git.committeractions',
242 default=lambda: ['messagedifferent'],
242 default=lambda: ['messagedifferent'],
243 )
243 )
244 coreconfigitem('convert', 'git.extrakeys',
244 coreconfigitem('convert', 'git.extrakeys',
245 default=list,
245 default=list,
246 )
246 )
247 coreconfigitem('convert', 'git.findcopiesharder',
247 coreconfigitem('convert', 'git.findcopiesharder',
248 default=False,
248 default=False,
249 )
249 )
250 coreconfigitem('convert', 'git.remoteprefix',
250 coreconfigitem('convert', 'git.remoteprefix',
251 default='remote',
251 default='remote',
252 )
252 )
253 coreconfigitem('convert', 'git.renamelimit',
253 coreconfigitem('convert', 'git.renamelimit',
254 default=400,
254 default=400,
255 )
255 )
256 coreconfigitem('convert', 'git.saverev',
256 coreconfigitem('convert', 'git.saverev',
257 default=True,
257 default=True,
258 )
258 )
259 coreconfigitem('convert', 'git.similarity',
259 coreconfigitem('convert', 'git.similarity',
260 default=50,
260 default=50,
261 )
261 )
262 coreconfigitem('convert', 'git.skipsubmodules',
262 coreconfigitem('convert', 'git.skipsubmodules',
263 default=False,
263 default=False,
264 )
264 )
265 coreconfigitem('convert', 'hg.clonebranches',
265 coreconfigitem('convert', 'hg.clonebranches',
266 default=False,
266 default=False,
267 )
267 )
268 coreconfigitem('convert', 'hg.ignoreerrors',
268 coreconfigitem('convert', 'hg.ignoreerrors',
269 default=False,
269 default=False,
270 )
270 )
271 coreconfigitem('convert', 'hg.revs',
271 coreconfigitem('convert', 'hg.revs',
272 default=None,
272 default=None,
273 )
273 )
274 coreconfigitem('convert', 'hg.saverev',
274 coreconfigitem('convert', 'hg.saverev',
275 default=False,
275 default=False,
276 )
276 )
277 coreconfigitem('convert', 'hg.sourcename',
277 coreconfigitem('convert', 'hg.sourcename',
278 default=None,
278 default=None,
279 )
279 )
280 coreconfigitem('convert', 'hg.startrev',
280 coreconfigitem('convert', 'hg.startrev',
281 default=None,
281 default=None,
282 )
282 )
283 coreconfigitem('convert', 'hg.tagsbranch',
283 coreconfigitem('convert', 'hg.tagsbranch',
284 default='default',
284 default='default',
285 )
285 )
286 coreconfigitem('convert', 'hg.usebranchnames',
286 coreconfigitem('convert', 'hg.usebranchnames',
287 default=True,
287 default=True,
288 )
288 )
289 coreconfigitem('convert', 'ignoreancestorcheck',
289 coreconfigitem('convert', 'ignoreancestorcheck',
290 default=False,
290 default=False,
291 )
291 )
292 coreconfigitem('convert', 'localtimezone',
292 coreconfigitem('convert', 'localtimezone',
293 default=False,
293 default=False,
294 )
294 )
295 coreconfigitem('convert', 'p4.encoding',
295 coreconfigitem('convert', 'p4.encoding',
296 default=dynamicdefault,
296 default=dynamicdefault,
297 )
297 )
298 coreconfigitem('convert', 'p4.startrev',
298 coreconfigitem('convert', 'p4.startrev',
299 default=0,
299 default=0,
300 )
300 )
301 coreconfigitem('convert', 'skiptags',
301 coreconfigitem('convert', 'skiptags',
302 default=False,
302 default=False,
303 )
303 )
304 coreconfigitem('convert', 'svn.debugsvnlog',
304 coreconfigitem('convert', 'svn.debugsvnlog',
305 default=True,
305 default=True,
306 )
306 )
307 coreconfigitem('convert', 'svn.trunk',
307 coreconfigitem('convert', 'svn.trunk',
308 default=None,
308 default=None,
309 )
309 )
310 coreconfigitem('convert', 'svn.tags',
310 coreconfigitem('convert', 'svn.tags',
311 default=None,
311 default=None,
312 )
312 )
313 coreconfigitem('convert', 'svn.branches',
313 coreconfigitem('convert', 'svn.branches',
314 default=None,
314 default=None,
315 )
315 )
316 coreconfigitem('convert', 'svn.startrev',
316 coreconfigitem('convert', 'svn.startrev',
317 default=0,
317 default=0,
318 )
318 )
319 coreconfigitem('debug', 'dirstate.delaywrite',
319 coreconfigitem('debug', 'dirstate.delaywrite',
320 default=0,
320 default=0,
321 )
321 )
322 coreconfigitem('defaults', '.*',
322 coreconfigitem('defaults', '.*',
323 default=None,
323 default=None,
324 generic=True,
324 generic=True,
325 )
325 )
326 coreconfigitem('devel', 'all-warnings',
326 coreconfigitem('devel', 'all-warnings',
327 default=False,
327 default=False,
328 )
328 )
329 coreconfigitem('devel', 'bundle2.debug',
329 coreconfigitem('devel', 'bundle2.debug',
330 default=False,
330 default=False,
331 )
331 )
332 coreconfigitem('devel', 'cache-vfs',
332 coreconfigitem('devel', 'cache-vfs',
333 default=None,
333 default=None,
334 )
334 )
335 coreconfigitem('devel', 'check-locks',
335 coreconfigitem('devel', 'check-locks',
336 default=False,
336 default=False,
337 )
337 )
338 coreconfigitem('devel', 'check-relroot',
338 coreconfigitem('devel', 'check-relroot',
339 default=False,
339 default=False,
340 )
340 )
341 coreconfigitem('devel', 'default-date',
341 coreconfigitem('devel', 'default-date',
342 default=None,
342 default=None,
343 )
343 )
344 coreconfigitem('devel', 'deprec-warn',
344 coreconfigitem('devel', 'deprec-warn',
345 default=False,
345 default=False,
346 )
346 )
347 coreconfigitem('devel', 'disableloaddefaultcerts',
347 coreconfigitem('devel', 'disableloaddefaultcerts',
348 default=False,
348 default=False,
349 )
349 )
350 coreconfigitem('devel', 'warn-empty-changegroup',
350 coreconfigitem('devel', 'warn-empty-changegroup',
351 default=False,
351 default=False,
352 )
352 )
353 coreconfigitem('devel', 'legacy.exchange',
353 coreconfigitem('devel', 'legacy.exchange',
354 default=list,
354 default=list,
355 )
355 )
356 coreconfigitem('devel', 'servercafile',
356 coreconfigitem('devel', 'servercafile',
357 default='',
357 default='',
358 )
358 )
359 coreconfigitem('devel', 'serverexactprotocol',
359 coreconfigitem('devel', 'serverexactprotocol',
360 default='',
360 default='',
361 )
361 )
362 coreconfigitem('devel', 'serverrequirecert',
362 coreconfigitem('devel', 'serverrequirecert',
363 default=False,
363 default=False,
364 )
364 )
365 coreconfigitem('devel', 'strip-obsmarkers',
365 coreconfigitem('devel', 'strip-obsmarkers',
366 default=True,
366 default=True,
367 )
367 )
368 coreconfigitem('devel', 'warn-config',
368 coreconfigitem('devel', 'warn-config',
369 default=None,
369 default=None,
370 )
370 )
371 coreconfigitem('devel', 'warn-config-default',
371 coreconfigitem('devel', 'warn-config-default',
372 default=None,
372 default=None,
373 )
373 )
374 coreconfigitem('devel', 'user.obsmarker',
374 coreconfigitem('devel', 'user.obsmarker',
375 default=None,
375 default=None,
376 )
376 )
377 coreconfigitem('devel', 'warn-config-unknown',
377 coreconfigitem('devel', 'warn-config-unknown',
378 default=None,
378 default=None,
379 )
379 )
380 coreconfigitem('devel', 'debug.copies',
380 coreconfigitem('devel', 'debug.copies',
381 default=False,
381 default=False,
382 )
382 )
383 coreconfigitem('devel', 'debug.extensions',
383 coreconfigitem('devel', 'debug.extensions',
384 default=False,
384 default=False,
385 )
385 )
386 coreconfigitem('devel', 'debug.peer-request',
386 coreconfigitem('devel', 'debug.peer-request',
387 default=False,
387 default=False,
388 )
388 )
389 coreconfigitem('diff', 'nodates',
389 coreconfigitem('diff', 'nodates',
390 default=False,
390 default=False,
391 )
391 )
392 coreconfigitem('diff', 'showfunc',
392 coreconfigitem('diff', 'showfunc',
393 default=False,
393 default=False,
394 )
394 )
395 coreconfigitem('diff', 'unified',
395 coreconfigitem('diff', 'unified',
396 default=None,
396 default=None,
397 )
397 )
398 coreconfigitem('diff', 'git',
398 coreconfigitem('diff', 'git',
399 default=False,
399 default=False,
400 )
400 )
401 coreconfigitem('diff', 'ignorews',
401 coreconfigitem('diff', 'ignorews',
402 default=False,
402 default=False,
403 )
403 )
404 coreconfigitem('diff', 'ignorewsamount',
404 coreconfigitem('diff', 'ignorewsamount',
405 default=False,
405 default=False,
406 )
406 )
407 coreconfigitem('diff', 'ignoreblanklines',
407 coreconfigitem('diff', 'ignoreblanklines',
408 default=False,
408 default=False,
409 )
409 )
410 coreconfigitem('diff', 'ignorewseol',
410 coreconfigitem('diff', 'ignorewseol',
411 default=False,
411 default=False,
412 )
412 )
413 coreconfigitem('diff', 'nobinary',
413 coreconfigitem('diff', 'nobinary',
414 default=False,
414 default=False,
415 )
415 )
416 coreconfigitem('diff', 'noprefix',
416 coreconfigitem('diff', 'noprefix',
417 default=False,
417 default=False,
418 )
418 )
419 coreconfigitem('diff', 'word-diff',
419 coreconfigitem('diff', 'word-diff',
420 default=False,
420 default=False,
421 )
421 )
422 coreconfigitem('email', 'bcc',
422 coreconfigitem('email', 'bcc',
423 default=None,
423 default=None,
424 )
424 )
425 coreconfigitem('email', 'cc',
425 coreconfigitem('email', 'cc',
426 default=None,
426 default=None,
427 )
427 )
428 coreconfigitem('email', 'charsets',
428 coreconfigitem('email', 'charsets',
429 default=list,
429 default=list,
430 )
430 )
431 coreconfigitem('email', 'from',
431 coreconfigitem('email', 'from',
432 default=None,
432 default=None,
433 )
433 )
434 coreconfigitem('email', 'method',
434 coreconfigitem('email', 'method',
435 default='smtp',
435 default='smtp',
436 )
436 )
437 coreconfigitem('email', 'reply-to',
437 coreconfigitem('email', 'reply-to',
438 default=None,
438 default=None,
439 )
439 )
440 coreconfigitem('email', 'to',
440 coreconfigitem('email', 'to',
441 default=None,
441 default=None,
442 )
442 )
443 coreconfigitem('experimental', 'archivemetatemplate',
443 coreconfigitem('experimental', 'archivemetatemplate',
444 default=dynamicdefault,
444 default=dynamicdefault,
445 )
445 )
446 coreconfigitem('experimental', 'bundle-phases',
446 coreconfigitem('experimental', 'bundle-phases',
447 default=False,
447 default=False,
448 )
448 )
449 coreconfigitem('experimental', 'bundle2-advertise',
449 coreconfigitem('experimental', 'bundle2-advertise',
450 default=True,
450 default=True,
451 )
451 )
452 coreconfigitem('experimental', 'bundle2-output-capture',
452 coreconfigitem('experimental', 'bundle2-output-capture',
453 default=False,
453 default=False,
454 )
454 )
455 coreconfigitem('experimental', 'bundle2.pushback',
455 coreconfigitem('experimental', 'bundle2.pushback',
456 default=False,
456 default=False,
457 )
457 )
458 coreconfigitem('experimental', 'bundle2lazylocking',
458 coreconfigitem('experimental', 'bundle2lazylocking',
459 default=False,
459 default=False,
460 )
460 )
461 coreconfigitem('experimental', 'bundlecomplevel',
461 coreconfigitem('experimental', 'bundlecomplevel',
462 default=None,
462 default=None,
463 )
463 )
464 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
464 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
465 default=None,
465 default=None,
466 )
466 )
467 coreconfigitem('experimental', 'bundlecomplevel.gzip',
467 coreconfigitem('experimental', 'bundlecomplevel.gzip',
468 default=None,
468 default=None,
469 )
469 )
470 coreconfigitem('experimental', 'bundlecomplevel.none',
470 coreconfigitem('experimental', 'bundlecomplevel.none',
471 default=None,
471 default=None,
472 )
472 )
473 coreconfigitem('experimental', 'bundlecomplevel.zstd',
473 coreconfigitem('experimental', 'bundlecomplevel.zstd',
474 default=None,
474 default=None,
475 )
475 )
476 coreconfigitem('experimental', 'changegroup3',
476 coreconfigitem('experimental', 'changegroup3',
477 default=False,
477 default=False,
478 )
478 )
479 coreconfigitem('experimental', 'clientcompressionengines',
479 coreconfigitem('experimental', 'clientcompressionengines',
480 default=list,
480 default=list,
481 )
481 )
482 coreconfigitem('experimental', 'copytrace',
482 coreconfigitem('experimental', 'copytrace',
483 default='on',
483 default='on',
484 )
484 )
485 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
485 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
486 default=100,
486 default=100,
487 )
487 )
488 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
488 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
489 default=100,
489 default=100,
490 )
490 )
491 coreconfigitem('experimental', 'crecordtest',
491 coreconfigitem('experimental', 'crecordtest',
492 default=None,
492 default=None,
493 )
493 )
494 coreconfigitem('experimental', 'directaccess',
494 coreconfigitem('experimental', 'directaccess',
495 default=False,
495 default=False,
496 )
496 )
497 coreconfigitem('experimental', 'directaccess.revnums',
497 coreconfigitem('experimental', 'directaccess.revnums',
498 default=False,
498 default=False,
499 )
499 )
500 coreconfigitem('experimental', 'editortmpinhg',
500 coreconfigitem('experimental', 'editortmpinhg',
501 default=False,
501 default=False,
502 )
502 )
503 coreconfigitem('experimental', 'evolution',
503 coreconfigitem('experimental', 'evolution',
504 default=list,
504 default=list,
505 )
505 )
506 coreconfigitem('experimental', 'evolution.allowdivergence',
506 coreconfigitem('experimental', 'evolution.allowdivergence',
507 default=False,
507 default=False,
508 alias=[('experimental', 'allowdivergence')]
508 alias=[('experimental', 'allowdivergence')]
509 )
509 )
510 coreconfigitem('experimental', 'evolution.allowunstable',
510 coreconfigitem('experimental', 'evolution.allowunstable',
511 default=None,
511 default=None,
512 )
512 )
513 coreconfigitem('experimental', 'evolution.createmarkers',
513 coreconfigitem('experimental', 'evolution.createmarkers',
514 default=None,
514 default=None,
515 )
515 )
516 coreconfigitem('experimental', 'evolution.effect-flags',
516 coreconfigitem('experimental', 'evolution.effect-flags',
517 default=True,
517 default=True,
518 alias=[('experimental', 'effect-flags')]
518 alias=[('experimental', 'effect-flags')]
519 )
519 )
520 coreconfigitem('experimental', 'evolution.exchange',
520 coreconfigitem('experimental', 'evolution.exchange',
521 default=None,
521 default=None,
522 )
522 )
523 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
523 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
524 default=False,
524 default=False,
525 )
525 )
526 coreconfigitem('experimental', 'evolution.report-instabilities',
526 coreconfigitem('experimental', 'evolution.report-instabilities',
527 default=True,
527 default=True,
528 )
528 )
529 coreconfigitem('experimental', 'evolution.track-operation',
529 coreconfigitem('experimental', 'evolution.track-operation',
530 default=True,
530 default=True,
531 )
531 )
532 coreconfigitem('experimental', 'maxdeltachainspan',
532 coreconfigitem('experimental', 'maxdeltachainspan',
533 default=-1,
533 default=-1,
534 )
534 )
535 coreconfigitem('experimental', 'mergetempdirprefix',
535 coreconfigitem('experimental', 'mergetempdirprefix',
536 default=None,
536 default=None,
537 )
537 )
538 coreconfigitem('experimental', 'mmapindexthreshold',
538 coreconfigitem('experimental', 'mmapindexthreshold',
539 default=None,
539 default=None,
540 )
540 )
541 coreconfigitem('experimental', 'narrow',
541 coreconfigitem('experimental', 'narrow',
542 default=False,
542 default=False,
543 )
543 )
544 coreconfigitem('experimental', 'nonnormalparanoidcheck',
544 coreconfigitem('experimental', 'nonnormalparanoidcheck',
545 default=False,
545 default=False,
546 )
546 )
547 coreconfigitem('experimental', 'exportableenviron',
547 coreconfigitem('experimental', 'exportableenviron',
548 default=list,
548 default=list,
549 )
549 )
550 coreconfigitem('experimental', 'extendedheader.index',
550 coreconfigitem('experimental', 'extendedheader.index',
551 default=None,
551 default=None,
552 )
552 )
553 coreconfigitem('experimental', 'extendedheader.similarity',
553 coreconfigitem('experimental', 'extendedheader.similarity',
554 default=False,
554 default=False,
555 )
555 )
556 coreconfigitem('experimental', 'format.compression',
556 coreconfigitem('experimental', 'format.compression',
557 default='zlib',
557 default='zlib',
558 )
558 )
559 coreconfigitem('experimental', 'graphshorten',
559 coreconfigitem('experimental', 'graphshorten',
560 default=False,
560 default=False,
561 )
561 )
562 coreconfigitem('experimental', 'graphstyle.parent',
562 coreconfigitem('experimental', 'graphstyle.parent',
563 default=dynamicdefault,
563 default=dynamicdefault,
564 )
564 )
565 coreconfigitem('experimental', 'graphstyle.missing',
565 coreconfigitem('experimental', 'graphstyle.missing',
566 default=dynamicdefault,
566 default=dynamicdefault,
567 )
567 )
568 coreconfigitem('experimental', 'graphstyle.grandparent',
568 coreconfigitem('experimental', 'graphstyle.grandparent',
569 default=dynamicdefault,
569 default=dynamicdefault,
570 )
570 )
571 coreconfigitem('experimental', 'hook-track-tags',
571 coreconfigitem('experimental', 'hook-track-tags',
572 default=False,
572 default=False,
573 )
573 )
574 coreconfigitem('experimental', 'httppeer.advertise-v2',
574 coreconfigitem('experimental', 'httppeer.advertise-v2',
575 default=False,
575 default=False,
576 )
576 )
577 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
577 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
578 default=None,
578 default=None,
579 )
579 )
580 coreconfigitem('experimental', 'httppostargs',
580 coreconfigitem('experimental', 'httppostargs',
581 default=False,
581 default=False,
582 )
582 )
583 coreconfigitem('experimental', 'mergedriver',
583 coreconfigitem('experimental', 'mergedriver',
584 default=None,
584 default=None,
585 )
585 )
586 coreconfigitem('experimental', 'nointerrupt', default=False)
586 coreconfigitem('experimental', 'nointerrupt', default=False)
587 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
587 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
588
588
589 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
589 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
590 default=False,
590 default=False,
591 )
591 )
592 coreconfigitem('experimental', 'remotenames',
592 coreconfigitem('experimental', 'remotenames',
593 default=False,
593 default=False,
594 )
594 )
595 coreconfigitem('experimental', 'removeemptydirs',
595 coreconfigitem('experimental', 'removeemptydirs',
596 default=True,
596 default=True,
597 )
597 )
598 coreconfigitem('experimental', 'revisions.prefixhexnode',
598 coreconfigitem('experimental', 'revisions.prefixhexnode',
599 default=False,
599 default=False,
600 )
600 )
601 coreconfigitem('experimental', 'revlogv2',
601 coreconfigitem('experimental', 'revlogv2',
602 default=None,
602 default=None,
603 )
603 )
604 coreconfigitem('experimental', 'revisions.disambiguatewithin',
604 coreconfigitem('experimental', 'revisions.disambiguatewithin',
605 default=None,
605 default=None,
606 )
606 )
607 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
608 default=100000,
609 )
607 coreconfigitem('experimental', 'single-head-per-branch',
610 coreconfigitem('experimental', 'single-head-per-branch',
608 default=False,
611 default=False,
609 )
612 )
610 coreconfigitem('experimental', 'sshserver.support-v2',
613 coreconfigitem('experimental', 'sshserver.support-v2',
611 default=False,
614 default=False,
612 )
615 )
613 coreconfigitem('experimental', 'spacemovesdown',
616 coreconfigitem('experimental', 'spacemovesdown',
614 default=False,
617 default=False,
615 )
618 )
616 coreconfigitem('experimental', 'sparse-read',
619 coreconfigitem('experimental', 'sparse-read',
617 default=False,
620 default=False,
618 )
621 )
619 coreconfigitem('experimental', 'sparse-read.density-threshold',
622 coreconfigitem('experimental', 'sparse-read.density-threshold',
620 default=0.50,
623 default=0.50,
621 )
624 )
622 coreconfigitem('experimental', 'sparse-read.min-gap-size',
625 coreconfigitem('experimental', 'sparse-read.min-gap-size',
623 default='65K',
626 default='65K',
624 )
627 )
625 coreconfigitem('experimental', 'treemanifest',
628 coreconfigitem('experimental', 'treemanifest',
626 default=False,
629 default=False,
627 )
630 )
628 coreconfigitem('experimental', 'update.atomic-file',
631 coreconfigitem('experimental', 'update.atomic-file',
629 default=False,
632 default=False,
630 )
633 )
631 coreconfigitem('experimental', 'sshpeer.advertise-v2',
634 coreconfigitem('experimental', 'sshpeer.advertise-v2',
632 default=False,
635 default=False,
633 )
636 )
634 coreconfigitem('experimental', 'web.apiserver',
637 coreconfigitem('experimental', 'web.apiserver',
635 default=False,
638 default=False,
636 )
639 )
637 coreconfigitem('experimental', 'web.api.http-v2',
640 coreconfigitem('experimental', 'web.api.http-v2',
638 default=False,
641 default=False,
639 )
642 )
640 coreconfigitem('experimental', 'web.api.debugreflect',
643 coreconfigitem('experimental', 'web.api.debugreflect',
641 default=False,
644 default=False,
642 )
645 )
643 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
646 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
644 default=False,
647 default=False,
645 )
648 )
646 coreconfigitem('experimental', 'xdiff',
649 coreconfigitem('experimental', 'xdiff',
647 default=False,
650 default=False,
648 )
651 )
649 coreconfigitem('extensions', '.*',
652 coreconfigitem('extensions', '.*',
650 default=None,
653 default=None,
651 generic=True,
654 generic=True,
652 )
655 )
653 coreconfigitem('extdata', '.*',
656 coreconfigitem('extdata', '.*',
654 default=None,
657 default=None,
655 generic=True,
658 generic=True,
656 )
659 )
657 coreconfigitem('format', 'chunkcachesize',
660 coreconfigitem('format', 'chunkcachesize',
658 default=None,
661 default=None,
659 )
662 )
660 coreconfigitem('format', 'dotencode',
663 coreconfigitem('format', 'dotencode',
661 default=True,
664 default=True,
662 )
665 )
663 coreconfigitem('format', 'generaldelta',
666 coreconfigitem('format', 'generaldelta',
664 default=False,
667 default=False,
665 )
668 )
666 coreconfigitem('format', 'manifestcachesize',
669 coreconfigitem('format', 'manifestcachesize',
667 default=None,
670 default=None,
668 )
671 )
669 coreconfigitem('format', 'maxchainlen',
672 coreconfigitem('format', 'maxchainlen',
670 default=dynamicdefault,
673 default=dynamicdefault,
671 )
674 )
672 coreconfigitem('format', 'obsstore-version',
675 coreconfigitem('format', 'obsstore-version',
673 default=None,
676 default=None,
674 )
677 )
675 coreconfigitem('format', 'sparse-revlog',
678 coreconfigitem('format', 'sparse-revlog',
676 default=False,
679 default=False,
677 )
680 )
678 coreconfigitem('format', 'usefncache',
681 coreconfigitem('format', 'usefncache',
679 default=True,
682 default=True,
680 )
683 )
681 coreconfigitem('format', 'usegeneraldelta',
684 coreconfigitem('format', 'usegeneraldelta',
682 default=True,
685 default=True,
683 )
686 )
684 coreconfigitem('format', 'usestore',
687 coreconfigitem('format', 'usestore',
685 default=True,
688 default=True,
686 )
689 )
687 coreconfigitem('format', 'internal-phase',
690 coreconfigitem('format', 'internal-phase',
688 default=False,
691 default=False,
689 )
692 )
690 coreconfigitem('fsmonitor', 'warn_when_unused',
693 coreconfigitem('fsmonitor', 'warn_when_unused',
691 default=True,
694 default=True,
692 )
695 )
693 coreconfigitem('fsmonitor', 'warn_update_file_count',
696 coreconfigitem('fsmonitor', 'warn_update_file_count',
694 default=50000,
697 default=50000,
695 )
698 )
696 coreconfigitem('hooks', '.*',
699 coreconfigitem('hooks', '.*',
697 default=dynamicdefault,
700 default=dynamicdefault,
698 generic=True,
701 generic=True,
699 )
702 )
700 coreconfigitem('hgweb-paths', '.*',
703 coreconfigitem('hgweb-paths', '.*',
701 default=list,
704 default=list,
702 generic=True,
705 generic=True,
703 )
706 )
704 coreconfigitem('hostfingerprints', '.*',
707 coreconfigitem('hostfingerprints', '.*',
705 default=list,
708 default=list,
706 generic=True,
709 generic=True,
707 )
710 )
708 coreconfigitem('hostsecurity', 'ciphers',
711 coreconfigitem('hostsecurity', 'ciphers',
709 default=None,
712 default=None,
710 )
713 )
711 coreconfigitem('hostsecurity', 'disabletls10warning',
714 coreconfigitem('hostsecurity', 'disabletls10warning',
712 default=False,
715 default=False,
713 )
716 )
714 coreconfigitem('hostsecurity', 'minimumprotocol',
717 coreconfigitem('hostsecurity', 'minimumprotocol',
715 default=dynamicdefault,
718 default=dynamicdefault,
716 )
719 )
717 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
720 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
718 default=dynamicdefault,
721 default=dynamicdefault,
719 generic=True,
722 generic=True,
720 )
723 )
721 coreconfigitem('hostsecurity', '.*:ciphers$',
724 coreconfigitem('hostsecurity', '.*:ciphers$',
722 default=dynamicdefault,
725 default=dynamicdefault,
723 generic=True,
726 generic=True,
724 )
727 )
725 coreconfigitem('hostsecurity', '.*:fingerprints$',
728 coreconfigitem('hostsecurity', '.*:fingerprints$',
726 default=list,
729 default=list,
727 generic=True,
730 generic=True,
728 )
731 )
729 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
732 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
730 default=None,
733 default=None,
731 generic=True,
734 generic=True,
732 )
735 )
733
736
734 coreconfigitem('http_proxy', 'always',
737 coreconfigitem('http_proxy', 'always',
735 default=False,
738 default=False,
736 )
739 )
737 coreconfigitem('http_proxy', 'host',
740 coreconfigitem('http_proxy', 'host',
738 default=None,
741 default=None,
739 )
742 )
740 coreconfigitem('http_proxy', 'no',
743 coreconfigitem('http_proxy', 'no',
741 default=list,
744 default=list,
742 )
745 )
743 coreconfigitem('http_proxy', 'passwd',
746 coreconfigitem('http_proxy', 'passwd',
744 default=None,
747 default=None,
745 )
748 )
746 coreconfigitem('http_proxy', 'user',
749 coreconfigitem('http_proxy', 'user',
747 default=None,
750 default=None,
748 )
751 )
749
752
750 coreconfigitem('http', 'timeout',
753 coreconfigitem('http', 'timeout',
751 default=None,
754 default=None,
752 )
755 )
753
756
754 coreconfigitem('logtoprocess', 'commandexception',
757 coreconfigitem('logtoprocess', 'commandexception',
755 default=None,
758 default=None,
756 )
759 )
757 coreconfigitem('logtoprocess', 'commandfinish',
760 coreconfigitem('logtoprocess', 'commandfinish',
758 default=None,
761 default=None,
759 )
762 )
760 coreconfigitem('logtoprocess', 'command',
763 coreconfigitem('logtoprocess', 'command',
761 default=None,
764 default=None,
762 )
765 )
763 coreconfigitem('logtoprocess', 'develwarn',
766 coreconfigitem('logtoprocess', 'develwarn',
764 default=None,
767 default=None,
765 )
768 )
766 coreconfigitem('logtoprocess', 'uiblocked',
769 coreconfigitem('logtoprocess', 'uiblocked',
767 default=None,
770 default=None,
768 )
771 )
769 coreconfigitem('merge', 'checkunknown',
772 coreconfigitem('merge', 'checkunknown',
770 default='abort',
773 default='abort',
771 )
774 )
772 coreconfigitem('merge', 'checkignored',
775 coreconfigitem('merge', 'checkignored',
773 default='abort',
776 default='abort',
774 )
777 )
775 coreconfigitem('experimental', 'merge.checkpathconflicts',
778 coreconfigitem('experimental', 'merge.checkpathconflicts',
776 default=False,
779 default=False,
777 )
780 )
778 coreconfigitem('merge', 'followcopies',
781 coreconfigitem('merge', 'followcopies',
779 default=True,
782 default=True,
780 )
783 )
781 coreconfigitem('merge', 'on-failure',
784 coreconfigitem('merge', 'on-failure',
782 default='continue',
785 default='continue',
783 )
786 )
784 coreconfigitem('merge', 'preferancestor',
787 coreconfigitem('merge', 'preferancestor',
785 default=lambda: ['*'],
788 default=lambda: ['*'],
786 )
789 )
787 coreconfigitem('merge', 'strict-capability-check',
790 coreconfigitem('merge', 'strict-capability-check',
788 default=False,
791 default=False,
789 )
792 )
790 coreconfigitem('merge-tools', '.*',
793 coreconfigitem('merge-tools', '.*',
791 default=None,
794 default=None,
792 generic=True,
795 generic=True,
793 )
796 )
794 coreconfigitem('merge-tools', br'.*\.args$',
797 coreconfigitem('merge-tools', br'.*\.args$',
795 default="$local $base $other",
798 default="$local $base $other",
796 generic=True,
799 generic=True,
797 priority=-1,
800 priority=-1,
798 )
801 )
799 coreconfigitem('merge-tools', br'.*\.binary$',
802 coreconfigitem('merge-tools', br'.*\.binary$',
800 default=False,
803 default=False,
801 generic=True,
804 generic=True,
802 priority=-1,
805 priority=-1,
803 )
806 )
804 coreconfigitem('merge-tools', br'.*\.check$',
807 coreconfigitem('merge-tools', br'.*\.check$',
805 default=list,
808 default=list,
806 generic=True,
809 generic=True,
807 priority=-1,
810 priority=-1,
808 )
811 )
809 coreconfigitem('merge-tools', br'.*\.checkchanged$',
812 coreconfigitem('merge-tools', br'.*\.checkchanged$',
810 default=False,
813 default=False,
811 generic=True,
814 generic=True,
812 priority=-1,
815 priority=-1,
813 )
816 )
814 coreconfigitem('merge-tools', br'.*\.executable$',
817 coreconfigitem('merge-tools', br'.*\.executable$',
815 default=dynamicdefault,
818 default=dynamicdefault,
816 generic=True,
819 generic=True,
817 priority=-1,
820 priority=-1,
818 )
821 )
819 coreconfigitem('merge-tools', br'.*\.fixeol$',
822 coreconfigitem('merge-tools', br'.*\.fixeol$',
820 default=False,
823 default=False,
821 generic=True,
824 generic=True,
822 priority=-1,
825 priority=-1,
823 )
826 )
824 coreconfigitem('merge-tools', br'.*\.gui$',
827 coreconfigitem('merge-tools', br'.*\.gui$',
825 default=False,
828 default=False,
826 generic=True,
829 generic=True,
827 priority=-1,
830 priority=-1,
828 )
831 )
829 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
832 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
830 default='basic',
833 default='basic',
831 generic=True,
834 generic=True,
832 priority=-1,
835 priority=-1,
833 )
836 )
834 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
837 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
835 default=dynamicdefault, # take from ui.mergemarkertemplate
838 default=dynamicdefault, # take from ui.mergemarkertemplate
836 generic=True,
839 generic=True,
837 priority=-1,
840 priority=-1,
838 )
841 )
839 coreconfigitem('merge-tools', br'.*\.priority$',
842 coreconfigitem('merge-tools', br'.*\.priority$',
840 default=0,
843 default=0,
841 generic=True,
844 generic=True,
842 priority=-1,
845 priority=-1,
843 )
846 )
844 coreconfigitem('merge-tools', br'.*\.premerge$',
847 coreconfigitem('merge-tools', br'.*\.premerge$',
845 default=dynamicdefault,
848 default=dynamicdefault,
846 generic=True,
849 generic=True,
847 priority=-1,
850 priority=-1,
848 )
851 )
849 coreconfigitem('merge-tools', br'.*\.symlink$',
852 coreconfigitem('merge-tools', br'.*\.symlink$',
850 default=False,
853 default=False,
851 generic=True,
854 generic=True,
852 priority=-1,
855 priority=-1,
853 )
856 )
854 coreconfigitem('pager', 'attend-.*',
857 coreconfigitem('pager', 'attend-.*',
855 default=dynamicdefault,
858 default=dynamicdefault,
856 generic=True,
859 generic=True,
857 )
860 )
858 coreconfigitem('pager', 'ignore',
861 coreconfigitem('pager', 'ignore',
859 default=list,
862 default=list,
860 )
863 )
861 coreconfigitem('pager', 'pager',
864 coreconfigitem('pager', 'pager',
862 default=dynamicdefault,
865 default=dynamicdefault,
863 )
866 )
864 coreconfigitem('patch', 'eol',
867 coreconfigitem('patch', 'eol',
865 default='strict',
868 default='strict',
866 )
869 )
867 coreconfigitem('patch', 'fuzz',
870 coreconfigitem('patch', 'fuzz',
868 default=2,
871 default=2,
869 )
872 )
870 coreconfigitem('paths', 'default',
873 coreconfigitem('paths', 'default',
871 default=None,
874 default=None,
872 )
875 )
873 coreconfigitem('paths', 'default-push',
876 coreconfigitem('paths', 'default-push',
874 default=None,
877 default=None,
875 )
878 )
876 coreconfigitem('paths', '.*',
879 coreconfigitem('paths', '.*',
877 default=None,
880 default=None,
878 generic=True,
881 generic=True,
879 )
882 )
880 coreconfigitem('phases', 'checksubrepos',
883 coreconfigitem('phases', 'checksubrepos',
881 default='follow',
884 default='follow',
882 )
885 )
883 coreconfigitem('phases', 'new-commit',
886 coreconfigitem('phases', 'new-commit',
884 default='draft',
887 default='draft',
885 )
888 )
886 coreconfigitem('phases', 'publish',
889 coreconfigitem('phases', 'publish',
887 default=True,
890 default=True,
888 )
891 )
889 coreconfigitem('profiling', 'enabled',
892 coreconfigitem('profiling', 'enabled',
890 default=False,
893 default=False,
891 )
894 )
892 coreconfigitem('profiling', 'format',
895 coreconfigitem('profiling', 'format',
893 default='text',
896 default='text',
894 )
897 )
895 coreconfigitem('profiling', 'freq',
898 coreconfigitem('profiling', 'freq',
896 default=1000,
899 default=1000,
897 )
900 )
898 coreconfigitem('profiling', 'limit',
901 coreconfigitem('profiling', 'limit',
899 default=30,
902 default=30,
900 )
903 )
901 coreconfigitem('profiling', 'nested',
904 coreconfigitem('profiling', 'nested',
902 default=0,
905 default=0,
903 )
906 )
904 coreconfigitem('profiling', 'output',
907 coreconfigitem('profiling', 'output',
905 default=None,
908 default=None,
906 )
909 )
907 coreconfigitem('profiling', 'showmax',
910 coreconfigitem('profiling', 'showmax',
908 default=0.999,
911 default=0.999,
909 )
912 )
910 coreconfigitem('profiling', 'showmin',
913 coreconfigitem('profiling', 'showmin',
911 default=dynamicdefault,
914 default=dynamicdefault,
912 )
915 )
913 coreconfigitem('profiling', 'sort',
916 coreconfigitem('profiling', 'sort',
914 default='inlinetime',
917 default='inlinetime',
915 )
918 )
916 coreconfigitem('profiling', 'statformat',
919 coreconfigitem('profiling', 'statformat',
917 default='hotpath',
920 default='hotpath',
918 )
921 )
919 coreconfigitem('profiling', 'time-track',
922 coreconfigitem('profiling', 'time-track',
920 default='cpu',
923 default='cpu',
921 )
924 )
922 coreconfigitem('profiling', 'type',
925 coreconfigitem('profiling', 'type',
923 default='stat',
926 default='stat',
924 )
927 )
925 coreconfigitem('progress', 'assume-tty',
928 coreconfigitem('progress', 'assume-tty',
926 default=False,
929 default=False,
927 )
930 )
928 coreconfigitem('progress', 'changedelay',
931 coreconfigitem('progress', 'changedelay',
929 default=1,
932 default=1,
930 )
933 )
931 coreconfigitem('progress', 'clear-complete',
934 coreconfigitem('progress', 'clear-complete',
932 default=True,
935 default=True,
933 )
936 )
934 coreconfigitem('progress', 'debug',
937 coreconfigitem('progress', 'debug',
935 default=False,
938 default=False,
936 )
939 )
937 coreconfigitem('progress', 'delay',
940 coreconfigitem('progress', 'delay',
938 default=3,
941 default=3,
939 )
942 )
940 coreconfigitem('progress', 'disable',
943 coreconfigitem('progress', 'disable',
941 default=False,
944 default=False,
942 )
945 )
943 coreconfigitem('progress', 'estimateinterval',
946 coreconfigitem('progress', 'estimateinterval',
944 default=60.0,
947 default=60.0,
945 )
948 )
946 coreconfigitem('progress', 'format',
949 coreconfigitem('progress', 'format',
947 default=lambda: ['topic', 'bar', 'number', 'estimate'],
950 default=lambda: ['topic', 'bar', 'number', 'estimate'],
948 )
951 )
949 coreconfigitem('progress', 'refresh',
952 coreconfigitem('progress', 'refresh',
950 default=0.1,
953 default=0.1,
951 )
954 )
952 coreconfigitem('progress', 'width',
955 coreconfigitem('progress', 'width',
953 default=dynamicdefault,
956 default=dynamicdefault,
954 )
957 )
955 coreconfigitem('push', 'pushvars.server',
958 coreconfigitem('push', 'pushvars.server',
956 default=False,
959 default=False,
957 )
960 )
958 coreconfigitem('storage', 'new-repo-backend',
961 coreconfigitem('storage', 'new-repo-backend',
959 default='revlogv1',
962 default='revlogv1',
960 )
963 )
961 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
964 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
962 default=True,
965 default=True,
963 alias=[('format', 'aggressivemergedeltas')],
966 alias=[('format', 'aggressivemergedeltas')],
964 )
967 )
965 coreconfigitem('server', 'bookmarks-pushkey-compat',
968 coreconfigitem('server', 'bookmarks-pushkey-compat',
966 default=True,
969 default=True,
967 )
970 )
968 coreconfigitem('server', 'bundle1',
971 coreconfigitem('server', 'bundle1',
969 default=True,
972 default=True,
970 )
973 )
971 coreconfigitem('server', 'bundle1gd',
974 coreconfigitem('server', 'bundle1gd',
972 default=None,
975 default=None,
973 )
976 )
974 coreconfigitem('server', 'bundle1.pull',
977 coreconfigitem('server', 'bundle1.pull',
975 default=None,
978 default=None,
976 )
979 )
977 coreconfigitem('server', 'bundle1gd.pull',
980 coreconfigitem('server', 'bundle1gd.pull',
978 default=None,
981 default=None,
979 )
982 )
980 coreconfigitem('server', 'bundle1.push',
983 coreconfigitem('server', 'bundle1.push',
981 default=None,
984 default=None,
982 )
985 )
983 coreconfigitem('server', 'bundle1gd.push',
986 coreconfigitem('server', 'bundle1gd.push',
984 default=None,
987 default=None,
985 )
988 )
986 coreconfigitem('server', 'bundle2.stream',
989 coreconfigitem('server', 'bundle2.stream',
987 default=True,
990 default=True,
988 alias=[('experimental', 'bundle2.stream')]
991 alias=[('experimental', 'bundle2.stream')]
989 )
992 )
990 coreconfigitem('server', 'compressionengines',
993 coreconfigitem('server', 'compressionengines',
991 default=list,
994 default=list,
992 )
995 )
993 coreconfigitem('server', 'concurrent-push-mode',
996 coreconfigitem('server', 'concurrent-push-mode',
994 default='strict',
997 default='strict',
995 )
998 )
996 coreconfigitem('server', 'disablefullbundle',
999 coreconfigitem('server', 'disablefullbundle',
997 default=False,
1000 default=False,
998 )
1001 )
999 coreconfigitem('server', 'maxhttpheaderlen',
1002 coreconfigitem('server', 'maxhttpheaderlen',
1000 default=1024,
1003 default=1024,
1001 )
1004 )
1002 coreconfigitem('server', 'pullbundle',
1005 coreconfigitem('server', 'pullbundle',
1003 default=False,
1006 default=False,
1004 )
1007 )
1005 coreconfigitem('server', 'preferuncompressed',
1008 coreconfigitem('server', 'preferuncompressed',
1006 default=False,
1009 default=False,
1007 )
1010 )
1008 coreconfigitem('server', 'streamunbundle',
1011 coreconfigitem('server', 'streamunbundle',
1009 default=False,
1012 default=False,
1010 )
1013 )
1011 coreconfigitem('server', 'uncompressed',
1014 coreconfigitem('server', 'uncompressed',
1012 default=True,
1015 default=True,
1013 )
1016 )
1014 coreconfigitem('server', 'uncompressedallowsecret',
1017 coreconfigitem('server', 'uncompressedallowsecret',
1015 default=False,
1018 default=False,
1016 )
1019 )
1017 coreconfigitem('server', 'validate',
1020 coreconfigitem('server', 'validate',
1018 default=False,
1021 default=False,
1019 )
1022 )
1020 coreconfigitem('server', 'zliblevel',
1023 coreconfigitem('server', 'zliblevel',
1021 default=-1,
1024 default=-1,
1022 )
1025 )
1023 coreconfigitem('server', 'zstdlevel',
1026 coreconfigitem('server', 'zstdlevel',
1024 default=3,
1027 default=3,
1025 )
1028 )
1026 coreconfigitem('share', 'pool',
1029 coreconfigitem('share', 'pool',
1027 default=None,
1030 default=None,
1028 )
1031 )
1029 coreconfigitem('share', 'poolnaming',
1032 coreconfigitem('share', 'poolnaming',
1030 default='identity',
1033 default='identity',
1031 )
1034 )
1032 coreconfigitem('smtp', 'host',
1035 coreconfigitem('smtp', 'host',
1033 default=None,
1036 default=None,
1034 )
1037 )
1035 coreconfigitem('smtp', 'local_hostname',
1038 coreconfigitem('smtp', 'local_hostname',
1036 default=None,
1039 default=None,
1037 )
1040 )
1038 coreconfigitem('smtp', 'password',
1041 coreconfigitem('smtp', 'password',
1039 default=None,
1042 default=None,
1040 )
1043 )
1041 coreconfigitem('smtp', 'port',
1044 coreconfigitem('smtp', 'port',
1042 default=dynamicdefault,
1045 default=dynamicdefault,
1043 )
1046 )
1044 coreconfigitem('smtp', 'tls',
1047 coreconfigitem('smtp', 'tls',
1045 default='none',
1048 default='none',
1046 )
1049 )
1047 coreconfigitem('smtp', 'username',
1050 coreconfigitem('smtp', 'username',
1048 default=None,
1051 default=None,
1049 )
1052 )
1050 coreconfigitem('sparse', 'missingwarning',
1053 coreconfigitem('sparse', 'missingwarning',
1051 default=True,
1054 default=True,
1052 )
1055 )
1053 coreconfigitem('subrepos', 'allowed',
1056 coreconfigitem('subrepos', 'allowed',
1054 default=dynamicdefault, # to make backporting simpler
1057 default=dynamicdefault, # to make backporting simpler
1055 )
1058 )
1056 coreconfigitem('subrepos', 'hg:allowed',
1059 coreconfigitem('subrepos', 'hg:allowed',
1057 default=dynamicdefault,
1060 default=dynamicdefault,
1058 )
1061 )
1059 coreconfigitem('subrepos', 'git:allowed',
1062 coreconfigitem('subrepos', 'git:allowed',
1060 default=dynamicdefault,
1063 default=dynamicdefault,
1061 )
1064 )
1062 coreconfigitem('subrepos', 'svn:allowed',
1065 coreconfigitem('subrepos', 'svn:allowed',
1063 default=dynamicdefault,
1066 default=dynamicdefault,
1064 )
1067 )
1065 coreconfigitem('templates', '.*',
1068 coreconfigitem('templates', '.*',
1066 default=None,
1069 default=None,
1067 generic=True,
1070 generic=True,
1068 )
1071 )
1069 coreconfigitem('trusted', 'groups',
1072 coreconfigitem('trusted', 'groups',
1070 default=list,
1073 default=list,
1071 )
1074 )
1072 coreconfigitem('trusted', 'users',
1075 coreconfigitem('trusted', 'users',
1073 default=list,
1076 default=list,
1074 )
1077 )
1075 coreconfigitem('ui', '_usedassubrepo',
1078 coreconfigitem('ui', '_usedassubrepo',
1076 default=False,
1079 default=False,
1077 )
1080 )
1078 coreconfigitem('ui', 'allowemptycommit',
1081 coreconfigitem('ui', 'allowemptycommit',
1079 default=False,
1082 default=False,
1080 )
1083 )
1081 coreconfigitem('ui', 'archivemeta',
1084 coreconfigitem('ui', 'archivemeta',
1082 default=True,
1085 default=True,
1083 )
1086 )
1084 coreconfigitem('ui', 'askusername',
1087 coreconfigitem('ui', 'askusername',
1085 default=False,
1088 default=False,
1086 )
1089 )
1087 coreconfigitem('ui', 'clonebundlefallback',
1090 coreconfigitem('ui', 'clonebundlefallback',
1088 default=False,
1091 default=False,
1089 )
1092 )
1090 coreconfigitem('ui', 'clonebundleprefers',
1093 coreconfigitem('ui', 'clonebundleprefers',
1091 default=list,
1094 default=list,
1092 )
1095 )
1093 coreconfigitem('ui', 'clonebundles',
1096 coreconfigitem('ui', 'clonebundles',
1094 default=True,
1097 default=True,
1095 )
1098 )
1096 coreconfigitem('ui', 'color',
1099 coreconfigitem('ui', 'color',
1097 default='auto',
1100 default='auto',
1098 )
1101 )
1099 coreconfigitem('ui', 'commitsubrepos',
1102 coreconfigitem('ui', 'commitsubrepos',
1100 default=False,
1103 default=False,
1101 )
1104 )
1102 coreconfigitem('ui', 'debug',
1105 coreconfigitem('ui', 'debug',
1103 default=False,
1106 default=False,
1104 )
1107 )
1105 coreconfigitem('ui', 'debugger',
1108 coreconfigitem('ui', 'debugger',
1106 default=None,
1109 default=None,
1107 )
1110 )
1108 coreconfigitem('ui', 'editor',
1111 coreconfigitem('ui', 'editor',
1109 default=dynamicdefault,
1112 default=dynamicdefault,
1110 )
1113 )
1111 coreconfigitem('ui', 'fallbackencoding',
1114 coreconfigitem('ui', 'fallbackencoding',
1112 default=None,
1115 default=None,
1113 )
1116 )
1114 coreconfigitem('ui', 'forcecwd',
1117 coreconfigitem('ui', 'forcecwd',
1115 default=None,
1118 default=None,
1116 )
1119 )
1117 coreconfigitem('ui', 'forcemerge',
1120 coreconfigitem('ui', 'forcemerge',
1118 default=None,
1121 default=None,
1119 )
1122 )
1120 coreconfigitem('ui', 'formatdebug',
1123 coreconfigitem('ui', 'formatdebug',
1121 default=False,
1124 default=False,
1122 )
1125 )
1123 coreconfigitem('ui', 'formatjson',
1126 coreconfigitem('ui', 'formatjson',
1124 default=False,
1127 default=False,
1125 )
1128 )
1126 coreconfigitem('ui', 'formatted',
1129 coreconfigitem('ui', 'formatted',
1127 default=None,
1130 default=None,
1128 )
1131 )
1129 coreconfigitem('ui', 'graphnodetemplate',
1132 coreconfigitem('ui', 'graphnodetemplate',
1130 default=None,
1133 default=None,
1131 )
1134 )
1132 coreconfigitem('ui', 'history-editing-backup',
1135 coreconfigitem('ui', 'history-editing-backup',
1133 default=True,
1136 default=True,
1134 )
1137 )
1135 coreconfigitem('ui', 'interactive',
1138 coreconfigitem('ui', 'interactive',
1136 default=None,
1139 default=None,
1137 )
1140 )
1138 coreconfigitem('ui', 'interface',
1141 coreconfigitem('ui', 'interface',
1139 default=None,
1142 default=None,
1140 )
1143 )
1141 coreconfigitem('ui', 'interface.chunkselector',
1144 coreconfigitem('ui', 'interface.chunkselector',
1142 default=None,
1145 default=None,
1143 )
1146 )
1144 coreconfigitem('ui', 'large-file-limit',
1147 coreconfigitem('ui', 'large-file-limit',
1145 default=10000000,
1148 default=10000000,
1146 )
1149 )
1147 coreconfigitem('ui', 'logblockedtimes',
1150 coreconfigitem('ui', 'logblockedtimes',
1148 default=False,
1151 default=False,
1149 )
1152 )
1150 coreconfigitem('ui', 'logtemplate',
1153 coreconfigitem('ui', 'logtemplate',
1151 default=None,
1154 default=None,
1152 )
1155 )
1153 coreconfigitem('ui', 'merge',
1156 coreconfigitem('ui', 'merge',
1154 default=None,
1157 default=None,
1155 )
1158 )
1156 coreconfigitem('ui', 'mergemarkers',
1159 coreconfigitem('ui', 'mergemarkers',
1157 default='basic',
1160 default='basic',
1158 )
1161 )
1159 coreconfigitem('ui', 'mergemarkertemplate',
1162 coreconfigitem('ui', 'mergemarkertemplate',
1160 default=('{node|short} '
1163 default=('{node|short} '
1161 '{ifeq(tags, "tip", "", '
1164 '{ifeq(tags, "tip", "", '
1162 'ifeq(tags, "", "", "{tags} "))}'
1165 'ifeq(tags, "", "", "{tags} "))}'
1163 '{if(bookmarks, "{bookmarks} ")}'
1166 '{if(bookmarks, "{bookmarks} ")}'
1164 '{ifeq(branch, "default", "", "{branch} ")}'
1167 '{ifeq(branch, "default", "", "{branch} ")}'
1165 '- {author|user}: {desc|firstline}')
1168 '- {author|user}: {desc|firstline}')
1166 )
1169 )
1167 coreconfigitem('ui', 'nontty',
1170 coreconfigitem('ui', 'nontty',
1168 default=False,
1171 default=False,
1169 )
1172 )
1170 coreconfigitem('ui', 'origbackuppath',
1173 coreconfigitem('ui', 'origbackuppath',
1171 default=None,
1174 default=None,
1172 )
1175 )
1173 coreconfigitem('ui', 'paginate',
1176 coreconfigitem('ui', 'paginate',
1174 default=True,
1177 default=True,
1175 )
1178 )
1176 coreconfigitem('ui', 'patch',
1179 coreconfigitem('ui', 'patch',
1177 default=None,
1180 default=None,
1178 )
1181 )
1179 coreconfigitem('ui', 'portablefilenames',
1182 coreconfigitem('ui', 'portablefilenames',
1180 default='warn',
1183 default='warn',
1181 )
1184 )
1182 coreconfigitem('ui', 'promptecho',
1185 coreconfigitem('ui', 'promptecho',
1183 default=False,
1186 default=False,
1184 )
1187 )
1185 coreconfigitem('ui', 'quiet',
1188 coreconfigitem('ui', 'quiet',
1186 default=False,
1189 default=False,
1187 )
1190 )
1188 coreconfigitem('ui', 'quietbookmarkmove',
1191 coreconfigitem('ui', 'quietbookmarkmove',
1189 default=False,
1192 default=False,
1190 )
1193 )
1191 coreconfigitem('ui', 'remotecmd',
1194 coreconfigitem('ui', 'remotecmd',
1192 default='hg',
1195 default='hg',
1193 )
1196 )
1194 coreconfigitem('ui', 'report_untrusted',
1197 coreconfigitem('ui', 'report_untrusted',
1195 default=True,
1198 default=True,
1196 )
1199 )
1197 coreconfigitem('ui', 'rollback',
1200 coreconfigitem('ui', 'rollback',
1198 default=True,
1201 default=True,
1199 )
1202 )
1200 coreconfigitem('ui', 'signal-safe-lock',
1203 coreconfigitem('ui', 'signal-safe-lock',
1201 default=True,
1204 default=True,
1202 )
1205 )
1203 coreconfigitem('ui', 'slash',
1206 coreconfigitem('ui', 'slash',
1204 default=False,
1207 default=False,
1205 )
1208 )
1206 coreconfigitem('ui', 'ssh',
1209 coreconfigitem('ui', 'ssh',
1207 default='ssh',
1210 default='ssh',
1208 )
1211 )
1209 coreconfigitem('ui', 'ssherrorhint',
1212 coreconfigitem('ui', 'ssherrorhint',
1210 default=None,
1213 default=None,
1211 )
1214 )
1212 coreconfigitem('ui', 'statuscopies',
1215 coreconfigitem('ui', 'statuscopies',
1213 default=False,
1216 default=False,
1214 )
1217 )
1215 coreconfigitem('ui', 'strict',
1218 coreconfigitem('ui', 'strict',
1216 default=False,
1219 default=False,
1217 )
1220 )
1218 coreconfigitem('ui', 'style',
1221 coreconfigitem('ui', 'style',
1219 default='',
1222 default='',
1220 )
1223 )
1221 coreconfigitem('ui', 'supportcontact',
1224 coreconfigitem('ui', 'supportcontact',
1222 default=None,
1225 default=None,
1223 )
1226 )
1224 coreconfigitem('ui', 'textwidth',
1227 coreconfigitem('ui', 'textwidth',
1225 default=78,
1228 default=78,
1226 )
1229 )
1227 coreconfigitem('ui', 'timeout',
1230 coreconfigitem('ui', 'timeout',
1228 default='600',
1231 default='600',
1229 )
1232 )
1230 coreconfigitem('ui', 'timeout.warn',
1233 coreconfigitem('ui', 'timeout.warn',
1231 default=0,
1234 default=0,
1232 )
1235 )
1233 coreconfigitem('ui', 'traceback',
1236 coreconfigitem('ui', 'traceback',
1234 default=False,
1237 default=False,
1235 )
1238 )
1236 coreconfigitem('ui', 'tweakdefaults',
1239 coreconfigitem('ui', 'tweakdefaults',
1237 default=False,
1240 default=False,
1238 )
1241 )
1239 coreconfigitem('ui', 'username',
1242 coreconfigitem('ui', 'username',
1240 alias=[('ui', 'user')]
1243 alias=[('ui', 'user')]
1241 )
1244 )
1242 coreconfigitem('ui', 'verbose',
1245 coreconfigitem('ui', 'verbose',
1243 default=False,
1246 default=False,
1244 )
1247 )
1245 coreconfigitem('verify', 'skipflags',
1248 coreconfigitem('verify', 'skipflags',
1246 default=None,
1249 default=None,
1247 )
1250 )
1248 coreconfigitem('web', 'allowbz2',
1251 coreconfigitem('web', 'allowbz2',
1249 default=False,
1252 default=False,
1250 )
1253 )
1251 coreconfigitem('web', 'allowgz',
1254 coreconfigitem('web', 'allowgz',
1252 default=False,
1255 default=False,
1253 )
1256 )
1254 coreconfigitem('web', 'allow-pull',
1257 coreconfigitem('web', 'allow-pull',
1255 alias=[('web', 'allowpull')],
1258 alias=[('web', 'allowpull')],
1256 default=True,
1259 default=True,
1257 )
1260 )
1258 coreconfigitem('web', 'allow-push',
1261 coreconfigitem('web', 'allow-push',
1259 alias=[('web', 'allow_push')],
1262 alias=[('web', 'allow_push')],
1260 default=list,
1263 default=list,
1261 )
1264 )
1262 coreconfigitem('web', 'allowzip',
1265 coreconfigitem('web', 'allowzip',
1263 default=False,
1266 default=False,
1264 )
1267 )
1265 coreconfigitem('web', 'archivesubrepos',
1268 coreconfigitem('web', 'archivesubrepos',
1266 default=False,
1269 default=False,
1267 )
1270 )
1268 coreconfigitem('web', 'cache',
1271 coreconfigitem('web', 'cache',
1269 default=True,
1272 default=True,
1270 )
1273 )
1271 coreconfigitem('web', 'contact',
1274 coreconfigitem('web', 'contact',
1272 default=None,
1275 default=None,
1273 )
1276 )
1274 coreconfigitem('web', 'deny_push',
1277 coreconfigitem('web', 'deny_push',
1275 default=list,
1278 default=list,
1276 )
1279 )
1277 coreconfigitem('web', 'guessmime',
1280 coreconfigitem('web', 'guessmime',
1278 default=False,
1281 default=False,
1279 )
1282 )
1280 coreconfigitem('web', 'hidden',
1283 coreconfigitem('web', 'hidden',
1281 default=False,
1284 default=False,
1282 )
1285 )
1283 coreconfigitem('web', 'labels',
1286 coreconfigitem('web', 'labels',
1284 default=list,
1287 default=list,
1285 )
1288 )
1286 coreconfigitem('web', 'logoimg',
1289 coreconfigitem('web', 'logoimg',
1287 default='hglogo.png',
1290 default='hglogo.png',
1288 )
1291 )
1289 coreconfigitem('web', 'logourl',
1292 coreconfigitem('web', 'logourl',
1290 default='https://mercurial-scm.org/',
1293 default='https://mercurial-scm.org/',
1291 )
1294 )
1292 coreconfigitem('web', 'accesslog',
1295 coreconfigitem('web', 'accesslog',
1293 default='-',
1296 default='-',
1294 )
1297 )
1295 coreconfigitem('web', 'address',
1298 coreconfigitem('web', 'address',
1296 default='',
1299 default='',
1297 )
1300 )
1298 coreconfigitem('web', 'allow-archive',
1301 coreconfigitem('web', 'allow-archive',
1299 alias=[('web', 'allow_archive')],
1302 alias=[('web', 'allow_archive')],
1300 default=list,
1303 default=list,
1301 )
1304 )
1302 coreconfigitem('web', 'allow_read',
1305 coreconfigitem('web', 'allow_read',
1303 default=list,
1306 default=list,
1304 )
1307 )
1305 coreconfigitem('web', 'baseurl',
1308 coreconfigitem('web', 'baseurl',
1306 default=None,
1309 default=None,
1307 )
1310 )
1308 coreconfigitem('web', 'cacerts',
1311 coreconfigitem('web', 'cacerts',
1309 default=None,
1312 default=None,
1310 )
1313 )
1311 coreconfigitem('web', 'certificate',
1314 coreconfigitem('web', 'certificate',
1312 default=None,
1315 default=None,
1313 )
1316 )
1314 coreconfigitem('web', 'collapse',
1317 coreconfigitem('web', 'collapse',
1315 default=False,
1318 default=False,
1316 )
1319 )
1317 coreconfigitem('web', 'csp',
1320 coreconfigitem('web', 'csp',
1318 default=None,
1321 default=None,
1319 )
1322 )
1320 coreconfigitem('web', 'deny_read',
1323 coreconfigitem('web', 'deny_read',
1321 default=list,
1324 default=list,
1322 )
1325 )
1323 coreconfigitem('web', 'descend',
1326 coreconfigitem('web', 'descend',
1324 default=True,
1327 default=True,
1325 )
1328 )
1326 coreconfigitem('web', 'description',
1329 coreconfigitem('web', 'description',
1327 default="",
1330 default="",
1328 )
1331 )
1329 coreconfigitem('web', 'encoding',
1332 coreconfigitem('web', 'encoding',
1330 default=lambda: encoding.encoding,
1333 default=lambda: encoding.encoding,
1331 )
1334 )
1332 coreconfigitem('web', 'errorlog',
1335 coreconfigitem('web', 'errorlog',
1333 default='-',
1336 default='-',
1334 )
1337 )
1335 coreconfigitem('web', 'ipv6',
1338 coreconfigitem('web', 'ipv6',
1336 default=False,
1339 default=False,
1337 )
1340 )
1338 coreconfigitem('web', 'maxchanges',
1341 coreconfigitem('web', 'maxchanges',
1339 default=10,
1342 default=10,
1340 )
1343 )
1341 coreconfigitem('web', 'maxfiles',
1344 coreconfigitem('web', 'maxfiles',
1342 default=10,
1345 default=10,
1343 )
1346 )
1344 coreconfigitem('web', 'maxshortchanges',
1347 coreconfigitem('web', 'maxshortchanges',
1345 default=60,
1348 default=60,
1346 )
1349 )
1347 coreconfigitem('web', 'motd',
1350 coreconfigitem('web', 'motd',
1348 default='',
1351 default='',
1349 )
1352 )
1350 coreconfigitem('web', 'name',
1353 coreconfigitem('web', 'name',
1351 default=dynamicdefault,
1354 default=dynamicdefault,
1352 )
1355 )
1353 coreconfigitem('web', 'port',
1356 coreconfigitem('web', 'port',
1354 default=8000,
1357 default=8000,
1355 )
1358 )
1356 coreconfigitem('web', 'prefix',
1359 coreconfigitem('web', 'prefix',
1357 default='',
1360 default='',
1358 )
1361 )
1359 coreconfigitem('web', 'push_ssl',
1362 coreconfigitem('web', 'push_ssl',
1360 default=True,
1363 default=True,
1361 )
1364 )
1362 coreconfigitem('web', 'refreshinterval',
1365 coreconfigitem('web', 'refreshinterval',
1363 default=20,
1366 default=20,
1364 )
1367 )
1365 coreconfigitem('web', 'server-header',
1368 coreconfigitem('web', 'server-header',
1366 default=None,
1369 default=None,
1367 )
1370 )
1368 coreconfigitem('web', 'static',
1371 coreconfigitem('web', 'static',
1369 default=None,
1372 default=None,
1370 )
1373 )
1371 coreconfigitem('web', 'staticurl',
1374 coreconfigitem('web', 'staticurl',
1372 default=None,
1375 default=None,
1373 )
1376 )
1374 coreconfigitem('web', 'stripes',
1377 coreconfigitem('web', 'stripes',
1375 default=1,
1378 default=1,
1376 )
1379 )
1377 coreconfigitem('web', 'style',
1380 coreconfigitem('web', 'style',
1378 default='paper',
1381 default='paper',
1379 )
1382 )
1380 coreconfigitem('web', 'templates',
1383 coreconfigitem('web', 'templates',
1381 default=None,
1384 default=None,
1382 )
1385 )
1383 coreconfigitem('web', 'view',
1386 coreconfigitem('web', 'view',
1384 default='served',
1387 default='served',
1385 )
1388 )
1386 coreconfigitem('worker', 'backgroundclose',
1389 coreconfigitem('worker', 'backgroundclose',
1387 default=dynamicdefault,
1390 default=dynamicdefault,
1388 )
1391 )
1389 # Windows defaults to a limit of 512 open files. A buffer of 128
1392 # Windows defaults to a limit of 512 open files. A buffer of 128
1390 # should give us enough headway.
1393 # should give us enough headway.
1391 coreconfigitem('worker', 'backgroundclosemaxqueue',
1394 coreconfigitem('worker', 'backgroundclosemaxqueue',
1392 default=384,
1395 default=384,
1393 )
1396 )
1394 coreconfigitem('worker', 'backgroundcloseminfilecount',
1397 coreconfigitem('worker', 'backgroundcloseminfilecount',
1395 default=2048,
1398 default=2048,
1396 )
1399 )
1397 coreconfigitem('worker', 'backgroundclosethreadcount',
1400 coreconfigitem('worker', 'backgroundclosethreadcount',
1398 default=4,
1401 default=4,
1399 )
1402 )
1400 coreconfigitem('worker', 'enabled',
1403 coreconfigitem('worker', 'enabled',
1401 default=True,
1404 default=True,
1402 )
1405 )
1403 coreconfigitem('worker', 'numcpus',
1406 coreconfigitem('worker', 'numcpus',
1404 default=None,
1407 default=None,
1405 )
1408 )
1406
1409
1407 # Rebase related configuration moved to core because other extension are doing
1410 # Rebase related configuration moved to core because other extension are doing
1408 # strange things. For example, shelve import the extensions to reuse some bit
1411 # strange things. For example, shelve import the extensions to reuse some bit
1409 # without formally loading it.
1412 # without formally loading it.
1410 coreconfigitem('commands', 'rebase.requiredest',
1413 coreconfigitem('commands', 'rebase.requiredest',
1411 default=False,
1414 default=False,
1412 )
1415 )
1413 coreconfigitem('experimental', 'rebaseskipobsolete',
1416 coreconfigitem('experimental', 'rebaseskipobsolete',
1414 default=True,
1417 default=True,
1415 )
1418 )
1416 coreconfigitem('rebase', 'singletransaction',
1419 coreconfigitem('rebase', 'singletransaction',
1417 default=False,
1420 default=False,
1418 )
1421 )
1419 coreconfigitem('rebase', 'experimental.inmemory',
1422 coreconfigitem('rebase', 'experimental.inmemory',
1420 default=False,
1423 default=False,
1421 )
1424 )
@@ -1,529 +1,542 b''
1 **Experimental and under active development**
1 **Experimental and under active development**
2
2
3 This section documents the wire protocol commands exposed to transports
3 This section documents the wire protocol commands exposed to transports
4 using the frame-based protocol. The set of commands exposed through
4 using the frame-based protocol. The set of commands exposed through
5 these transports is distinct from the set of commands exposed to legacy
5 these transports is distinct from the set of commands exposed to legacy
6 transports.
6 transports.
7
7
8 The frame-based protocol uses CBOR to encode command execution requests.
8 The frame-based protocol uses CBOR to encode command execution requests.
9 All command arguments must be mapped to a specific or set of CBOR data
9 All command arguments must be mapped to a specific or set of CBOR data
10 types.
10 types.
11
11
12 The response to many commands is also CBOR. There is no common response
12 The response to many commands is also CBOR. There is no common response
13 format: each command defines its own response format.
13 format: each command defines its own response format.
14
14
15 TODOs
15 TODOs
16 =====
16 =====
17
17
18 * Add "node namespace" support to each command. In order to support
18 * Add "node namespace" support to each command. In order to support
19 SHA-1 hash transition, we want servers to be able to expose different
19 SHA-1 hash transition, we want servers to be able to expose different
20 "node namespaces" for the same data. Every command operating on nodes
20 "node namespaces" for the same data. Every command operating on nodes
21 should specify which "node namespace" it is operating on and responses
21 should specify which "node namespace" it is operating on and responses
22 should encode the "node namespace" accordingly.
22 should encode the "node namespace" accordingly.
23
23
24 Commands
24 Commands
25 ========
25 ========
26
26
27 The sections below detail all commands available to wire protocol version
27 The sections below detail all commands available to wire protocol version
28 2.
28 2.
29
29
30 branchmap
30 branchmap
31 ---------
31 ---------
32
32
33 Obtain heads in named branches.
33 Obtain heads in named branches.
34
34
35 Receives no arguments.
35 Receives no arguments.
36
36
37 The response is a map with bytestring keys defining the branch name.
37 The response is a map with bytestring keys defining the branch name.
38 Values are arrays of bytestring defining raw changeset nodes.
38 Values are arrays of bytestring defining raw changeset nodes.
39
39
40 capabilities
40 capabilities
41 ------------
41 ------------
42
42
43 Obtain the server's capabilities.
43 Obtain the server's capabilities.
44
44
45 Receives no arguments.
45 Receives no arguments.
46
46
47 This command is typically called only as part of the handshake during
47 This command is typically called only as part of the handshake during
48 initial connection establishment.
48 initial connection establishment.
49
49
50 The response is a map with bytestring keys defining server information.
50 The response is a map with bytestring keys defining server information.
51
51
52 The defined keys are:
52 The defined keys are:
53
53
54 commands
54 commands
55 A map defining available wire protocol commands on this server.
55 A map defining available wire protocol commands on this server.
56
56
57 Keys in the map are the names of commands that can be invoked. Values
57 Keys in the map are the names of commands that can be invoked. Values
58 are maps defining information about that command. The bytestring keys
58 are maps defining information about that command. The bytestring keys
59 are:
59 are:
60
60
61 args
61 args
62 (map) Describes arguments accepted by the command.
62 (map) Describes arguments accepted by the command.
63
63
64 Keys are bytestrings denoting the argument name.
64 Keys are bytestrings denoting the argument name.
65
65
66 Values are maps describing the argument. The map has the following
66 Values are maps describing the argument. The map has the following
67 bytestring keys:
67 bytestring keys:
68
68
69 default
69 default
70 (varied) The default value for this argument if not specified. Only
70 (varied) The default value for this argument if not specified. Only
71 present if ``required`` is not true.
71 present if ``required`` is not true.
72
72
73 required
73 required
74 (boolean) Whether the argument must be specified. Failure to send
74 (boolean) Whether the argument must be specified. Failure to send
75 required arguments will result in an error executing the command.
75 required arguments will result in an error executing the command.
76
76
77 type
77 type
78 (bytestring) The type of the argument. e.g. ``bytes`` or ``bool``.
78 (bytestring) The type of the argument. e.g. ``bytes`` or ``bool``.
79
79
80 validvalues
80 validvalues
81 (set) Values that are recognized for this argument. Some arguments
81 (set) Values that are recognized for this argument. Some arguments
82 only allow a fixed set of values to be specified. These arguments
82 only allow a fixed set of values to be specified. These arguments
83 may advertise that set in this key. If this set is advertised and
83 may advertise that set in this key. If this set is advertised and
84 a value not in this set is specified, the command should result
84 a value not in this set is specified, the command should result
85 in error.
85 in error.
86
86
87 permissions
87 permissions
88 An array of permissions required to execute this command.
88 An array of permissions required to execute this command.
89
89
90 *
91 (various) Individual commands may define extra keys that supplement
92 generic command metadata. See the command definition for more.
93
90 framingmediatypes
94 framingmediatypes
91 An array of bytestrings defining the supported framing protocol
95 An array of bytestrings defining the supported framing protocol
92 media types. Servers will not accept media types not in this list.
96 media types. Servers will not accept media types not in this list.
93
97
94 pathfilterprefixes
98 pathfilterprefixes
95 (set of bytestring) Matcher prefixes that are recognized when performing
99 (set of bytestring) Matcher prefixes that are recognized when performing
96 path filtering. Specifying a path filter whose type/prefix does not
100 path filtering. Specifying a path filter whose type/prefix does not
97 match one in this set will likely be rejected by the server.
101 match one in this set will likely be rejected by the server.
98
102
99 rawrepoformats
103 rawrepoformats
100 An array of storage formats the repository is using. This set of
104 An array of storage formats the repository is using. This set of
101 requirements can be used to determine whether a client can read a
105 requirements can be used to determine whether a client can read a
102 *raw* copy of file data available.
106 *raw* copy of file data available.
103
107
104 redirect
108 redirect
105 A map declaring potential *content redirects* that may be used by this
109 A map declaring potential *content redirects* that may be used by this
106 server. Contains the following bytestring keys:
110 server. Contains the following bytestring keys:
107
111
108 targets
112 targets
109 (array of maps) Potential redirect targets. Values are maps describing
113 (array of maps) Potential redirect targets. Values are maps describing
110 this target in more detail. Each map has the following bytestring keys:
114 this target in more detail. Each map has the following bytestring keys:
111
115
112 name
116 name
113 (bytestring) Identifier for this target. The identifier will be used
117 (bytestring) Identifier for this target. The identifier will be used
114 by clients to uniquely identify this target.
118 by clients to uniquely identify this target.
115
119
116 protocol
120 protocol
117 (bytestring) High-level network protocol. Values can be
121 (bytestring) High-level network protocol. Values can be
118 ``http``, ```https``, ``ssh``, etc.
122 ``http``, ```https``, ``ssh``, etc.
119
123
120 uris
124 uris
121 (array of bytestrings) Representative URIs for this target.
125 (array of bytestrings) Representative URIs for this target.
122
126
123 snirequired (optional)
127 snirequired (optional)
124 (boolean) Indicates whether Server Name Indication is required
128 (boolean) Indicates whether Server Name Indication is required
125 to use this target. Defaults to False.
129 to use this target. Defaults to False.
126
130
127 tlsversions (optional)
131 tlsversions (optional)
128 (array of bytestring) Indicates which TLS versions are supported by
132 (array of bytestring) Indicates which TLS versions are supported by
129 this target. Values are ``1.1``, ``1.2``, ``1.3``, etc.
133 this target. Values are ``1.1``, ``1.2``, ``1.3``, etc.
130
134
131 hashes
135 hashes
132 (array of bytestring) Indicates support for hashing algorithms that are
136 (array of bytestring) Indicates support for hashing algorithms that are
133 used to ensure content integrity. Values include ``sha1``, ``sha256``,
137 used to ensure content integrity. Values include ``sha1``, ``sha256``,
134 etc.
138 etc.
135
139
136 changesetdata
140 changesetdata
137 -------------
141 -------------
138
142
139 Obtain various data related to changesets.
143 Obtain various data related to changesets.
140
144
141 The command accepts the following arguments:
145 The command accepts the following arguments:
142
146
143 noderange
147 noderange
144 (array of arrays of bytestrings) An array of 2 elements, each being an
148 (array of arrays of bytestrings) An array of 2 elements, each being an
145 array of node bytestrings. The first array denotes the changelog revisions
149 array of node bytestrings. The first array denotes the changelog revisions
146 that are already known to the client. The second array denotes the changelog
150 that are already known to the client. The second array denotes the changelog
147 revision DAG heads to fetch. The argument essentially defines a DAG range
151 revision DAG heads to fetch. The argument essentially defines a DAG range
148 bounded by root and head nodes to fetch.
152 bounded by root and head nodes to fetch.
149
153
150 The roots array may be empty. The heads array must be defined.
154 The roots array may be empty. The heads array must be defined.
151
155
152 nodes
156 nodes
153 (array of bytestrings) Changelog revisions to request explicitly.
157 (array of bytestrings) Changelog revisions to request explicitly.
154
158
155 nodesdepth
159 nodesdepth
156 (unsigned integer) Number of ancestor revisions of elements in ``nodes``
160 (unsigned integer) Number of ancestor revisions of elements in ``nodes``
157 to also fetch. When defined, for each element in ``nodes``, DAG ancestors
161 to also fetch. When defined, for each element in ``nodes``, DAG ancestors
158 will be walked until at most N total revisions are emitted.
162 will be walked until at most N total revisions are emitted.
159
163
160 fields
164 fields
161 (set of bytestring) Which data associated with changelog revisions to
165 (set of bytestring) Which data associated with changelog revisions to
162 fetch. The following values are recognized:
166 fetch. The following values are recognized:
163
167
164 bookmarks
168 bookmarks
165 Bookmarks associated with a revision.
169 Bookmarks associated with a revision.
166
170
167 parents
171 parents
168 Parent revisions.
172 Parent revisions.
169
173
170 phase
174 phase
171 The phase state of a revision.
175 The phase state of a revision.
172
176
173 revision
177 revision
174 The raw, revision data for the changelog entry. The hash of this data
178 The raw, revision data for the changelog entry. The hash of this data
175 will match the revision's node value.
179 will match the revision's node value.
176
180
177 The server resolves the set of revisions relevant to the request by taking
181 The server resolves the set of revisions relevant to the request by taking
178 the union of the ``noderange`` and ``nodes`` arguments. At least one of these
182 the union of the ``noderange`` and ``nodes`` arguments. At least one of these
179 arguments must be defined.
183 arguments must be defined.
180
184
181 The response bytestream starts with a CBOR map describing the data that follows.
185 The response bytestream starts with a CBOR map describing the data that follows.
182 This map has the following bytestring keys:
186 This map has the following bytestring keys:
183
187
184 totalitems
188 totalitems
185 (unsigned integer) Total number of changelog revisions whose data is being
189 (unsigned integer) Total number of changelog revisions whose data is being
186 transferred. This maps to the set of revisions in the requested node
190 transferred. This maps to the set of revisions in the requested node
187 range, not the total number of records that follow (see below for why).
191 range, not the total number of records that follow (see below for why).
188
192
189 Following the map header is a series of 0 or more CBOR values. If values
193 Following the map header is a series of 0 or more CBOR values. If values
190 are present, the first value will always be a map describing a single changeset
194 are present, the first value will always be a map describing a single changeset
191 revision.
195 revision.
192
196
193 If the ``fieldsfollowing`` key is present, the map will immediately be followed
197 If the ``fieldsfollowing`` key is present, the map will immediately be followed
194 by N CBOR bytestring values, where N is the number of elements in
198 by N CBOR bytestring values, where N is the number of elements in
195 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
199 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
196 by ``fieldsfollowing``.
200 by ``fieldsfollowing``.
197
201
198 Following the optional bytestring field values is the next revision descriptor
202 Following the optional bytestring field values is the next revision descriptor
199 map, or end of stream.
203 map, or end of stream.
200
204
201 Each revision descriptor map has the following bytestring keys:
205 Each revision descriptor map has the following bytestring keys:
202
206
203 node
207 node
204 (bytestring) The node value for this revision. This is the SHA-1 hash of
208 (bytestring) The node value for this revision. This is the SHA-1 hash of
205 the raw revision data.
209 the raw revision data.
206
210
207 bookmarks (optional)
211 bookmarks (optional)
208 (array of bytestrings) Bookmarks attached to this revision. Only present
212 (array of bytestrings) Bookmarks attached to this revision. Only present
209 if ``bookmarks`` data is being requested and the revision has bookmarks
213 if ``bookmarks`` data is being requested and the revision has bookmarks
210 attached.
214 attached.
211
215
212 fieldsfollowing (optional)
216 fieldsfollowing (optional)
213 (array of 2-array) Denotes what fields immediately follow this map. Each
217 (array of 2-array) Denotes what fields immediately follow this map. Each
214 value is an array with 2 elements: the bytestring field name and an unsigned
218 value is an array with 2 elements: the bytestring field name and an unsigned
215 integer describing the length of the data, in bytes.
219 integer describing the length of the data, in bytes.
216
220
217 If this key isn't present, no special fields will follow this map.
221 If this key isn't present, no special fields will follow this map.
218
222
219 The following fields may be present:
223 The following fields may be present:
220
224
221 revision
225 revision
222 Raw, revision data for the changelog entry. Contains a serialized form
226 Raw, revision data for the changelog entry. Contains a serialized form
223 of the changeset data, including the author, date, commit message, set
227 of the changeset data, including the author, date, commit message, set
224 of changed files, manifest node, and other metadata.
228 of changed files, manifest node, and other metadata.
225
229
226 Only present if the ``revision`` field was requested.
230 Only present if the ``revision`` field was requested.
227
231
228 parents (optional)
232 parents (optional)
229 (array of bytestrings) The nodes representing the parent revisions of this
233 (array of bytestrings) The nodes representing the parent revisions of this
230 revision. Only present if ``parents`` data is being requested.
234 revision. Only present if ``parents`` data is being requested.
231
235
232 phase (optional)
236 phase (optional)
233 (bytestring) The phase that a revision is in. Recognized values are
237 (bytestring) The phase that a revision is in. Recognized values are
234 ``secret``, ``draft``, and ``public``. Only present if ``phase`` data
238 ``secret``, ``draft``, and ``public``. Only present if ``phase`` data
235 is being requested.
239 is being requested.
236
240
237 If nodes are requested via ``noderange``, they will be emitted in DAG order,
241 If nodes are requested via ``noderange``, they will be emitted in DAG order,
238 parents always before children.
242 parents always before children.
239
243
240 If nodes are requested via ``nodes``, they will be emitted in requested order.
244 If nodes are requested via ``nodes``, they will be emitted in requested order.
241
245
242 Nodes from ``nodes`` are emitted before nodes from ``noderange``.
246 Nodes from ``nodes`` are emitted before nodes from ``noderange``.
243
247
244 The set of changeset revisions emitted may not match the exact set of
248 The set of changeset revisions emitted may not match the exact set of
245 changesets requested. Furthermore, the set of keys present on each
249 changesets requested. Furthermore, the set of keys present on each
246 map may vary. This is to facilitate emitting changeset updates as well
250 map may vary. This is to facilitate emitting changeset updates as well
247 as new revisions.
251 as new revisions.
248
252
249 For example, if the request wants ``phase`` and ``revision`` data,
253 For example, if the request wants ``phase`` and ``revision`` data,
250 the response may contain entries for each changeset in the common nodes
254 the response may contain entries for each changeset in the common nodes
251 set with the ``phase`` key and without the ``revision`` key in order
255 set with the ``phase`` key and without the ``revision`` key in order
252 to reflect a phase-only update.
256 to reflect a phase-only update.
253
257
254 TODO support different revision selection mechanisms (e.g. non-public, specific
258 TODO support different revision selection mechanisms (e.g. non-public, specific
255 revisions)
259 revisions)
256 TODO support different hash "namespaces" for revisions (e.g. sha-1 versus other)
260 TODO support different hash "namespaces" for revisions (e.g. sha-1 versus other)
257 TODO support emitting obsolescence data
261 TODO support emitting obsolescence data
258 TODO support filtering based on relevant paths (narrow clone)
262 TODO support filtering based on relevant paths (narrow clone)
259 TODO support hgtagsfnodes cache / tags data
263 TODO support hgtagsfnodes cache / tags data
260 TODO support branch heads cache
264 TODO support branch heads cache
261 TODO consider unify query mechanism. e.g. as an array of "query descriptors"
265 TODO consider unify query mechanism. e.g. as an array of "query descriptors"
262 rather than a set of top-level arguments that have semantics when combined.
266 rather than a set of top-level arguments that have semantics when combined.
263
267
264 filedata
268 filedata
265 --------
269 --------
266
270
267 Obtain various data related to an individual tracked file.
271 Obtain various data related to an individual tracked file.
268
272
269 The command accepts the following arguments:
273 The command accepts the following arguments:
270
274
271 fields
275 fields
272 (set of bytestring) Which data associated with a file to fetch.
276 (set of bytestring) Which data associated with a file to fetch.
273 The following values are recognized:
277 The following values are recognized:
274
278
275 parents
279 parents
276 Parent nodes for the revision.
280 Parent nodes for the revision.
277
281
278 revision
282 revision
279 The raw revision data for a file.
283 The raw revision data for a file.
280
284
281 haveparents
285 haveparents
282 (bool) Whether the client has the parent revisions of all requested
286 (bool) Whether the client has the parent revisions of all requested
283 nodes. If set, the server may emit revision data as deltas against
287 nodes. If set, the server may emit revision data as deltas against
284 any parent revision. If not set, the server MUST only emit deltas for
288 any parent revision. If not set, the server MUST only emit deltas for
285 revisions previously emitted by this command.
289 revisions previously emitted by this command.
286
290
287 False is assumed in the absence of any value.
291 False is assumed in the absence of any value.
288
292
289 nodes
293 nodes
290 (array of bytestrings) File nodes whose data to retrieve.
294 (array of bytestrings) File nodes whose data to retrieve.
291
295
292 path
296 path
293 (bytestring) Path of the tracked file whose data to retrieve.
297 (bytestring) Path of the tracked file whose data to retrieve.
294
298
295 TODO allow specifying revisions via alternate means (such as from
299 TODO allow specifying revisions via alternate means (such as from
296 changeset revisions or ranges)
300 changeset revisions or ranges)
297
301
298 The response bytestream starts with a CBOR map describing the data that
302 The response bytestream starts with a CBOR map describing the data that
299 follows. It has the following bytestream keys:
303 follows. It has the following bytestream keys:
300
304
301 totalitems
305 totalitems
302 (unsigned integer) Total number of file revisions whose data is
306 (unsigned integer) Total number of file revisions whose data is
303 being returned.
307 being returned.
304
308
305 Following the map header is a series of 0 or more CBOR values. If values
309 Following the map header is a series of 0 or more CBOR values. If values
306 are present, the first value will always be a map describing a single changeset
310 are present, the first value will always be a map describing a single changeset
307 revision.
311 revision.
308
312
309 If the ``fieldsfollowing`` key is present, the map will immediately be followed
313 If the ``fieldsfollowing`` key is present, the map will immediately be followed
310 by N CBOR bytestring values, where N is the number of elements in
314 by N CBOR bytestring values, where N is the number of elements in
311 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
315 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
312 by ``fieldsfollowing``.
316 by ``fieldsfollowing``.
313
317
314 Following the optional bytestring field values is the next revision descriptor
318 Following the optional bytestring field values is the next revision descriptor
315 map, or end of stream.
319 map, or end of stream.
316
320
317 Each revision descriptor map has the following bytestring keys:
321 Each revision descriptor map has the following bytestring keys:
318
322
319 Each map has the following bytestring keys:
323 Each map has the following bytestring keys:
320
324
321 node
325 node
322 (bytestring) The node of the file revision whose data is represented.
326 (bytestring) The node of the file revision whose data is represented.
323
327
324 deltabasenode
328 deltabasenode
325 (bytestring) Node of the file revision the following delta is against.
329 (bytestring) Node of the file revision the following delta is against.
326
330
327 Only present if the ``revision`` field is requested and delta data
331 Only present if the ``revision`` field is requested and delta data
328 follows this map.
332 follows this map.
329
333
330 fieldsfollowing
334 fieldsfollowing
331 (array of 2-array) Denotes extra bytestring fields that following this map.
335 (array of 2-array) Denotes extra bytestring fields that following this map.
332 See the documentation for ``changesetdata`` for semantics.
336 See the documentation for ``changesetdata`` for semantics.
333
337
334 The following named fields may be present:
338 The following named fields may be present:
335
339
336 ``delta``
340 ``delta``
337 The delta data to use to construct the fulltext revision.
341 The delta data to use to construct the fulltext revision.
338
342
339 Only present if the ``revision`` field is requested and a delta is
343 Only present if the ``revision`` field is requested and a delta is
340 being emitted. The ``deltabasenode`` top-level key will also be
344 being emitted. The ``deltabasenode`` top-level key will also be
341 present if this field is being emitted.
345 present if this field is being emitted.
342
346
343 ``revision``
347 ``revision``
344 The fulltext revision data for this manifest. Only present if the
348 The fulltext revision data for this manifest. Only present if the
345 ``revision`` field is requested and a fulltext revision is being emitted.
349 ``revision`` field is requested and a fulltext revision is being emitted.
346
350
347 parents
351 parents
348 (array of bytestring) The nodes of the parents of this file revision.
352 (array of bytestring) The nodes of the parents of this file revision.
349
353
350 Only present if the ``parents`` field is requested.
354 Only present if the ``parents`` field is requested.
351
355
352 When ``revision`` data is requested, the server chooses to emit either fulltext
356 When ``revision`` data is requested, the server chooses to emit either fulltext
353 revision data or a delta. What the server decides can be inferred by looking
357 revision data or a delta. What the server decides can be inferred by looking
354 for the presence of the ``delta`` or ``revision`` keys in the
358 for the presence of the ``delta`` or ``revision`` keys in the
355 ``fieldsfollowing`` array.
359 ``fieldsfollowing`` array.
356
360
357 heads
361 heads
358 -----
362 -----
359
363
360 Obtain DAG heads in the repository.
364 Obtain DAG heads in the repository.
361
365
362 The command accepts the following arguments:
366 The command accepts the following arguments:
363
367
364 publiconly (optional)
368 publiconly (optional)
365 (boolean) If set, operate on the DAG for public phase changesets only.
369 (boolean) If set, operate on the DAG for public phase changesets only.
366 Non-public (i.e. draft) phase DAG heads will not be returned.
370 Non-public (i.e. draft) phase DAG heads will not be returned.
367
371
368 The response is a CBOR array of bytestrings defining changeset nodes
372 The response is a CBOR array of bytestrings defining changeset nodes
369 of DAG heads. The array can be empty if the repository is empty or no
373 of DAG heads. The array can be empty if the repository is empty or no
370 changesets satisfied the request.
374 changesets satisfied the request.
371
375
372 TODO consider exposing phase of heads in response
376 TODO consider exposing phase of heads in response
373
377
374 known
378 known
375 -----
379 -----
376
380
377 Determine whether a series of changeset nodes is known to the server.
381 Determine whether a series of changeset nodes is known to the server.
378
382
379 The command accepts the following arguments:
383 The command accepts the following arguments:
380
384
381 nodes
385 nodes
382 (array of bytestrings) List of changeset nodes whose presence to
386 (array of bytestrings) List of changeset nodes whose presence to
383 query.
387 query.
384
388
385 The response is a bytestring where each byte contains a 0 or 1 for the
389 The response is a bytestring where each byte contains a 0 or 1 for the
386 corresponding requested node at the same index.
390 corresponding requested node at the same index.
387
391
388 TODO use a bit array for even more compact response
392 TODO use a bit array for even more compact response
389
393
390 listkeys
394 listkeys
391 --------
395 --------
392
396
393 List values in a specified ``pushkey`` namespace.
397 List values in a specified ``pushkey`` namespace.
394
398
395 The command receives the following arguments:
399 The command receives the following arguments:
396
400
397 namespace
401 namespace
398 (bytestring) Pushkey namespace to query.
402 (bytestring) Pushkey namespace to query.
399
403
400 The response is a map with bytestring keys and values.
404 The response is a map with bytestring keys and values.
401
405
402 TODO consider using binary to represent nodes in certain pushkey namespaces.
406 TODO consider using binary to represent nodes in certain pushkey namespaces.
403
407
404 lookup
408 lookup
405 ------
409 ------
406
410
407 Try to resolve a value to a changeset revision.
411 Try to resolve a value to a changeset revision.
408
412
409 Unlike ``known`` which operates on changeset nodes, lookup operates on
413 Unlike ``known`` which operates on changeset nodes, lookup operates on
410 node fragments and other names that a user may use.
414 node fragments and other names that a user may use.
411
415
412 The command receives the following arguments:
416 The command receives the following arguments:
413
417
414 key
418 key
415 (bytestring) Value to try to resolve.
419 (bytestring) Value to try to resolve.
416
420
417 On success, returns a bytestring containing the resolved node.
421 On success, returns a bytestring containing the resolved node.
418
422
419 manifestdata
423 manifestdata
420 ------------
424 ------------
421
425
422 Obtain various data related to manifests (which are lists of files in
426 Obtain various data related to manifests (which are lists of files in
423 a revision).
427 a revision).
424
428
425 The command accepts the following arguments:
429 The command accepts the following arguments:
426
430
427 fields
431 fields
428 (set of bytestring) Which data associated with manifests to fetch.
432 (set of bytestring) Which data associated with manifests to fetch.
429 The following values are recognized:
433 The following values are recognized:
430
434
431 parents
435 parents
432 Parent nodes for the manifest.
436 Parent nodes for the manifest.
433
437
434 revision
438 revision
435 The raw revision data for the manifest.
439 The raw revision data for the manifest.
436
440
437 haveparents
441 haveparents
438 (bool) Whether the client has the parent revisions of all requested
442 (bool) Whether the client has the parent revisions of all requested
439 nodes. If set, the server may emit revision data as deltas against
443 nodes. If set, the server may emit revision data as deltas against
440 any parent revision. If not set, the server MUST only emit deltas for
444 any parent revision. If not set, the server MUST only emit deltas for
441 revisions previously emitted by this command.
445 revisions previously emitted by this command.
442
446
443 False is assumed in the absence of any value.
447 False is assumed in the absence of any value.
444
448
445 nodes
449 nodes
446 (array of bytestring) Manifest nodes whose data to retrieve.
450 (array of bytestring) Manifest nodes whose data to retrieve.
447
451
448 tree
452 tree
449 (bytestring) Path to manifest to retrieve. The empty bytestring represents
453 (bytestring) Path to manifest to retrieve. The empty bytestring represents
450 the root manifest. All other values represent directories/trees within
454 the root manifest. All other values represent directories/trees within
451 the repository.
455 the repository.
452
456
453 TODO allow specifying revisions via alternate means (such as from changeset
457 TODO allow specifying revisions via alternate means (such as from changeset
454 revisions or ranges)
458 revisions or ranges)
455 TODO consider recursive expansion of manifests (with path filtering for
459 TODO consider recursive expansion of manifests (with path filtering for
456 narrow use cases)
460 narrow use cases)
457
461
458 The response bytestream starts with a CBOR map describing the data that
462 The response bytestream starts with a CBOR map describing the data that
459 follows. It has the following bytestring keys:
463 follows. It has the following bytestring keys:
460
464
461 totalitems
465 totalitems
462 (unsigned integer) Total number of manifest revisions whose data is
466 (unsigned integer) Total number of manifest revisions whose data is
463 being returned.
467 being returned.
464
468
465 Following the map header is a series of 0 or more CBOR values. If values
469 Following the map header is a series of 0 or more CBOR values. If values
466 are present, the first value will always be a map describing a single manifest
470 are present, the first value will always be a map describing a single manifest
467 revision.
471 revision.
468
472
469 If the ``fieldsfollowing`` key is present, the map will immediately be followed
473 If the ``fieldsfollowing`` key is present, the map will immediately be followed
470 by N CBOR bytestring values, where N is the number of elements in
474 by N CBOR bytestring values, where N is the number of elements in
471 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
475 ``fieldsfollowing``. Each bytestring value corresponds to a field denoted
472 by ``fieldsfollowing``.
476 by ``fieldsfollowing``.
473
477
474 Following the optional bytestring field values is the next revision descriptor
478 Following the optional bytestring field values is the next revision descriptor
475 map, or end of stream.
479 map, or end of stream.
476
480
477 Each revision descriptor map has the following bytestring keys:
481 Each revision descriptor map has the following bytestring keys:
478
482
479 node
483 node
480 (bytestring) The node of the manifest revision whose data is represented.
484 (bytestring) The node of the manifest revision whose data is represented.
481
485
482 deltabasenode
486 deltabasenode
483 (bytestring) The node that the delta representation of this revision is
487 (bytestring) The node that the delta representation of this revision is
484 computed against. Only present if the ``revision`` field is requested and
488 computed against. Only present if the ``revision`` field is requested and
485 a delta is being emitted.
489 a delta is being emitted.
486
490
487 fieldsfollowing
491 fieldsfollowing
488 (array of 2-array) Denotes extra bytestring fields that following this map.
492 (array of 2-array) Denotes extra bytestring fields that following this map.
489 See the documentation for ``changesetdata`` for semantics.
493 See the documentation for ``changesetdata`` for semantics.
490
494
491 The following named fields may be present:
495 The following named fields may be present:
492
496
493 ``delta``
497 ``delta``
494 The delta data to use to construct the fulltext revision.
498 The delta data to use to construct the fulltext revision.
495
499
496 Only present if the ``revision`` field is requested and a delta is
500 Only present if the ``revision`` field is requested and a delta is
497 being emitted. The ``deltabasenode`` top-level key will also be
501 being emitted. The ``deltabasenode`` top-level key will also be
498 present if this field is being emitted.
502 present if this field is being emitted.
499
503
500 ``revision``
504 ``revision``
501 The fulltext revision data for this manifest. Only present if the
505 The fulltext revision data for this manifest. Only present if the
502 ``revision`` field is requested and a fulltext revision is being emitted.
506 ``revision`` field is requested and a fulltext revision is being emitted.
503
507
504 parents
508 parents
505 (array of bytestring) The nodes of the parents of this manifest revision.
509 (array of bytestring) The nodes of the parents of this manifest revision.
506 Only present if the ``parents`` field is requested.
510 Only present if the ``parents`` field is requested.
507
511
508 When ``revision`` data is requested, the server chooses to emit either fulltext
512 When ``revision`` data is requested, the server chooses to emit either fulltext
509 revision data or a delta. What the server decides can be inferred by looking
513 revision data or a delta. What the server decides can be inferred by looking
510 for the presence of ``delta`` or ``revision`` in the ``fieldsfollowing`` array.
514 for the presence of ``delta`` or ``revision`` in the ``fieldsfollowing`` array.
511
515
516 Servers MAY advertise the following extra fields in the capabilities
517 descriptor for this command:
518
519 recommendedbatchsize
520 (unsigned integer) Number of revisions the server recommends as a batch
521 query size. If defined, clients needing to issue multiple ``manifestdata``
522 commands to obtain needed data SHOULD construct their commands to have
523 this many revisions per request.
524
512 pushkey
525 pushkey
513 -------
526 -------
514
527
515 Set a value using the ``pushkey`` protocol.
528 Set a value using the ``pushkey`` protocol.
516
529
517 The command receives the following arguments:
530 The command receives the following arguments:
518
531
519 namespace
532 namespace
520 (bytestring) Pushkey namespace to operate on.
533 (bytestring) Pushkey namespace to operate on.
521 key
534 key
522 (bytestring) The pushkey key to set.
535 (bytestring) The pushkey key to set.
523 old
536 old
524 (bytestring) Old value for this key.
537 (bytestring) Old value for this key.
525 new
538 new
526 (bytestring) New value for this key.
539 (bytestring) New value for this key.
527
540
528 TODO consider using binary to represent nodes is certain pushkey namespaces.
541 TODO consider using binary to represent nodes is certain pushkey namespaces.
529 TODO better define response type and meaning.
542 TODO better define response type and meaning.
@@ -1,390 +1,391 b''
1 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
1 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 from __future__ import absolute_import
6 from __future__ import absolute_import
7
7
8 from .node import (
8 from .node import (
9 bin,
9 bin,
10 hex,
10 hex,
11 )
11 )
12 from .i18n import _
12 from .i18n import _
13 from .thirdparty import (
13 from .thirdparty import (
14 attr,
14 attr,
15 )
15 )
16 from . import (
16 from . import (
17 error,
17 error,
18 util,
18 util,
19 )
19 )
20 from .utils import (
20 from .utils import (
21 interfaceutil,
21 interfaceutil,
22 )
22 )
23
23
24 # Names of the SSH protocol implementations.
24 # Names of the SSH protocol implementations.
25 SSHV1 = 'ssh-v1'
25 SSHV1 = 'ssh-v1'
26 # These are advertised over the wire. Increment the counters at the end
26 # These are advertised over the wire. Increment the counters at the end
27 # to reflect BC breakages.
27 # to reflect BC breakages.
28 SSHV2 = 'exp-ssh-v2-0002'
28 SSHV2 = 'exp-ssh-v2-0002'
29 HTTP_WIREPROTO_V2 = 'exp-http-v2-0002'
29 HTTP_WIREPROTO_V2 = 'exp-http-v2-0002'
30
30
31 NARROWCAP = 'exp-narrow-1'
31 NARROWCAP = 'exp-narrow-1'
32 ELLIPSESCAP = 'exp-ellipses-1'
32 ELLIPSESCAP = 'exp-ellipses-1'
33
33
34 # All available wire protocol transports.
34 # All available wire protocol transports.
35 TRANSPORTS = {
35 TRANSPORTS = {
36 SSHV1: {
36 SSHV1: {
37 'transport': 'ssh',
37 'transport': 'ssh',
38 'version': 1,
38 'version': 1,
39 },
39 },
40 SSHV2: {
40 SSHV2: {
41 'transport': 'ssh',
41 'transport': 'ssh',
42 # TODO mark as version 2 once all commands are implemented.
42 # TODO mark as version 2 once all commands are implemented.
43 'version': 1,
43 'version': 1,
44 },
44 },
45 'http-v1': {
45 'http-v1': {
46 'transport': 'http',
46 'transport': 'http',
47 'version': 1,
47 'version': 1,
48 },
48 },
49 HTTP_WIREPROTO_V2: {
49 HTTP_WIREPROTO_V2: {
50 'transport': 'http',
50 'transport': 'http',
51 'version': 2,
51 'version': 2,
52 }
52 }
53 }
53 }
54
54
55 class bytesresponse(object):
55 class bytesresponse(object):
56 """A wire protocol response consisting of raw bytes."""
56 """A wire protocol response consisting of raw bytes."""
57 def __init__(self, data):
57 def __init__(self, data):
58 self.data = data
58 self.data = data
59
59
60 class ooberror(object):
60 class ooberror(object):
61 """wireproto reply: failure of a batch of operation
61 """wireproto reply: failure of a batch of operation
62
62
63 Something failed during a batch call. The error message is stored in
63 Something failed during a batch call. The error message is stored in
64 `self.message`.
64 `self.message`.
65 """
65 """
66 def __init__(self, message):
66 def __init__(self, message):
67 self.message = message
67 self.message = message
68
68
69 class pushres(object):
69 class pushres(object):
70 """wireproto reply: success with simple integer return
70 """wireproto reply: success with simple integer return
71
71
72 The call was successful and returned an integer contained in `self.res`.
72 The call was successful and returned an integer contained in `self.res`.
73 """
73 """
74 def __init__(self, res, output):
74 def __init__(self, res, output):
75 self.res = res
75 self.res = res
76 self.output = output
76 self.output = output
77
77
78 class pusherr(object):
78 class pusherr(object):
79 """wireproto reply: failure
79 """wireproto reply: failure
80
80
81 The call failed. The `self.res` attribute contains the error message.
81 The call failed. The `self.res` attribute contains the error message.
82 """
82 """
83 def __init__(self, res, output):
83 def __init__(self, res, output):
84 self.res = res
84 self.res = res
85 self.output = output
85 self.output = output
86
86
87 class streamres(object):
87 class streamres(object):
88 """wireproto reply: binary stream
88 """wireproto reply: binary stream
89
89
90 The call was successful and the result is a stream.
90 The call was successful and the result is a stream.
91
91
92 Accepts a generator containing chunks of data to be sent to the client.
92 Accepts a generator containing chunks of data to be sent to the client.
93
93
94 ``prefer_uncompressed`` indicates that the data is expected to be
94 ``prefer_uncompressed`` indicates that the data is expected to be
95 uncompressable and that the stream should therefore use the ``none``
95 uncompressable and that the stream should therefore use the ``none``
96 engine.
96 engine.
97 """
97 """
98 def __init__(self, gen=None, prefer_uncompressed=False):
98 def __init__(self, gen=None, prefer_uncompressed=False):
99 self.gen = gen
99 self.gen = gen
100 self.prefer_uncompressed = prefer_uncompressed
100 self.prefer_uncompressed = prefer_uncompressed
101
101
102 class streamreslegacy(object):
102 class streamreslegacy(object):
103 """wireproto reply: uncompressed binary stream
103 """wireproto reply: uncompressed binary stream
104
104
105 The call was successful and the result is a stream.
105 The call was successful and the result is a stream.
106
106
107 Accepts a generator containing chunks of data to be sent to the client.
107 Accepts a generator containing chunks of data to be sent to the client.
108
108
109 Like ``streamres``, but sends an uncompressed data for "version 1" clients
109 Like ``streamres``, but sends an uncompressed data for "version 1" clients
110 using the application/mercurial-0.1 media type.
110 using the application/mercurial-0.1 media type.
111 """
111 """
112 def __init__(self, gen=None):
112 def __init__(self, gen=None):
113 self.gen = gen
113 self.gen = gen
114
114
115 # list of nodes encoding / decoding
115 # list of nodes encoding / decoding
116 def decodelist(l, sep=' '):
116 def decodelist(l, sep=' '):
117 if l:
117 if l:
118 return [bin(v) for v in l.split(sep)]
118 return [bin(v) for v in l.split(sep)]
119 return []
119 return []
120
120
121 def encodelist(l, sep=' '):
121 def encodelist(l, sep=' '):
122 try:
122 try:
123 return sep.join(map(hex, l))
123 return sep.join(map(hex, l))
124 except TypeError:
124 except TypeError:
125 raise
125 raise
126
126
127 # batched call argument encoding
127 # batched call argument encoding
128
128
129 def escapebatcharg(plain):
129 def escapebatcharg(plain):
130 return (plain
130 return (plain
131 .replace(':', ':c')
131 .replace(':', ':c')
132 .replace(',', ':o')
132 .replace(',', ':o')
133 .replace(';', ':s')
133 .replace(';', ':s')
134 .replace('=', ':e'))
134 .replace('=', ':e'))
135
135
136 def unescapebatcharg(escaped):
136 def unescapebatcharg(escaped):
137 return (escaped
137 return (escaped
138 .replace(':e', '=')
138 .replace(':e', '=')
139 .replace(':s', ';')
139 .replace(':s', ';')
140 .replace(':o', ',')
140 .replace(':o', ',')
141 .replace(':c', ':'))
141 .replace(':c', ':'))
142
142
143 # mapping of options accepted by getbundle and their types
143 # mapping of options accepted by getbundle and their types
144 #
144 #
145 # Meant to be extended by extensions. It is extensions responsibility to ensure
145 # Meant to be extended by extensions. It is extensions responsibility to ensure
146 # such options are properly processed in exchange.getbundle.
146 # such options are properly processed in exchange.getbundle.
147 #
147 #
148 # supported types are:
148 # supported types are:
149 #
149 #
150 # :nodes: list of binary nodes
150 # :nodes: list of binary nodes
151 # :csv: list of comma-separated values
151 # :csv: list of comma-separated values
152 # :scsv: list of comma-separated values return as set
152 # :scsv: list of comma-separated values return as set
153 # :plain: string with no transformation needed.
153 # :plain: string with no transformation needed.
154 GETBUNDLE_ARGUMENTS = {
154 GETBUNDLE_ARGUMENTS = {
155 'heads': 'nodes',
155 'heads': 'nodes',
156 'bookmarks': 'boolean',
156 'bookmarks': 'boolean',
157 'common': 'nodes',
157 'common': 'nodes',
158 'obsmarkers': 'boolean',
158 'obsmarkers': 'boolean',
159 'phases': 'boolean',
159 'phases': 'boolean',
160 'bundlecaps': 'scsv',
160 'bundlecaps': 'scsv',
161 'listkeys': 'csv',
161 'listkeys': 'csv',
162 'cg': 'boolean',
162 'cg': 'boolean',
163 'cbattempted': 'boolean',
163 'cbattempted': 'boolean',
164 'stream': 'boolean',
164 'stream': 'boolean',
165 }
165 }
166
166
167 class baseprotocolhandler(interfaceutil.Interface):
167 class baseprotocolhandler(interfaceutil.Interface):
168 """Abstract base class for wire protocol handlers.
168 """Abstract base class for wire protocol handlers.
169
169
170 A wire protocol handler serves as an interface between protocol command
170 A wire protocol handler serves as an interface between protocol command
171 handlers and the wire protocol transport layer. Protocol handlers provide
171 handlers and the wire protocol transport layer. Protocol handlers provide
172 methods to read command arguments, redirect stdio for the duration of
172 methods to read command arguments, redirect stdio for the duration of
173 the request, handle response types, etc.
173 the request, handle response types, etc.
174 """
174 """
175
175
176 name = interfaceutil.Attribute(
176 name = interfaceutil.Attribute(
177 """The name of the protocol implementation.
177 """The name of the protocol implementation.
178
178
179 Used for uniquely identifying the transport type.
179 Used for uniquely identifying the transport type.
180 """)
180 """)
181
181
182 def getargs(args):
182 def getargs(args):
183 """return the value for arguments in <args>
183 """return the value for arguments in <args>
184
184
185 For version 1 transports, returns a list of values in the same
185 For version 1 transports, returns a list of values in the same
186 order they appear in ``args``. For version 2 transports, returns
186 order they appear in ``args``. For version 2 transports, returns
187 a dict mapping argument name to value.
187 a dict mapping argument name to value.
188 """
188 """
189
189
190 def getprotocaps():
190 def getprotocaps():
191 """Returns the list of protocol-level capabilities of client
191 """Returns the list of protocol-level capabilities of client
192
192
193 Returns a list of capabilities as declared by the client for
193 Returns a list of capabilities as declared by the client for
194 the current request (or connection for stateful protocol handlers)."""
194 the current request (or connection for stateful protocol handlers)."""
195
195
196 def getpayload():
196 def getpayload():
197 """Provide a generator for the raw payload.
197 """Provide a generator for the raw payload.
198
198
199 The caller is responsible for ensuring that the full payload is
199 The caller is responsible for ensuring that the full payload is
200 processed.
200 processed.
201 """
201 """
202
202
203 def mayberedirectstdio():
203 def mayberedirectstdio():
204 """Context manager to possibly redirect stdio.
204 """Context manager to possibly redirect stdio.
205
205
206 The context manager yields a file-object like object that receives
206 The context manager yields a file-object like object that receives
207 stdout and stderr output when the context manager is active. Or it
207 stdout and stderr output when the context manager is active. Or it
208 yields ``None`` if no I/O redirection occurs.
208 yields ``None`` if no I/O redirection occurs.
209
209
210 The intent of this context manager is to capture stdio output
210 The intent of this context manager is to capture stdio output
211 so it may be sent in the response. Some transports support streaming
211 so it may be sent in the response. Some transports support streaming
212 stdio to the client in real time. For these transports, stdio output
212 stdio to the client in real time. For these transports, stdio output
213 won't be captured.
213 won't be captured.
214 """
214 """
215
215
216 def client():
216 def client():
217 """Returns a string representation of this client (as bytes)."""
217 """Returns a string representation of this client (as bytes)."""
218
218
219 def addcapabilities(repo, caps):
219 def addcapabilities(repo, caps):
220 """Adds advertised capabilities specific to this protocol.
220 """Adds advertised capabilities specific to this protocol.
221
221
222 Receives the list of capabilities collected so far.
222 Receives the list of capabilities collected so far.
223
223
224 Returns a list of capabilities. The passed in argument can be returned.
224 Returns a list of capabilities. The passed in argument can be returned.
225 """
225 """
226
226
227 def checkperm(perm):
227 def checkperm(perm):
228 """Validate that the client has permissions to perform a request.
228 """Validate that the client has permissions to perform a request.
229
229
230 The argument is the permission required to proceed. If the client
230 The argument is the permission required to proceed. If the client
231 doesn't have that permission, the exception should raise or abort
231 doesn't have that permission, the exception should raise or abort
232 in a protocol specific manner.
232 in a protocol specific manner.
233 """
233 """
234
234
235 class commandentry(object):
235 class commandentry(object):
236 """Represents a declared wire protocol command."""
236 """Represents a declared wire protocol command."""
237 def __init__(self, func, args='', transports=None,
237 def __init__(self, func, args='', transports=None,
238 permission='push', cachekeyfn=None):
238 permission='push', cachekeyfn=None, extracapabilitiesfn=None):
239 self.func = func
239 self.func = func
240 self.args = args
240 self.args = args
241 self.transports = transports or set()
241 self.transports = transports or set()
242 self.permission = permission
242 self.permission = permission
243 self.cachekeyfn = cachekeyfn
243 self.cachekeyfn = cachekeyfn
244 self.extracapabilitiesfn = extracapabilitiesfn
244
245
245 def _merge(self, func, args):
246 def _merge(self, func, args):
246 """Merge this instance with an incoming 2-tuple.
247 """Merge this instance with an incoming 2-tuple.
247
248
248 This is called when a caller using the old 2-tuple API attempts
249 This is called when a caller using the old 2-tuple API attempts
249 to replace an instance. The incoming values are merged with
250 to replace an instance. The incoming values are merged with
250 data not captured by the 2-tuple and a new instance containing
251 data not captured by the 2-tuple and a new instance containing
251 the union of the two objects is returned.
252 the union of the two objects is returned.
252 """
253 """
253 return commandentry(func, args=args, transports=set(self.transports),
254 return commandentry(func, args=args, transports=set(self.transports),
254 permission=self.permission)
255 permission=self.permission)
255
256
256 # Old code treats instances as 2-tuples. So expose that interface.
257 # Old code treats instances as 2-tuples. So expose that interface.
257 def __iter__(self):
258 def __iter__(self):
258 yield self.func
259 yield self.func
259 yield self.args
260 yield self.args
260
261
261 def __getitem__(self, i):
262 def __getitem__(self, i):
262 if i == 0:
263 if i == 0:
263 return self.func
264 return self.func
264 elif i == 1:
265 elif i == 1:
265 return self.args
266 return self.args
266 else:
267 else:
267 raise IndexError('can only access elements 0 and 1')
268 raise IndexError('can only access elements 0 and 1')
268
269
269 class commanddict(dict):
270 class commanddict(dict):
270 """Container for registered wire protocol commands.
271 """Container for registered wire protocol commands.
271
272
272 It behaves like a dict. But __setitem__ is overwritten to allow silent
273 It behaves like a dict. But __setitem__ is overwritten to allow silent
273 coercion of values from 2-tuples for API compatibility.
274 coercion of values from 2-tuples for API compatibility.
274 """
275 """
275 def __setitem__(self, k, v):
276 def __setitem__(self, k, v):
276 if isinstance(v, commandentry):
277 if isinstance(v, commandentry):
277 pass
278 pass
278 # Cast 2-tuples to commandentry instances.
279 # Cast 2-tuples to commandentry instances.
279 elif isinstance(v, tuple):
280 elif isinstance(v, tuple):
280 if len(v) != 2:
281 if len(v) != 2:
281 raise ValueError('command tuples must have exactly 2 elements')
282 raise ValueError('command tuples must have exactly 2 elements')
282
283
283 # It is common for extensions to wrap wire protocol commands via
284 # It is common for extensions to wrap wire protocol commands via
284 # e.g. ``wireproto.commands[x] = (newfn, args)``. Because callers
285 # e.g. ``wireproto.commands[x] = (newfn, args)``. Because callers
285 # doing this aren't aware of the new API that uses objects to store
286 # doing this aren't aware of the new API that uses objects to store
286 # command entries, we automatically merge old state with new.
287 # command entries, we automatically merge old state with new.
287 if k in self:
288 if k in self:
288 v = self[k]._merge(v[0], v[1])
289 v = self[k]._merge(v[0], v[1])
289 else:
290 else:
290 # Use default values from @wireprotocommand.
291 # Use default values from @wireprotocommand.
291 v = commandentry(v[0], args=v[1],
292 v = commandentry(v[0], args=v[1],
292 transports=set(TRANSPORTS),
293 transports=set(TRANSPORTS),
293 permission='push')
294 permission='push')
294 else:
295 else:
295 raise ValueError('command entries must be commandentry instances '
296 raise ValueError('command entries must be commandentry instances '
296 'or 2-tuples')
297 'or 2-tuples')
297
298
298 return super(commanddict, self).__setitem__(k, v)
299 return super(commanddict, self).__setitem__(k, v)
299
300
300 def commandavailable(self, command, proto):
301 def commandavailable(self, command, proto):
301 """Determine if a command is available for the requested protocol."""
302 """Determine if a command is available for the requested protocol."""
302 assert proto.name in TRANSPORTS
303 assert proto.name in TRANSPORTS
303
304
304 entry = self.get(command)
305 entry = self.get(command)
305
306
306 if not entry:
307 if not entry:
307 return False
308 return False
308
309
309 if proto.name not in entry.transports:
310 if proto.name not in entry.transports:
310 return False
311 return False
311
312
312 return True
313 return True
313
314
314 def supportedcompengines(ui, role):
315 def supportedcompengines(ui, role):
315 """Obtain the list of supported compression engines for a request."""
316 """Obtain the list of supported compression engines for a request."""
316 assert role in (util.CLIENTROLE, util.SERVERROLE)
317 assert role in (util.CLIENTROLE, util.SERVERROLE)
317
318
318 compengines = util.compengines.supportedwireengines(role)
319 compengines = util.compengines.supportedwireengines(role)
319
320
320 # Allow config to override default list and ordering.
321 # Allow config to override default list and ordering.
321 if role == util.SERVERROLE:
322 if role == util.SERVERROLE:
322 configengines = ui.configlist('server', 'compressionengines')
323 configengines = ui.configlist('server', 'compressionengines')
323 config = 'server.compressionengines'
324 config = 'server.compressionengines'
324 else:
325 else:
325 # This is currently implemented mainly to facilitate testing. In most
326 # This is currently implemented mainly to facilitate testing. In most
326 # cases, the server should be in charge of choosing a compression engine
327 # cases, the server should be in charge of choosing a compression engine
327 # because a server has the most to lose from a sub-optimal choice. (e.g.
328 # because a server has the most to lose from a sub-optimal choice. (e.g.
328 # CPU DoS due to an expensive engine or a network DoS due to poor
329 # CPU DoS due to an expensive engine or a network DoS due to poor
329 # compression ratio).
330 # compression ratio).
330 configengines = ui.configlist('experimental',
331 configengines = ui.configlist('experimental',
331 'clientcompressionengines')
332 'clientcompressionengines')
332 config = 'experimental.clientcompressionengines'
333 config = 'experimental.clientcompressionengines'
333
334
334 # No explicit config. Filter out the ones that aren't supposed to be
335 # No explicit config. Filter out the ones that aren't supposed to be
335 # advertised and return default ordering.
336 # advertised and return default ordering.
336 if not configengines:
337 if not configengines:
337 attr = 'serverpriority' if role == util.SERVERROLE else 'clientpriority'
338 attr = 'serverpriority' if role == util.SERVERROLE else 'clientpriority'
338 return [e for e in compengines
339 return [e for e in compengines
339 if getattr(e.wireprotosupport(), attr) > 0]
340 if getattr(e.wireprotosupport(), attr) > 0]
340
341
341 # If compression engines are listed in the config, assume there is a good
342 # If compression engines are listed in the config, assume there is a good
342 # reason for it (like server operators wanting to achieve specific
343 # reason for it (like server operators wanting to achieve specific
343 # performance characteristics). So fail fast if the config references
344 # performance characteristics). So fail fast if the config references
344 # unusable compression engines.
345 # unusable compression engines.
345 validnames = set(e.name() for e in compengines)
346 validnames = set(e.name() for e in compengines)
346 invalidnames = set(e for e in configengines if e not in validnames)
347 invalidnames = set(e for e in configengines if e not in validnames)
347 if invalidnames:
348 if invalidnames:
348 raise error.Abort(_('invalid compression engine defined in %s: %s') %
349 raise error.Abort(_('invalid compression engine defined in %s: %s') %
349 (config, ', '.join(sorted(invalidnames))))
350 (config, ', '.join(sorted(invalidnames))))
350
351
351 compengines = [e for e in compengines if e.name() in configengines]
352 compengines = [e for e in compengines if e.name() in configengines]
352 compengines = sorted(compengines,
353 compengines = sorted(compengines,
353 key=lambda e: configengines.index(e.name()))
354 key=lambda e: configengines.index(e.name()))
354
355
355 if not compengines:
356 if not compengines:
356 raise error.Abort(_('%s config option does not specify any known '
357 raise error.Abort(_('%s config option does not specify any known '
357 'compression engines') % config,
358 'compression engines') % config,
358 hint=_('usable compression engines: %s') %
359 hint=_('usable compression engines: %s') %
359 ', '.sorted(validnames))
360 ', '.sorted(validnames))
360
361
361 return compengines
362 return compengines
362
363
363 @attr.s
364 @attr.s
364 class encodedresponse(object):
365 class encodedresponse(object):
365 """Represents response data that is already content encoded.
366 """Represents response data that is already content encoded.
366
367
367 Wire protocol version 2 only.
368 Wire protocol version 2 only.
368
369
369 Commands typically emit Python objects that are encoded and sent over the
370 Commands typically emit Python objects that are encoded and sent over the
370 wire. If commands emit an object of this type, the encoding step is bypassed
371 wire. If commands emit an object of this type, the encoding step is bypassed
371 and the content from this object is used instead.
372 and the content from this object is used instead.
372 """
373 """
373 data = attr.ib()
374 data = attr.ib()
374
375
375 @attr.s
376 @attr.s
376 class alternatelocationresponse(object):
377 class alternatelocationresponse(object):
377 """Represents a response available at an alternate location.
378 """Represents a response available at an alternate location.
378
379
379 Instances are sent in place of actual response objects when the server
380 Instances are sent in place of actual response objects when the server
380 is sending a "content redirect" response.
381 is sending a "content redirect" response.
381
382
382 Only compatible with wire protocol version 2.
383 Only compatible with wire protocol version 2.
383 """
384 """
384 url = attr.ib()
385 url = attr.ib()
385 mediatype = attr.ib()
386 mediatype = attr.ib()
386 size = attr.ib(default=None)
387 size = attr.ib(default=None)
387 fullhashes = attr.ib(default=None)
388 fullhashes = attr.ib(default=None)
388 fullhashseed = attr.ib(default=None)
389 fullhashseed = attr.ib(default=None)
389 serverdercerts = attr.ib(default=None)
390 serverdercerts = attr.ib(default=None)
390 servercadercerts = attr.ib(default=None)
391 servercadercerts = attr.ib(default=None)
@@ -1,1192 +1,1212 b''
1 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
1 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
2 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 #
3 #
4 # This software may be used and distributed according to the terms of the
4 # This software may be used and distributed according to the terms of the
5 # GNU General Public License version 2 or any later version.
5 # GNU General Public License version 2 or any later version.
6
6
7 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import 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 wireprotoframing,
23 wireprotoframing,
24 wireprototypes,
24 wireprototypes,
25 )
25 )
26 from .utils import (
26 from .utils import (
27 cborutil,
27 cborutil,
28 interfaceutil,
28 interfaceutil,
29 stringutil,
29 stringutil,
30 )
30 )
31
31
32 FRAMINGTYPE = b'application/mercurial-exp-framing-0006'
32 FRAMINGTYPE = b'application/mercurial-exp-framing-0006'
33
33
34 HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
34 HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
35
35
36 COMMANDS = wireprototypes.commanddict()
36 COMMANDS = wireprototypes.commanddict()
37
37
38 # Value inserted into cache key computation function. Change the value to
38 # Value inserted into cache key computation function. Change the value to
39 # 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
40 # there is a change to how caching works, etc.
40 # there is a change to how caching works, etc.
41 GLOBAL_CACHE_VERSION = 1
41 GLOBAL_CACHE_VERSION = 1
42
42
43 def handlehttpv2request(rctx, req, res, checkperm, urlparts):
43 def handlehttpv2request(rctx, req, res, checkperm, urlparts):
44 from .hgweb import common as hgwebcommon
44 from .hgweb import common as hgwebcommon
45
45
46 # URL space looks like: <permissions>/<command>, where <permission> can
46 # URL space looks like: <permissions>/<command>, where <permission> can
47 # 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.
48
48
49 # Root URL does nothing meaningful... yet.
49 # Root URL does nothing meaningful... yet.
50 if not urlparts:
50 if not urlparts:
51 res.status = b'200 OK'
51 res.status = b'200 OK'
52 res.headers[b'Content-Type'] = b'text/plain'
52 res.headers[b'Content-Type'] = b'text/plain'
53 res.setbodybytes(_('HTTP version 2 API handler'))
53 res.setbodybytes(_('HTTP version 2 API handler'))
54 return
54 return
55
55
56 if len(urlparts) == 1:
56 if len(urlparts) == 1:
57 res.status = b'404 Not Found'
57 res.status = b'404 Not Found'
58 res.headers[b'Content-Type'] = b'text/plain'
58 res.headers[b'Content-Type'] = b'text/plain'
59 res.setbodybytes(_('do not know how to process %s\n') %
59 res.setbodybytes(_('do not know how to process %s\n') %
60 req.dispatchpath)
60 req.dispatchpath)
61 return
61 return
62
62
63 permission, command = urlparts[0:2]
63 permission, command = urlparts[0:2]
64
64
65 if permission not in (b'ro', b'rw'):
65 if permission not in (b'ro', b'rw'):
66 res.status = b'404 Not Found'
66 res.status = b'404 Not Found'
67 res.headers[b'Content-Type'] = b'text/plain'
67 res.headers[b'Content-Type'] = b'text/plain'
68 res.setbodybytes(_('unknown permission: %s') % permission)
68 res.setbodybytes(_('unknown permission: %s') % permission)
69 return
69 return
70
70
71 if req.method != 'POST':
71 if req.method != 'POST':
72 res.status = b'405 Method Not Allowed'
72 res.status = b'405 Method Not Allowed'
73 res.headers[b'Allow'] = b'POST'
73 res.headers[b'Allow'] = b'POST'
74 res.setbodybytes(_('commands require POST requests'))
74 res.setbodybytes(_('commands require POST requests'))
75 return
75 return
76
76
77 # 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
78 # behavior of version 1 of the wire protocol...
78 # behavior of version 1 of the wire protocol...
79 # TODO return reasonable responses - not responses that overload the
79 # TODO return reasonable responses - not responses that overload the
80 # HTTP status line message for error reporting.
80 # HTTP status line message for error reporting.
81 try:
81 try:
82 checkperm(rctx, req, 'pull' if permission == b'ro' else 'push')
82 checkperm(rctx, req, 'pull' if permission == b'ro' else 'push')
83 except hgwebcommon.ErrorResponse as e:
83 except hgwebcommon.ErrorResponse as e:
84 res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e))
84 res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e))
85 for k, v in e.headers:
85 for k, v in e.headers:
86 res.headers[k] = v
86 res.headers[k] = v
87 res.setbodybytes('permission denied')
87 res.setbodybytes('permission denied')
88 return
88 return
89
89
90 # 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.
91 if command == b'debugreflect':
91 if command == b'debugreflect':
92 _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
92 _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
93 return
93 return
94
94
95 # Extra commands that we handle that aren't really wire protocol
95 # Extra commands that we handle that aren't really wire protocol
96 # commands. Think extra hard before making this hackery available to
96 # commands. Think extra hard before making this hackery available to
97 # extension.
97 # extension.
98 extracommands = {'multirequest'}
98 extracommands = {'multirequest'}
99
99
100 if command not in COMMANDS and command not in extracommands:
100 if command not in COMMANDS and command not in extracommands:
101 res.status = b'404 Not Found'
101 res.status = b'404 Not Found'
102 res.headers[b'Content-Type'] = b'text/plain'
102 res.headers[b'Content-Type'] = b'text/plain'
103 res.setbodybytes(_('unknown wire protocol command: %s\n') % command)
103 res.setbodybytes(_('unknown wire protocol command: %s\n') % command)
104 return
104 return
105
105
106 repo = rctx.repo
106 repo = rctx.repo
107 ui = repo.ui
107 ui = repo.ui
108
108
109 proto = httpv2protocolhandler(req, ui)
109 proto = httpv2protocolhandler(req, ui)
110
110
111 if (not COMMANDS.commandavailable(command, proto)
111 if (not COMMANDS.commandavailable(command, proto)
112 and command not in extracommands):
112 and command not in extracommands):
113 res.status = b'404 Not Found'
113 res.status = b'404 Not Found'
114 res.headers[b'Content-Type'] = b'text/plain'
114 res.headers[b'Content-Type'] = b'text/plain'
115 res.setbodybytes(_('invalid wire protocol command: %s') % command)
115 res.setbodybytes(_('invalid wire protocol command: %s') % command)
116 return
116 return
117
117
118 # TODO consider cases where proxies may add additional Accept headers.
118 # TODO consider cases where proxies may add additional Accept headers.
119 if req.headers.get(b'Accept') != FRAMINGTYPE:
119 if req.headers.get(b'Accept') != FRAMINGTYPE:
120 res.status = b'406 Not Acceptable'
120 res.status = b'406 Not Acceptable'
121 res.headers[b'Content-Type'] = b'text/plain'
121 res.headers[b'Content-Type'] = b'text/plain'
122 res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
122 res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
123 % FRAMINGTYPE)
123 % FRAMINGTYPE)
124 return
124 return
125
125
126 if req.headers.get(b'Content-Type') != FRAMINGTYPE:
126 if req.headers.get(b'Content-Type') != FRAMINGTYPE:
127 res.status = b'415 Unsupported Media Type'
127 res.status = b'415 Unsupported Media Type'
128 # TODO we should send a response with appropriate media type,
128 # TODO we should send a response with appropriate media type,
129 # since client does Accept it.
129 # since client does Accept it.
130 res.headers[b'Content-Type'] = b'text/plain'
130 res.headers[b'Content-Type'] = b'text/plain'
131 res.setbodybytes(_('client MUST send Content-Type header with '
131 res.setbodybytes(_('client MUST send Content-Type header with '
132 'value: %s\n') % FRAMINGTYPE)
132 'value: %s\n') % FRAMINGTYPE)
133 return
133 return
134
134
135 _processhttpv2request(ui, repo, req, res, permission, command, proto)
135 _processhttpv2request(ui, repo, req, res, permission, command, proto)
136
136
137 def _processhttpv2reflectrequest(ui, repo, req, res):
137 def _processhttpv2reflectrequest(ui, repo, req, res):
138 """Reads unified frame protocol request and dumps out state to client.
138 """Reads unified frame protocol request and dumps out state to client.
139
139
140 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.
141
141
142 Instead of routing the request through the normal dispatch mechanism,
142 Instead of routing the request through the normal dispatch mechanism,
143 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
144 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
145 client.
145 client.
146 """
146 """
147 import json
147 import json
148
148
149 # Reflection APIs have a history of being abused, accidentally disclosing
149 # Reflection APIs have a history of being abused, accidentally disclosing
150 # sensitive data, etc. So we have a config knob.
150 # sensitive data, etc. So we have a config knob.
151 if not ui.configbool('experimental', 'web.api.debugreflect'):
151 if not ui.configbool('experimental', 'web.api.debugreflect'):
152 res.status = b'404 Not Found'
152 res.status = b'404 Not Found'
153 res.headers[b'Content-Type'] = b'text/plain'
153 res.headers[b'Content-Type'] = b'text/plain'
154 res.setbodybytes(_('debugreflect service not available'))
154 res.setbodybytes(_('debugreflect service not available'))
155 return
155 return
156
156
157 # We assume we have a unified framing protocol request body.
157 # We assume we have a unified framing protocol request body.
158
158
159 reactor = wireprotoframing.serverreactor(ui)
159 reactor = wireprotoframing.serverreactor(ui)
160 states = []
160 states = []
161
161
162 while True:
162 while True:
163 frame = wireprotoframing.readframe(req.bodyfh)
163 frame = wireprotoframing.readframe(req.bodyfh)
164
164
165 if not frame:
165 if not frame:
166 states.append(b'received: <no frame>')
166 states.append(b'received: <no frame>')
167 break
167 break
168
168
169 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,
170 frame.requestid,
170 frame.requestid,
171 frame.payload))
171 frame.payload))
172
172
173 action, meta = reactor.onframerecv(frame)
173 action, meta = reactor.onframerecv(frame)
174 states.append(json.dumps((action, meta), sort_keys=True,
174 states.append(json.dumps((action, meta), sort_keys=True,
175 separators=(', ', ': ')))
175 separators=(', ', ': ')))
176
176
177 action, meta = reactor.oninputeof()
177 action, meta = reactor.oninputeof()
178 meta['action'] = action
178 meta['action'] = action
179 states.append(json.dumps(meta, sort_keys=True, separators=(', ',': ')))
179 states.append(json.dumps(meta, sort_keys=True, separators=(', ',': ')))
180
180
181 res.status = b'200 OK'
181 res.status = b'200 OK'
182 res.headers[b'Content-Type'] = b'text/plain'
182 res.headers[b'Content-Type'] = b'text/plain'
183 res.setbodybytes(b'\n'.join(states))
183 res.setbodybytes(b'\n'.join(states))
184
184
185 def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
185 def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
186 """Post-validation handler for HTTPv2 requests.
186 """Post-validation handler for HTTPv2 requests.
187
187
188 Called when the HTTP request contains unified frame-based protocol
188 Called when the HTTP request contains unified frame-based protocol
189 frames for evaluation.
189 frames for evaluation.
190 """
190 """
191 # 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
192 # 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
193 # for that so we can opt into full duplex mode.
193 # for that so we can opt into full duplex mode.
194 reactor = wireprotoframing.serverreactor(ui, deferoutput=True)
194 reactor = wireprotoframing.serverreactor(ui, deferoutput=True)
195 seencommand = False
195 seencommand = False
196
196
197 outstream = None
197 outstream = None
198
198
199 while True:
199 while True:
200 frame = wireprotoframing.readframe(req.bodyfh)
200 frame = wireprotoframing.readframe(req.bodyfh)
201 if not frame:
201 if not frame:
202 break
202 break
203
203
204 action, meta = reactor.onframerecv(frame)
204 action, meta = reactor.onframerecv(frame)
205
205
206 if action == 'wantframe':
206 if action == 'wantframe':
207 # Need more data before we can do anything.
207 # Need more data before we can do anything.
208 continue
208 continue
209 elif action == 'runcommand':
209 elif action == 'runcommand':
210 # Defer creating output stream because we need to wait for
210 # Defer creating output stream because we need to wait for
211 # protocol settings frames so proper encoding can be applied.
211 # protocol settings frames so proper encoding can be applied.
212 if not outstream:
212 if not outstream:
213 outstream = reactor.makeoutputstream()
213 outstream = reactor.makeoutputstream()
214
214
215 sentoutput = _httpv2runcommand(ui, repo, req, res, authedperm,
215 sentoutput = _httpv2runcommand(ui, repo, req, res, authedperm,
216 reqcommand, reactor, outstream,
216 reqcommand, reactor, outstream,
217 meta, issubsequent=seencommand)
217 meta, issubsequent=seencommand)
218
218
219 if sentoutput:
219 if sentoutput:
220 return
220 return
221
221
222 seencommand = True
222 seencommand = True
223
223
224 elif action == 'error':
224 elif action == 'error':
225 # TODO define proper error mechanism.
225 # TODO define proper error mechanism.
226 res.status = b'200 OK'
226 res.status = b'200 OK'
227 res.headers[b'Content-Type'] = b'text/plain'
227 res.headers[b'Content-Type'] = b'text/plain'
228 res.setbodybytes(meta['message'] + b'\n')
228 res.setbodybytes(meta['message'] + b'\n')
229 return
229 return
230 else:
230 else:
231 raise error.ProgrammingError(
231 raise error.ProgrammingError(
232 'unhandled action from frame processor: %s' % action)
232 'unhandled action from frame processor: %s' % action)
233
233
234 action, meta = reactor.oninputeof()
234 action, meta = reactor.oninputeof()
235 if action == 'sendframes':
235 if action == 'sendframes':
236 # We assume we haven't started sending the response yet. If we're
236 # We assume we haven't started sending the response yet. If we're
237 # wrong, the response type will raise an exception.
237 # wrong, the response type will raise an exception.
238 res.status = b'200 OK'
238 res.status = b'200 OK'
239 res.headers[b'Content-Type'] = FRAMINGTYPE
239 res.headers[b'Content-Type'] = FRAMINGTYPE
240 res.setbodygen(meta['framegen'])
240 res.setbodygen(meta['framegen'])
241 elif action == 'noop':
241 elif action == 'noop':
242 pass
242 pass
243 else:
243 else:
244 raise error.ProgrammingError('unhandled action from frame processor: %s'
244 raise error.ProgrammingError('unhandled action from frame processor: %s'
245 % action)
245 % action)
246
246
247 def _httpv2runcommand(ui, repo, req, res, authedperm, reqcommand, reactor,
247 def _httpv2runcommand(ui, repo, req, res, authedperm, reqcommand, reactor,
248 outstream, command, issubsequent):
248 outstream, command, issubsequent):
249 """Dispatch a wire protocol command made from HTTPv2 requests.
249 """Dispatch a wire protocol command made from HTTPv2 requests.
250
250
251 The authenticated permission (``authedperm``) along with the original
251 The authenticated permission (``authedperm``) along with the original
252 command from the URL (``reqcommand``) are passed in.
252 command from the URL (``reqcommand``) are passed in.
253 """
253 """
254 # We already validated that the session has permissions to perform the
254 # We already validated that the session has permissions to perform the
255 # actions in ``authedperm``. In the unified frame protocol, the canonical
255 # actions in ``authedperm``. In the unified frame protocol, the canonical
256 # command to run is expressed in a frame. However, the URL also requested
256 # command to run is expressed in a frame. However, the URL also requested
257 # to run a specific command. We need to be careful that the command we
257 # to run a specific command. We need to be careful that the command we
258 # run doesn't have permissions requirements greater than what was granted
258 # run doesn't have permissions requirements greater than what was granted
259 # by ``authedperm``.
259 # by ``authedperm``.
260 #
260 #
261 # Our rule for this is we only allow one command per HTTP request and
261 # Our rule for this is we only allow one command per HTTP request and
262 # that command must match the command in the URL. However, we make
262 # that command must match the command in the URL. However, we make
263 # an exception for the ``multirequest`` URL. This URL is allowed to
263 # an exception for the ``multirequest`` URL. This URL is allowed to
264 # execute multiple commands. We double check permissions of each command
264 # execute multiple commands. We double check permissions of each command
265 # as it is invoked to ensure there is no privilege escalation.
265 # as it is invoked to ensure there is no privilege escalation.
266 # TODO consider allowing multiple commands to regular command URLs
266 # TODO consider allowing multiple commands to regular command URLs
267 # iff each command is the same.
267 # iff each command is the same.
268
268
269 proto = httpv2protocolhandler(req, ui, args=command['args'])
269 proto = httpv2protocolhandler(req, ui, args=command['args'])
270
270
271 if reqcommand == b'multirequest':
271 if reqcommand == b'multirequest':
272 if not COMMANDS.commandavailable(command['command'], proto):
272 if not COMMANDS.commandavailable(command['command'], proto):
273 # TODO proper error mechanism
273 # TODO proper error mechanism
274 res.status = b'200 OK'
274 res.status = b'200 OK'
275 res.headers[b'Content-Type'] = b'text/plain'
275 res.headers[b'Content-Type'] = b'text/plain'
276 res.setbodybytes(_('wire protocol command not available: %s') %
276 res.setbodybytes(_('wire protocol command not available: %s') %
277 command['command'])
277 command['command'])
278 return True
278 return True
279
279
280 # TODO don't use assert here, since it may be elided by -O.
280 # TODO don't use assert here, since it may be elided by -O.
281 assert authedperm in (b'ro', b'rw')
281 assert authedperm in (b'ro', b'rw')
282 wirecommand = COMMANDS[command['command']]
282 wirecommand = COMMANDS[command['command']]
283 assert wirecommand.permission in ('push', 'pull')
283 assert wirecommand.permission in ('push', 'pull')
284
284
285 if authedperm == b'ro' and wirecommand.permission != 'pull':
285 if authedperm == b'ro' and wirecommand.permission != 'pull':
286 # TODO proper error mechanism
286 # TODO proper error mechanism
287 res.status = b'403 Forbidden'
287 res.status = b'403 Forbidden'
288 res.headers[b'Content-Type'] = b'text/plain'
288 res.headers[b'Content-Type'] = b'text/plain'
289 res.setbodybytes(_('insufficient permissions to execute '
289 res.setbodybytes(_('insufficient permissions to execute '
290 'command: %s') % command['command'])
290 'command: %s') % command['command'])
291 return True
291 return True
292
292
293 # TODO should we also call checkperm() here? Maybe not if we're going
293 # TODO should we also call checkperm() here? Maybe not if we're going
294 # to overhaul that API. The granted scope from the URL check should
294 # to overhaul that API. The granted scope from the URL check should
295 # be good enough.
295 # be good enough.
296
296
297 else:
297 else:
298 # Don't allow multiple commands outside of ``multirequest`` URL.
298 # Don't allow multiple commands outside of ``multirequest`` URL.
299 if issubsequent:
299 if issubsequent:
300 # TODO proper error mechanism
300 # TODO proper error mechanism
301 res.status = b'200 OK'
301 res.status = b'200 OK'
302 res.headers[b'Content-Type'] = b'text/plain'
302 res.headers[b'Content-Type'] = b'text/plain'
303 res.setbodybytes(_('multiple commands cannot be issued to this '
303 res.setbodybytes(_('multiple commands cannot be issued to this '
304 'URL'))
304 'URL'))
305 return True
305 return True
306
306
307 if reqcommand != command['command']:
307 if reqcommand != command['command']:
308 # TODO define proper error mechanism
308 # TODO define proper error mechanism
309 res.status = b'200 OK'
309 res.status = b'200 OK'
310 res.headers[b'Content-Type'] = b'text/plain'
310 res.headers[b'Content-Type'] = b'text/plain'
311 res.setbodybytes(_('command in frame must match command in URL'))
311 res.setbodybytes(_('command in frame must match command in URL'))
312 return True
312 return True
313
313
314 res.status = b'200 OK'
314 res.status = b'200 OK'
315 res.headers[b'Content-Type'] = FRAMINGTYPE
315 res.headers[b'Content-Type'] = FRAMINGTYPE
316
316
317 try:
317 try:
318 objs = dispatch(repo, proto, command['command'], command['redirect'])
318 objs = dispatch(repo, proto, command['command'], command['redirect'])
319
319
320 action, meta = reactor.oncommandresponsereadyobjects(
320 action, meta = reactor.oncommandresponsereadyobjects(
321 outstream, command['requestid'], objs)
321 outstream, command['requestid'], objs)
322
322
323 except error.WireprotoCommandError as e:
323 except error.WireprotoCommandError as e:
324 action, meta = reactor.oncommanderror(
324 action, meta = reactor.oncommanderror(
325 outstream, command['requestid'], e.message, e.messageargs)
325 outstream, command['requestid'], e.message, e.messageargs)
326
326
327 except Exception as e:
327 except Exception as e:
328 action, meta = reactor.onservererror(
328 action, meta = reactor.onservererror(
329 outstream, command['requestid'],
329 outstream, command['requestid'],
330 _('exception when invoking command: %s') %
330 _('exception when invoking command: %s') %
331 stringutil.forcebytestr(e))
331 stringutil.forcebytestr(e))
332
332
333 if action == 'sendframes':
333 if action == 'sendframes':
334 res.setbodygen(meta['framegen'])
334 res.setbodygen(meta['framegen'])
335 return True
335 return True
336 elif action == 'noop':
336 elif action == 'noop':
337 return False
337 return False
338 else:
338 else:
339 raise error.ProgrammingError('unhandled event from reactor: %s' %
339 raise error.ProgrammingError('unhandled event from reactor: %s' %
340 action)
340 action)
341
341
342 def getdispatchrepo(repo, proto, command):
342 def getdispatchrepo(repo, proto, command):
343 return repo.filtered('served')
343 return repo.filtered('served')
344
344
345 def dispatch(repo, proto, command, redirect):
345 def dispatch(repo, proto, command, redirect):
346 """Run a wire protocol command.
346 """Run a wire protocol command.
347
347
348 Returns an iterable of objects that will be sent to the client.
348 Returns an iterable of objects that will be sent to the client.
349 """
349 """
350 repo = getdispatchrepo(repo, proto, command)
350 repo = getdispatchrepo(repo, proto, command)
351
351
352 entry = COMMANDS[command]
352 entry = COMMANDS[command]
353 func = entry.func
353 func = entry.func
354 spec = entry.args
354 spec = entry.args
355
355
356 args = proto.getargs(spec)
356 args = proto.getargs(spec)
357
357
358 # There is some duplicate boilerplate code here for calling the command and
358 # There is some duplicate boilerplate code here for calling the command and
359 # emitting objects. It is either that or a lot of indented code that looks
359 # emitting objects. It is either that or a lot of indented code that looks
360 # like a pyramid (since there are a lot of code paths that result in not
360 # like a pyramid (since there are a lot of code paths that result in not
361 # using the cacher).
361 # using the cacher).
362 callcommand = lambda: func(repo, proto, **pycompat.strkwargs(args))
362 callcommand = lambda: func(repo, proto, **pycompat.strkwargs(args))
363
363
364 # Request is not cacheable. Don't bother instantiating a cacher.
364 # Request is not cacheable. Don't bother instantiating a cacher.
365 if not entry.cachekeyfn:
365 if not entry.cachekeyfn:
366 for o in callcommand():
366 for o in callcommand():
367 yield o
367 yield o
368 return
368 return
369
369
370 if redirect:
370 if redirect:
371 redirecttargets = redirect[b'targets']
371 redirecttargets = redirect[b'targets']
372 redirecthashes = redirect[b'hashes']
372 redirecthashes = redirect[b'hashes']
373 else:
373 else:
374 redirecttargets = []
374 redirecttargets = []
375 redirecthashes = []
375 redirecthashes = []
376
376
377 cacher = makeresponsecacher(repo, proto, command, args,
377 cacher = makeresponsecacher(repo, proto, command, args,
378 cborutil.streamencode,
378 cborutil.streamencode,
379 redirecttargets=redirecttargets,
379 redirecttargets=redirecttargets,
380 redirecthashes=redirecthashes)
380 redirecthashes=redirecthashes)
381
381
382 # But we have no cacher. Do default handling.
382 # But we have no cacher. Do default handling.
383 if not cacher:
383 if not cacher:
384 for o in callcommand():
384 for o in callcommand():
385 yield o
385 yield o
386 return
386 return
387
387
388 with cacher:
388 with cacher:
389 cachekey = entry.cachekeyfn(repo, proto, cacher, **args)
389 cachekey = entry.cachekeyfn(repo, proto, cacher, **args)
390
390
391 # No cache key or the cacher doesn't like it. Do default handling.
391 # No cache key or the cacher doesn't like it. Do default handling.
392 if cachekey is None or not cacher.setcachekey(cachekey):
392 if cachekey is None or not cacher.setcachekey(cachekey):
393 for o in callcommand():
393 for o in callcommand():
394 yield o
394 yield o
395 return
395 return
396
396
397 # Serve it from the cache, if possible.
397 # Serve it from the cache, if possible.
398 cached = cacher.lookup()
398 cached = cacher.lookup()
399
399
400 if cached:
400 if cached:
401 for o in cached['objs']:
401 for o in cached['objs']:
402 yield o
402 yield o
403 return
403 return
404
404
405 # Else call the command and feed its output into the cacher, allowing
405 # Else call the command and feed its output into the cacher, allowing
406 # the cacher to buffer/mutate objects as it desires.
406 # the cacher to buffer/mutate objects as it desires.
407 for o in callcommand():
407 for o in callcommand():
408 for o in cacher.onobject(o):
408 for o in cacher.onobject(o):
409 yield o
409 yield o
410
410
411 for o in cacher.onfinished():
411 for o in cacher.onfinished():
412 yield o
412 yield o
413
413
414 @interfaceutil.implementer(wireprototypes.baseprotocolhandler)
414 @interfaceutil.implementer(wireprototypes.baseprotocolhandler)
415 class httpv2protocolhandler(object):
415 class httpv2protocolhandler(object):
416 def __init__(self, req, ui, args=None):
416 def __init__(self, req, ui, args=None):
417 self._req = req
417 self._req = req
418 self._ui = ui
418 self._ui = ui
419 self._args = args
419 self._args = args
420
420
421 @property
421 @property
422 def name(self):
422 def name(self):
423 return HTTP_WIREPROTO_V2
423 return HTTP_WIREPROTO_V2
424
424
425 def getargs(self, args):
425 def getargs(self, args):
426 # First look for args that were passed but aren't registered on this
426 # First look for args that were passed but aren't registered on this
427 # command.
427 # command.
428 extra = set(self._args) - set(args)
428 extra = set(self._args) - set(args)
429 if extra:
429 if extra:
430 raise error.WireprotoCommandError(
430 raise error.WireprotoCommandError(
431 'unsupported argument to command: %s' %
431 'unsupported argument to command: %s' %
432 ', '.join(sorted(extra)))
432 ', '.join(sorted(extra)))
433
433
434 # And look for required arguments that are missing.
434 # And look for required arguments that are missing.
435 missing = {a for a in args if args[a]['required']} - set(self._args)
435 missing = {a for a in args if args[a]['required']} - set(self._args)
436
436
437 if missing:
437 if missing:
438 raise error.WireprotoCommandError(
438 raise error.WireprotoCommandError(
439 'missing required arguments: %s' % ', '.join(sorted(missing)))
439 'missing required arguments: %s' % ', '.join(sorted(missing)))
440
440
441 # Now derive the arguments to pass to the command, taking into
441 # Now derive the arguments to pass to the command, taking into
442 # account the arguments specified by the client.
442 # account the arguments specified by the client.
443 data = {}
443 data = {}
444 for k, meta in sorted(args.items()):
444 for k, meta in sorted(args.items()):
445 # This argument wasn't passed by the client.
445 # This argument wasn't passed by the client.
446 if k not in self._args:
446 if k not in self._args:
447 data[k] = meta['default']()
447 data[k] = meta['default']()
448 continue
448 continue
449
449
450 v = self._args[k]
450 v = self._args[k]
451
451
452 # Sets may be expressed as lists. Silently normalize.
452 # Sets may be expressed as lists. Silently normalize.
453 if meta['type'] == 'set' and isinstance(v, list):
453 if meta['type'] == 'set' and isinstance(v, list):
454 v = set(v)
454 v = set(v)
455
455
456 # TODO consider more/stronger type validation.
456 # TODO consider more/stronger type validation.
457
457
458 data[k] = v
458 data[k] = v
459
459
460 return data
460 return data
461
461
462 def getprotocaps(self):
462 def getprotocaps(self):
463 # Protocol capabilities are currently not implemented for HTTP V2.
463 # Protocol capabilities are currently not implemented for HTTP V2.
464 return set()
464 return set()
465
465
466 def getpayload(self):
466 def getpayload(self):
467 raise NotImplementedError
467 raise NotImplementedError
468
468
469 @contextlib.contextmanager
469 @contextlib.contextmanager
470 def mayberedirectstdio(self):
470 def mayberedirectstdio(self):
471 raise NotImplementedError
471 raise NotImplementedError
472
472
473 def client(self):
473 def client(self):
474 raise NotImplementedError
474 raise NotImplementedError
475
475
476 def addcapabilities(self, repo, caps):
476 def addcapabilities(self, repo, caps):
477 return caps
477 return caps
478
478
479 def checkperm(self, perm):
479 def checkperm(self, perm):
480 raise NotImplementedError
480 raise NotImplementedError
481
481
482 def httpv2apidescriptor(req, repo):
482 def httpv2apidescriptor(req, repo):
483 proto = httpv2protocolhandler(req, repo.ui)
483 proto = httpv2protocolhandler(req, repo.ui)
484
484
485 return _capabilitiesv2(repo, proto)
485 return _capabilitiesv2(repo, proto)
486
486
487 def _capabilitiesv2(repo, proto):
487 def _capabilitiesv2(repo, proto):
488 """Obtain the set of capabilities for version 2 transports.
488 """Obtain the set of capabilities for version 2 transports.
489
489
490 These capabilities are distinct from the capabilities for version 1
490 These capabilities are distinct from the capabilities for version 1
491 transports.
491 transports.
492 """
492 """
493 caps = {
493 caps = {
494 'commands': {},
494 'commands': {},
495 'framingmediatypes': [FRAMINGTYPE],
495 'framingmediatypes': [FRAMINGTYPE],
496 'pathfilterprefixes': set(narrowspec.VALID_PREFIXES),
496 'pathfilterprefixes': set(narrowspec.VALID_PREFIXES),
497 }
497 }
498
498
499 for command, entry in COMMANDS.items():
499 for command, entry in COMMANDS.items():
500 args = {}
500 args = {}
501
501
502 for arg, meta in entry.args.items():
502 for arg, meta in entry.args.items():
503 args[arg] = {
503 args[arg] = {
504 # TODO should this be a normalized type using CBOR's
504 # TODO should this be a normalized type using CBOR's
505 # terminology?
505 # terminology?
506 b'type': meta['type'],
506 b'type': meta['type'],
507 b'required': meta['required'],
507 b'required': meta['required'],
508 }
508 }
509
509
510 if not meta['required']:
510 if not meta['required']:
511 args[arg][b'default'] = meta['default']()
511 args[arg][b'default'] = meta['default']()
512
512
513 if meta['validvalues']:
513 if meta['validvalues']:
514 args[arg][b'validvalues'] = meta['validvalues']
514 args[arg][b'validvalues'] = meta['validvalues']
515
515
516 caps['commands'][command] = {
516 caps['commands'][command] = {
517 'args': args,
517 'args': args,
518 'permissions': [entry.permission],
518 'permissions': [entry.permission],
519 }
519 }
520
520
521 if entry.extracapabilitiesfn:
522 extracaps = entry.extracapabilitiesfn(repo, proto)
523 caps['commands'][command].update(extracaps)
524
521 caps['rawrepoformats'] = sorted(repo.requirements &
525 caps['rawrepoformats'] = sorted(repo.requirements &
522 repo.supportedformats)
526 repo.supportedformats)
523
527
524 targets = getadvertisedredirecttargets(repo, proto)
528 targets = getadvertisedredirecttargets(repo, proto)
525 if targets:
529 if targets:
526 caps[b'redirect'] = {
530 caps[b'redirect'] = {
527 b'targets': [],
531 b'targets': [],
528 b'hashes': [b'sha256', b'sha1'],
532 b'hashes': [b'sha256', b'sha1'],
529 }
533 }
530
534
531 for target in targets:
535 for target in targets:
532 entry = {
536 entry = {
533 b'name': target['name'],
537 b'name': target['name'],
534 b'protocol': target['protocol'],
538 b'protocol': target['protocol'],
535 b'uris': target['uris'],
539 b'uris': target['uris'],
536 }
540 }
537
541
538 for key in ('snirequired', 'tlsversions'):
542 for key in ('snirequired', 'tlsversions'):
539 if key in target:
543 if key in target:
540 entry[key] = target[key]
544 entry[key] = target[key]
541
545
542 caps[b'redirect'][b'targets'].append(entry)
546 caps[b'redirect'][b'targets'].append(entry)
543
547
544 return proto.addcapabilities(repo, caps)
548 return proto.addcapabilities(repo, caps)
545
549
546 def getadvertisedredirecttargets(repo, proto):
550 def getadvertisedredirecttargets(repo, proto):
547 """Obtain a list of content redirect targets.
551 """Obtain a list of content redirect targets.
548
552
549 Returns a list containing potential redirect targets that will be
553 Returns a list containing potential redirect targets that will be
550 advertised in capabilities data. Each dict MUST have the following
554 advertised in capabilities data. Each dict MUST have the following
551 keys:
555 keys:
552
556
553 name
557 name
554 The name of this redirect target. This is the identifier clients use
558 The name of this redirect target. This is the identifier clients use
555 to refer to a target. It is transferred as part of every command
559 to refer to a target. It is transferred as part of every command
556 request.
560 request.
557
561
558 protocol
562 protocol
559 Network protocol used by this target. Typically this is the string
563 Network protocol used by this target. Typically this is the string
560 in front of the ``://`` in a URL. e.g. ``https``.
564 in front of the ``://`` in a URL. e.g. ``https``.
561
565
562 uris
566 uris
563 List of representative URIs for this target. Clients can use the
567 List of representative URIs for this target. Clients can use the
564 URIs to test parsing for compatibility or for ordering preference
568 URIs to test parsing for compatibility or for ordering preference
565 for which target to use.
569 for which target to use.
566
570
567 The following optional keys are recognized:
571 The following optional keys are recognized:
568
572
569 snirequired
573 snirequired
570 Bool indicating if Server Name Indication (SNI) is required to
574 Bool indicating if Server Name Indication (SNI) is required to
571 connect to this target.
575 connect to this target.
572
576
573 tlsversions
577 tlsversions
574 List of bytes indicating which TLS versions are supported by this
578 List of bytes indicating which TLS versions are supported by this
575 target.
579 target.
576
580
577 By default, clients reflect the target order advertised by servers
581 By default, clients reflect the target order advertised by servers
578 and servers will use the first client-advertised target when picking
582 and servers will use the first client-advertised target when picking
579 a redirect target. So targets should be advertised in the order the
583 a redirect target. So targets should be advertised in the order the
580 server prefers they be used.
584 server prefers they be used.
581 """
585 """
582 return []
586 return []
583
587
584 def wireprotocommand(name, args=None, permission='push', cachekeyfn=None):
588 def wireprotocommand(name, args=None, permission='push', cachekeyfn=None,
589 extracapabilitiesfn=None):
585 """Decorator to declare a wire protocol command.
590 """Decorator to declare a wire protocol command.
586
591
587 ``name`` is the name of the wire protocol command being provided.
592 ``name`` is the name of the wire protocol command being provided.
588
593
589 ``args`` is a dict defining arguments accepted by the command. Keys are
594 ``args`` is a dict defining arguments accepted by the command. Keys are
590 the argument name. Values are dicts with the following keys:
595 the argument name. Values are dicts with the following keys:
591
596
592 ``type``
597 ``type``
593 The argument data type. Must be one of the following string
598 The argument data type. Must be one of the following string
594 literals: ``bytes``, ``int``, ``list``, ``dict``, ``set``,
599 literals: ``bytes``, ``int``, ``list``, ``dict``, ``set``,
595 or ``bool``.
600 or ``bool``.
596
601
597 ``default``
602 ``default``
598 A callable returning the default value for this argument. If not
603 A callable returning the default value for this argument. If not
599 specified, ``None`` will be the default value.
604 specified, ``None`` will be the default value.
600
605
601 ``example``
606 ``example``
602 An example value for this argument.
607 An example value for this argument.
603
608
604 ``validvalues``
609 ``validvalues``
605 Set of recognized values for this argument.
610 Set of recognized values for this argument.
606
611
607 ``permission`` defines the permission type needed to run this command.
612 ``permission`` defines the permission type needed to run this command.
608 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
613 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
609 respectively. Default is to assume command requires ``push`` permissions
614 respectively. Default is to assume command requires ``push`` permissions
610 because otherwise commands not declaring their permissions could modify
615 because otherwise commands not declaring their permissions could modify
611 a repository that is supposed to be read-only.
616 a repository that is supposed to be read-only.
612
617
613 ``cachekeyfn`` defines an optional callable that can derive the
618 ``cachekeyfn`` defines an optional callable that can derive the
614 cache key for this request.
619 cache key for this request.
615
620
621 ``extracapabilitiesfn`` defines an optional callable that defines extra
622 command capabilities/parameters that are advertised next to the command
623 in the capabilities data structure describing the server. The callable
624 receives as arguments the repository and protocol objects. It returns
625 a dict of extra fields to add to the command descriptor.
626
616 Wire protocol commands are generators of objects to be serialized and
627 Wire protocol commands are generators of objects to be serialized and
617 sent to the client.
628 sent to the client.
618
629
619 If a command raises an uncaught exception, this will be translated into
630 If a command raises an uncaught exception, this will be translated into
620 a command error.
631 a command error.
621
632
622 All commands can opt in to being cacheable by defining a function
633 All commands can opt in to being cacheable by defining a function
623 (``cachekeyfn``) that is called to derive a cache key. This function
634 (``cachekeyfn``) that is called to derive a cache key. This function
624 receives the same arguments as the command itself plus a ``cacher``
635 receives the same arguments as the command itself plus a ``cacher``
625 argument containing the active cacher for the request and returns a bytes
636 argument containing the active cacher for the request and returns a bytes
626 containing the key in a cache the response to this command may be cached
637 containing the key in a cache the response to this command may be cached
627 under.
638 under.
628 """
639 """
629 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
640 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
630 if v['version'] == 2}
641 if v['version'] == 2}
631
642
632 if permission not in ('push', 'pull'):
643 if permission not in ('push', 'pull'):
633 raise error.ProgrammingError('invalid wire protocol permission; '
644 raise error.ProgrammingError('invalid wire protocol permission; '
634 'got %s; expected "push" or "pull"' %
645 'got %s; expected "push" or "pull"' %
635 permission)
646 permission)
636
647
637 if args is None:
648 if args is None:
638 args = {}
649 args = {}
639
650
640 if not isinstance(args, dict):
651 if not isinstance(args, dict):
641 raise error.ProgrammingError('arguments for version 2 commands '
652 raise error.ProgrammingError('arguments for version 2 commands '
642 'must be declared as dicts')
653 'must be declared as dicts')
643
654
644 for arg, meta in args.items():
655 for arg, meta in args.items():
645 if arg == '*':
656 if arg == '*':
646 raise error.ProgrammingError('* argument name not allowed on '
657 raise error.ProgrammingError('* argument name not allowed on '
647 'version 2 commands')
658 'version 2 commands')
648
659
649 if not isinstance(meta, dict):
660 if not isinstance(meta, dict):
650 raise error.ProgrammingError('arguments for version 2 commands '
661 raise error.ProgrammingError('arguments for version 2 commands '
651 'must declare metadata as a dict')
662 'must declare metadata as a dict')
652
663
653 if 'type' not in meta:
664 if 'type' not in meta:
654 raise error.ProgrammingError('%s argument for command %s does not '
665 raise error.ProgrammingError('%s argument for command %s does not '
655 'declare type field' % (arg, name))
666 'declare type field' % (arg, name))
656
667
657 if meta['type'] not in ('bytes', 'int', 'list', 'dict', 'set', 'bool'):
668 if meta['type'] not in ('bytes', 'int', 'list', 'dict', 'set', 'bool'):
658 raise error.ProgrammingError('%s argument for command %s has '
669 raise error.ProgrammingError('%s argument for command %s has '
659 'illegal type: %s' % (arg, name,
670 'illegal type: %s' % (arg, name,
660 meta['type']))
671 meta['type']))
661
672
662 if 'example' not in meta:
673 if 'example' not in meta:
663 raise error.ProgrammingError('%s argument for command %s does not '
674 raise error.ProgrammingError('%s argument for command %s does not '
664 'declare example field' % (arg, name))
675 'declare example field' % (arg, name))
665
676
666 meta['required'] = 'default' not in meta
677 meta['required'] = 'default' not in meta
667
678
668 meta.setdefault('default', lambda: None)
679 meta.setdefault('default', lambda: None)
669 meta.setdefault('validvalues', None)
680 meta.setdefault('validvalues', None)
670
681
671 def register(func):
682 def register(func):
672 if name in COMMANDS:
683 if name in COMMANDS:
673 raise error.ProgrammingError('%s command already registered '
684 raise error.ProgrammingError('%s command already registered '
674 'for version 2' % name)
685 'for version 2' % name)
675
686
676 COMMANDS[name] = wireprototypes.commandentry(
687 COMMANDS[name] = wireprototypes.commandentry(
677 func, args=args, transports=transports, permission=permission,
688 func, args=args, transports=transports, permission=permission,
678 cachekeyfn=cachekeyfn)
689 cachekeyfn=cachekeyfn, extracapabilitiesfn=extracapabilitiesfn)
679
690
680 return func
691 return func
681
692
682 return register
693 return register
683
694
684 def makecommandcachekeyfn(command, localversion=None, allargs=False):
695 def makecommandcachekeyfn(command, localversion=None, allargs=False):
685 """Construct a cache key derivation function with common features.
696 """Construct a cache key derivation function with common features.
686
697
687 By default, the cache key is a hash of:
698 By default, the cache key is a hash of:
688
699
689 * The command name.
700 * The command name.
690 * A global cache version number.
701 * A global cache version number.
691 * A local cache version number (passed via ``localversion``).
702 * A local cache version number (passed via ``localversion``).
692 * All the arguments passed to the command.
703 * All the arguments passed to the command.
693 * The media type used.
704 * The media type used.
694 * Wire protocol version string.
705 * Wire protocol version string.
695 * The repository path.
706 * The repository path.
696 """
707 """
697 if not allargs:
708 if not allargs:
698 raise error.ProgrammingError('only allargs=True is currently supported')
709 raise error.ProgrammingError('only allargs=True is currently supported')
699
710
700 if localversion is None:
711 if localversion is None:
701 raise error.ProgrammingError('must set localversion argument value')
712 raise error.ProgrammingError('must set localversion argument value')
702
713
703 def cachekeyfn(repo, proto, cacher, **args):
714 def cachekeyfn(repo, proto, cacher, **args):
704 spec = COMMANDS[command]
715 spec = COMMANDS[command]
705
716
706 # Commands that mutate the repo can not be cached.
717 # Commands that mutate the repo can not be cached.
707 if spec.permission == 'push':
718 if spec.permission == 'push':
708 return None
719 return None
709
720
710 # TODO config option to disable caching.
721 # TODO config option to disable caching.
711
722
712 # Our key derivation strategy is to construct a data structure
723 # Our key derivation strategy is to construct a data structure
713 # holding everything that could influence cacheability and to hash
724 # holding everything that could influence cacheability and to hash
714 # the CBOR representation of that. Using CBOR seems like it might
725 # the CBOR representation of that. Using CBOR seems like it might
715 # be overkill. However, simpler hashing mechanisms are prone to
726 # be overkill. However, simpler hashing mechanisms are prone to
716 # duplicate input issues. e.g. if you just concatenate two values,
727 # duplicate input issues. e.g. if you just concatenate two values,
717 # "foo"+"bar" is identical to "fo"+"obar". Using CBOR provides
728 # "foo"+"bar" is identical to "fo"+"obar". Using CBOR provides
718 # "padding" between values and prevents these problems.
729 # "padding" between values and prevents these problems.
719
730
720 # Seed the hash with various data.
731 # Seed the hash with various data.
721 state = {
732 state = {
722 # To invalidate all cache keys.
733 # To invalidate all cache keys.
723 b'globalversion': GLOBAL_CACHE_VERSION,
734 b'globalversion': GLOBAL_CACHE_VERSION,
724 # More granular cache key invalidation.
735 # More granular cache key invalidation.
725 b'localversion': localversion,
736 b'localversion': localversion,
726 # Cache keys are segmented by command.
737 # Cache keys are segmented by command.
727 b'command': pycompat.sysbytes(command),
738 b'command': pycompat.sysbytes(command),
728 # Throw in the media type and API version strings so changes
739 # Throw in the media type and API version strings so changes
729 # to exchange semantics invalid cache.
740 # to exchange semantics invalid cache.
730 b'mediatype': FRAMINGTYPE,
741 b'mediatype': FRAMINGTYPE,
731 b'version': HTTP_WIREPROTO_V2,
742 b'version': HTTP_WIREPROTO_V2,
732 # So same requests for different repos don't share cache keys.
743 # So same requests for different repos don't share cache keys.
733 b'repo': repo.root,
744 b'repo': repo.root,
734 }
745 }
735
746
736 # The arguments passed to us will have already been normalized.
747 # The arguments passed to us will have already been normalized.
737 # Default values will be set, etc. This is important because it
748 # Default values will be set, etc. This is important because it
738 # means that it doesn't matter if clients send an explicit argument
749 # means that it doesn't matter if clients send an explicit argument
739 # or rely on the default value: it will all normalize to the same
750 # or rely on the default value: it will all normalize to the same
740 # set of arguments on the server and therefore the same cache key.
751 # set of arguments on the server and therefore the same cache key.
741 #
752 #
742 # Arguments by their very nature must support being encoded to CBOR.
753 # Arguments by their very nature must support being encoded to CBOR.
743 # And the CBOR encoder is deterministic. So we hash the arguments
754 # And the CBOR encoder is deterministic. So we hash the arguments
744 # by feeding the CBOR of their representation into the hasher.
755 # by feeding the CBOR of their representation into the hasher.
745 if allargs:
756 if allargs:
746 state[b'args'] = pycompat.byteskwargs(args)
757 state[b'args'] = pycompat.byteskwargs(args)
747
758
748 cacher.adjustcachekeystate(state)
759 cacher.adjustcachekeystate(state)
749
760
750 hasher = hashlib.sha1()
761 hasher = hashlib.sha1()
751 for chunk in cborutil.streamencode(state):
762 for chunk in cborutil.streamencode(state):
752 hasher.update(chunk)
763 hasher.update(chunk)
753
764
754 return pycompat.sysbytes(hasher.hexdigest())
765 return pycompat.sysbytes(hasher.hexdigest())
755
766
756 return cachekeyfn
767 return cachekeyfn
757
768
758 def makeresponsecacher(repo, proto, command, args, objencoderfn,
769 def makeresponsecacher(repo, proto, command, args, objencoderfn,
759 redirecttargets, redirecthashes):
770 redirecttargets, redirecthashes):
760 """Construct a cacher for a cacheable command.
771 """Construct a cacher for a cacheable command.
761
772
762 Returns an ``iwireprotocolcommandcacher`` instance.
773 Returns an ``iwireprotocolcommandcacher`` instance.
763
774
764 Extensions can monkeypatch this function to provide custom caching
775 Extensions can monkeypatch this function to provide custom caching
765 backends.
776 backends.
766 """
777 """
767 return None
778 return None
768
779
769 @wireprotocommand('branchmap', permission='pull')
780 @wireprotocommand('branchmap', permission='pull')
770 def branchmapv2(repo, proto):
781 def branchmapv2(repo, proto):
771 yield {encoding.fromlocal(k): v
782 yield {encoding.fromlocal(k): v
772 for k, v in repo.branchmap().iteritems()}
783 for k, v in repo.branchmap().iteritems()}
773
784
774 @wireprotocommand('capabilities', permission='pull')
785 @wireprotocommand('capabilities', permission='pull')
775 def capabilitiesv2(repo, proto):
786 def capabilitiesv2(repo, proto):
776 yield _capabilitiesv2(repo, proto)
787 yield _capabilitiesv2(repo, proto)
777
788
778 @wireprotocommand(
789 @wireprotocommand(
779 'changesetdata',
790 'changesetdata',
780 args={
791 args={
781 'noderange': {
792 'noderange': {
782 'type': 'list',
793 'type': 'list',
783 'default': lambda: None,
794 'default': lambda: None,
784 'example': [[b'0123456...'], [b'abcdef...']],
795 'example': [[b'0123456...'], [b'abcdef...']],
785 },
796 },
786 'nodes': {
797 'nodes': {
787 'type': 'list',
798 'type': 'list',
788 'default': lambda: None,
799 'default': lambda: None,
789 'example': [b'0123456...'],
800 'example': [b'0123456...'],
790 },
801 },
791 'nodesdepth': {
802 'nodesdepth': {
792 'type': 'int',
803 'type': 'int',
793 'default': lambda: None,
804 'default': lambda: None,
794 'example': 10,
805 'example': 10,
795 },
806 },
796 'fields': {
807 'fields': {
797 'type': 'set',
808 'type': 'set',
798 'default': set,
809 'default': set,
799 'example': {b'parents', b'revision'},
810 'example': {b'parents', b'revision'},
800 'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
811 'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
801 },
812 },
802 },
813 },
803 permission='pull')
814 permission='pull')
804 def changesetdata(repo, proto, noderange, nodes, nodesdepth, fields):
815 def changesetdata(repo, proto, noderange, nodes, nodesdepth, fields):
805 # TODO look for unknown fields and abort when they can't be serviced.
816 # TODO look for unknown fields and abort when they can't be serviced.
806 # This could probably be validated by dispatcher using validvalues.
817 # This could probably be validated by dispatcher using validvalues.
807
818
808 if noderange is None and nodes is None:
819 if noderange is None and nodes is None:
809 raise error.WireprotoCommandError(
820 raise error.WireprotoCommandError(
810 'noderange or nodes must be defined')
821 'noderange or nodes must be defined')
811
822
812 if nodesdepth is not None and nodes is None:
823 if nodesdepth is not None and nodes is None:
813 raise error.WireprotoCommandError(
824 raise error.WireprotoCommandError(
814 'nodesdepth requires the nodes argument')
825 'nodesdepth requires the nodes argument')
815
826
816 if noderange is not None:
827 if noderange is not None:
817 if len(noderange) != 2:
828 if len(noderange) != 2:
818 raise error.WireprotoCommandError(
829 raise error.WireprotoCommandError(
819 'noderange must consist of 2 elements')
830 'noderange must consist of 2 elements')
820
831
821 if not noderange[1]:
832 if not noderange[1]:
822 raise error.WireprotoCommandError(
833 raise error.WireprotoCommandError(
823 'heads in noderange request cannot be empty')
834 'heads in noderange request cannot be empty')
824
835
825 cl = repo.changelog
836 cl = repo.changelog
826 hasnode = cl.hasnode
837 hasnode = cl.hasnode
827
838
828 seen = set()
839 seen = set()
829 outgoing = []
840 outgoing = []
830
841
831 if nodes is not None:
842 if nodes is not None:
832 outgoing = [n for n in nodes if hasnode(n)]
843 outgoing = [n for n in nodes if hasnode(n)]
833
844
834 if nodesdepth:
845 if nodesdepth:
835 outgoing = [cl.node(r) for r in
846 outgoing = [cl.node(r) for r in
836 repo.revs(b'ancestors(%ln, %d)', outgoing,
847 repo.revs(b'ancestors(%ln, %d)', outgoing,
837 nodesdepth - 1)]
848 nodesdepth - 1)]
838
849
839 seen |= set(outgoing)
850 seen |= set(outgoing)
840
851
841 if noderange is not None:
852 if noderange is not None:
842 if noderange[0]:
853 if noderange[0]:
843 common = [n for n in noderange[0] if hasnode(n)]
854 common = [n for n in noderange[0] if hasnode(n)]
844 else:
855 else:
845 common = [nullid]
856 common = [nullid]
846
857
847 for n in discovery.outgoing(repo, common, noderange[1]).missing:
858 for n in discovery.outgoing(repo, common, noderange[1]).missing:
848 if n not in seen:
859 if n not in seen:
849 outgoing.append(n)
860 outgoing.append(n)
850 # Don't need to add to seen here because this is the final
861 # Don't need to add to seen here because this is the final
851 # source of nodes and there should be no duplicates in this
862 # source of nodes and there should be no duplicates in this
852 # list.
863 # list.
853
864
854 seen.clear()
865 seen.clear()
855 publishing = repo.publishing()
866 publishing = repo.publishing()
856
867
857 if outgoing:
868 if outgoing:
858 repo.hook('preoutgoing', throw=True, source='serve')
869 repo.hook('preoutgoing', throw=True, source='serve')
859
870
860 yield {
871 yield {
861 b'totalitems': len(outgoing),
872 b'totalitems': len(outgoing),
862 }
873 }
863
874
864 # The phases of nodes already transferred to the client may have changed
875 # The phases of nodes already transferred to the client may have changed
865 # since the client last requested data. We send phase-only records
876 # since the client last requested data. We send phase-only records
866 # for these revisions, if requested.
877 # for these revisions, if requested.
867 if b'phase' in fields and noderange is not None:
878 if b'phase' in fields and noderange is not None:
868 # TODO skip nodes whose phase will be reflected by a node in the
879 # TODO skip nodes whose phase will be reflected by a node in the
869 # outgoing set. This is purely an optimization to reduce data
880 # outgoing set. This is purely an optimization to reduce data
870 # size.
881 # size.
871 for node in noderange[0]:
882 for node in noderange[0]:
872 yield {
883 yield {
873 b'node': node,
884 b'node': node,
874 b'phase': b'public' if publishing else repo[node].phasestr()
885 b'phase': b'public' if publishing else repo[node].phasestr()
875 }
886 }
876
887
877 nodebookmarks = {}
888 nodebookmarks = {}
878 for mark, node in repo._bookmarks.items():
889 for mark, node in repo._bookmarks.items():
879 nodebookmarks.setdefault(node, set()).add(mark)
890 nodebookmarks.setdefault(node, set()).add(mark)
880
891
881 # It is already topologically sorted by revision number.
892 # It is already topologically sorted by revision number.
882 for node in outgoing:
893 for node in outgoing:
883 d = {
894 d = {
884 b'node': node,
895 b'node': node,
885 }
896 }
886
897
887 if b'parents' in fields:
898 if b'parents' in fields:
888 d[b'parents'] = cl.parents(node)
899 d[b'parents'] = cl.parents(node)
889
900
890 if b'phase' in fields:
901 if b'phase' in fields:
891 if publishing:
902 if publishing:
892 d[b'phase'] = b'public'
903 d[b'phase'] = b'public'
893 else:
904 else:
894 ctx = repo[node]
905 ctx = repo[node]
895 d[b'phase'] = ctx.phasestr()
906 d[b'phase'] = ctx.phasestr()
896
907
897 if b'bookmarks' in fields and node in nodebookmarks:
908 if b'bookmarks' in fields and node in nodebookmarks:
898 d[b'bookmarks'] = sorted(nodebookmarks[node])
909 d[b'bookmarks'] = sorted(nodebookmarks[node])
899 del nodebookmarks[node]
910 del nodebookmarks[node]
900
911
901 followingmeta = []
912 followingmeta = []
902 followingdata = []
913 followingdata = []
903
914
904 if b'revision' in fields:
915 if b'revision' in fields:
905 revisiondata = cl.revision(node, raw=True)
916 revisiondata = cl.revision(node, raw=True)
906 followingmeta.append((b'revision', len(revisiondata)))
917 followingmeta.append((b'revision', len(revisiondata)))
907 followingdata.append(revisiondata)
918 followingdata.append(revisiondata)
908
919
909 # TODO make it possible for extensions to wrap a function or register
920 # TODO make it possible for extensions to wrap a function or register
910 # a handler to service custom fields.
921 # a handler to service custom fields.
911
922
912 if followingmeta:
923 if followingmeta:
913 d[b'fieldsfollowing'] = followingmeta
924 d[b'fieldsfollowing'] = followingmeta
914
925
915 yield d
926 yield d
916
927
917 for extra in followingdata:
928 for extra in followingdata:
918 yield extra
929 yield extra
919
930
920 # If requested, send bookmarks from nodes that didn't have revision
931 # If requested, send bookmarks from nodes that didn't have revision
921 # data sent so receiver is aware of any bookmark updates.
932 # data sent so receiver is aware of any bookmark updates.
922 if b'bookmarks' in fields:
933 if b'bookmarks' in fields:
923 for node, marks in sorted(nodebookmarks.iteritems()):
934 for node, marks in sorted(nodebookmarks.iteritems()):
924 yield {
935 yield {
925 b'node': node,
936 b'node': node,
926 b'bookmarks': sorted(marks),
937 b'bookmarks': sorted(marks),
927 }
938 }
928
939
929 class FileAccessError(Exception):
940 class FileAccessError(Exception):
930 """Represents an error accessing a specific file."""
941 """Represents an error accessing a specific file."""
931
942
932 def __init__(self, path, msg, args):
943 def __init__(self, path, msg, args):
933 self.path = path
944 self.path = path
934 self.msg = msg
945 self.msg = msg
935 self.args = args
946 self.args = args
936
947
937 def getfilestore(repo, proto, path):
948 def getfilestore(repo, proto, path):
938 """Obtain a file storage object for use with wire protocol.
949 """Obtain a file storage object for use with wire protocol.
939
950
940 Exists as a standalone function so extensions can monkeypatch to add
951 Exists as a standalone function so extensions can monkeypatch to add
941 access control.
952 access control.
942 """
953 """
943 # This seems to work even if the file doesn't exist. So catch
954 # This seems to work even if the file doesn't exist. So catch
944 # "empty" files and return an error.
955 # "empty" files and return an error.
945 fl = repo.file(path)
956 fl = repo.file(path)
946
957
947 if not len(fl):
958 if not len(fl):
948 raise FileAccessError(path, 'unknown file: %s', (path,))
959 raise FileAccessError(path, 'unknown file: %s', (path,))
949
960
950 return fl
961 return fl
951
962
952 @wireprotocommand(
963 @wireprotocommand(
953 'filedata',
964 'filedata',
954 args={
965 args={
955 'haveparents': {
966 'haveparents': {
956 'type': 'bool',
967 'type': 'bool',
957 'default': lambda: False,
968 'default': lambda: False,
958 'example': True,
969 'example': True,
959 },
970 },
960 'nodes': {
971 'nodes': {
961 'type': 'list',
972 'type': 'list',
962 'example': [b'0123456...'],
973 'example': [b'0123456...'],
963 },
974 },
964 'fields': {
975 'fields': {
965 'type': 'set',
976 'type': 'set',
966 'default': set,
977 'default': set,
967 'example': {b'parents', b'revision'},
978 'example': {b'parents', b'revision'},
968 'validvalues': {b'parents', b'revision'},
979 'validvalues': {b'parents', b'revision'},
969 },
980 },
970 'path': {
981 'path': {
971 'type': 'bytes',
982 'type': 'bytes',
972 'example': b'foo.txt',
983 'example': b'foo.txt',
973 }
984 }
974 },
985 },
975 permission='pull',
986 permission='pull',
976 # TODO censoring a file revision won't invalidate the cache.
987 # TODO censoring a file revision won't invalidate the cache.
977 # Figure out a way to take censoring into account when deriving
988 # Figure out a way to take censoring into account when deriving
978 # the cache key.
989 # the cache key.
979 cachekeyfn=makecommandcachekeyfn('filedata', 1, allargs=True))
990 cachekeyfn=makecommandcachekeyfn('filedata', 1, allargs=True))
980 def filedata(repo, proto, haveparents, nodes, fields, path):
991 def filedata(repo, proto, haveparents, nodes, fields, path):
981 try:
992 try:
982 # Extensions may wish to access the protocol handler.
993 # Extensions may wish to access the protocol handler.
983 store = getfilestore(repo, proto, path)
994 store = getfilestore(repo, proto, path)
984 except FileAccessError as e:
995 except FileAccessError as e:
985 raise error.WireprotoCommandError(e.msg, e.args)
996 raise error.WireprotoCommandError(e.msg, e.args)
986
997
987 # Validate requested nodes.
998 # Validate requested nodes.
988 for node in nodes:
999 for node in nodes:
989 try:
1000 try:
990 store.rev(node)
1001 store.rev(node)
991 except error.LookupError:
1002 except error.LookupError:
992 raise error.WireprotoCommandError('unknown file node: %s',
1003 raise error.WireprotoCommandError('unknown file node: %s',
993 (hex(node),))
1004 (hex(node),))
994
1005
995 revisions = store.emitrevisions(nodes,
1006 revisions = store.emitrevisions(nodes,
996 revisiondata=b'revision' in fields,
1007 revisiondata=b'revision' in fields,
997 assumehaveparentrevisions=haveparents)
1008 assumehaveparentrevisions=haveparents)
998
1009
999 yield {
1010 yield {
1000 b'totalitems': len(nodes),
1011 b'totalitems': len(nodes),
1001 }
1012 }
1002
1013
1003 for revision in revisions:
1014 for revision in revisions:
1004 d = {
1015 d = {
1005 b'node': revision.node,
1016 b'node': revision.node,
1006 }
1017 }
1007
1018
1008 if b'parents' in fields:
1019 if b'parents' in fields:
1009 d[b'parents'] = [revision.p1node, revision.p2node]
1020 d[b'parents'] = [revision.p1node, revision.p2node]
1010
1021
1011 followingmeta = []
1022 followingmeta = []
1012 followingdata = []
1023 followingdata = []
1013
1024
1014 if b'revision' in fields:
1025 if b'revision' in fields:
1015 if revision.revision is not None:
1026 if revision.revision is not None:
1016 followingmeta.append((b'revision', len(revision.revision)))
1027 followingmeta.append((b'revision', len(revision.revision)))
1017 followingdata.append(revision.revision)
1028 followingdata.append(revision.revision)
1018 else:
1029 else:
1019 d[b'deltabasenode'] = revision.basenode
1030 d[b'deltabasenode'] = revision.basenode
1020 followingmeta.append((b'delta', len(revision.delta)))
1031 followingmeta.append((b'delta', len(revision.delta)))
1021 followingdata.append(revision.delta)
1032 followingdata.append(revision.delta)
1022
1033
1023 if followingmeta:
1034 if followingmeta:
1024 d[b'fieldsfollowing'] = followingmeta
1035 d[b'fieldsfollowing'] = followingmeta
1025
1036
1026 yield d
1037 yield d
1027
1038
1028 for extra in followingdata:
1039 for extra in followingdata:
1029 yield extra
1040 yield extra
1030
1041
1031 @wireprotocommand(
1042 @wireprotocommand(
1032 'heads',
1043 'heads',
1033 args={
1044 args={
1034 'publiconly': {
1045 'publiconly': {
1035 'type': 'bool',
1046 'type': 'bool',
1036 'default': lambda: False,
1047 'default': lambda: False,
1037 'example': False,
1048 'example': False,
1038 },
1049 },
1039 },
1050 },
1040 permission='pull')
1051 permission='pull')
1041 def headsv2(repo, proto, publiconly):
1052 def headsv2(repo, proto, publiconly):
1042 if publiconly:
1053 if publiconly:
1043 repo = repo.filtered('immutable')
1054 repo = repo.filtered('immutable')
1044
1055
1045 yield repo.heads()
1056 yield repo.heads()
1046
1057
1047 @wireprotocommand(
1058 @wireprotocommand(
1048 'known',
1059 'known',
1049 args={
1060 args={
1050 'nodes': {
1061 'nodes': {
1051 'type': 'list',
1062 'type': 'list',
1052 'default': list,
1063 'default': list,
1053 'example': [b'deadbeef'],
1064 'example': [b'deadbeef'],
1054 },
1065 },
1055 },
1066 },
1056 permission='pull')
1067 permission='pull')
1057 def knownv2(repo, proto, nodes):
1068 def knownv2(repo, proto, nodes):
1058 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
1069 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
1059 yield result
1070 yield result
1060
1071
1061 @wireprotocommand(
1072 @wireprotocommand(
1062 'listkeys',
1073 'listkeys',
1063 args={
1074 args={
1064 'namespace': {
1075 'namespace': {
1065 'type': 'bytes',
1076 'type': 'bytes',
1066 'example': b'ns',
1077 'example': b'ns',
1067 },
1078 },
1068 },
1079 },
1069 permission='pull')
1080 permission='pull')
1070 def listkeysv2(repo, proto, namespace):
1081 def listkeysv2(repo, proto, namespace):
1071 keys = repo.listkeys(encoding.tolocal(namespace))
1082 keys = repo.listkeys(encoding.tolocal(namespace))
1072 keys = {encoding.fromlocal(k): encoding.fromlocal(v)
1083 keys = {encoding.fromlocal(k): encoding.fromlocal(v)
1073 for k, v in keys.iteritems()}
1084 for k, v in keys.iteritems()}
1074
1085
1075 yield keys
1086 yield keys
1076
1087
1077 @wireprotocommand(
1088 @wireprotocommand(
1078 'lookup',
1089 'lookup',
1079 args={
1090 args={
1080 'key': {
1091 'key': {
1081 'type': 'bytes',
1092 'type': 'bytes',
1082 'example': b'foo',
1093 'example': b'foo',
1083 },
1094 },
1084 },
1095 },
1085 permission='pull')
1096 permission='pull')
1086 def lookupv2(repo, proto, key):
1097 def lookupv2(repo, proto, key):
1087 key = encoding.tolocal(key)
1098 key = encoding.tolocal(key)
1088
1099
1089 # TODO handle exception.
1100 # TODO handle exception.
1090 node = repo.lookup(key)
1101 node = repo.lookup(key)
1091
1102
1092 yield node
1103 yield node
1093
1104
1105 def manifestdatacapabilities(repo, proto):
1106 batchsize = repo.ui.configint(
1107 b'experimental', b'server.manifestdata.recommended-batch-size')
1108
1109 return {
1110 b'recommendedbatchsize': batchsize,
1111 }
1112
1094 @wireprotocommand(
1113 @wireprotocommand(
1095 'manifestdata',
1114 'manifestdata',
1096 args={
1115 args={
1097 'nodes': {
1116 'nodes': {
1098 'type': 'list',
1117 'type': 'list',
1099 'example': [b'0123456...'],
1118 'example': [b'0123456...'],
1100 },
1119 },
1101 'haveparents': {
1120 'haveparents': {
1102 'type': 'bool',
1121 'type': 'bool',
1103 'default': lambda: False,
1122 'default': lambda: False,
1104 'example': True,
1123 'example': True,
1105 },
1124 },
1106 'fields': {
1125 'fields': {
1107 'type': 'set',
1126 'type': 'set',
1108 'default': set,
1127 'default': set,
1109 'example': {b'parents', b'revision'},
1128 'example': {b'parents', b'revision'},
1110 'validvalues': {b'parents', b'revision'},
1129 'validvalues': {b'parents', b'revision'},
1111 },
1130 },
1112 'tree': {
1131 'tree': {
1113 'type': 'bytes',
1132 'type': 'bytes',
1114 'example': b'',
1133 'example': b'',
1115 },
1134 },
1116 },
1135 },
1117 permission='pull',
1136 permission='pull',
1118 cachekeyfn=makecommandcachekeyfn('manifestdata', 1, allargs=True))
1137 cachekeyfn=makecommandcachekeyfn('manifestdata', 1, allargs=True),
1138 extracapabilitiesfn=manifestdatacapabilities)
1119 def manifestdata(repo, proto, haveparents, nodes, fields, tree):
1139 def manifestdata(repo, proto, haveparents, nodes, fields, tree):
1120 store = repo.manifestlog.getstorage(tree)
1140 store = repo.manifestlog.getstorage(tree)
1121
1141
1122 # Validate the node is known and abort on unknown revisions.
1142 # Validate the node is known and abort on unknown revisions.
1123 for node in nodes:
1143 for node in nodes:
1124 try:
1144 try:
1125 store.rev(node)
1145 store.rev(node)
1126 except error.LookupError:
1146 except error.LookupError:
1127 raise error.WireprotoCommandError(
1147 raise error.WireprotoCommandError(
1128 'unknown node: %s', (node,))
1148 'unknown node: %s', (node,))
1129
1149
1130 revisions = store.emitrevisions(nodes,
1150 revisions = store.emitrevisions(nodes,
1131 revisiondata=b'revision' in fields,
1151 revisiondata=b'revision' in fields,
1132 assumehaveparentrevisions=haveparents)
1152 assumehaveparentrevisions=haveparents)
1133
1153
1134 yield {
1154 yield {
1135 b'totalitems': len(nodes),
1155 b'totalitems': len(nodes),
1136 }
1156 }
1137
1157
1138 for revision in revisions:
1158 for revision in revisions:
1139 d = {
1159 d = {
1140 b'node': revision.node,
1160 b'node': revision.node,
1141 }
1161 }
1142
1162
1143 if b'parents' in fields:
1163 if b'parents' in fields:
1144 d[b'parents'] = [revision.p1node, revision.p2node]
1164 d[b'parents'] = [revision.p1node, revision.p2node]
1145
1165
1146 followingmeta = []
1166 followingmeta = []
1147 followingdata = []
1167 followingdata = []
1148
1168
1149 if b'revision' in fields:
1169 if b'revision' in fields:
1150 if revision.revision is not None:
1170 if revision.revision is not None:
1151 followingmeta.append((b'revision', len(revision.revision)))
1171 followingmeta.append((b'revision', len(revision.revision)))
1152 followingdata.append(revision.revision)
1172 followingdata.append(revision.revision)
1153 else:
1173 else:
1154 d[b'deltabasenode'] = revision.basenode
1174 d[b'deltabasenode'] = revision.basenode
1155 followingmeta.append((b'delta', len(revision.delta)))
1175 followingmeta.append((b'delta', len(revision.delta)))
1156 followingdata.append(revision.delta)
1176 followingdata.append(revision.delta)
1157
1177
1158 if followingmeta:
1178 if followingmeta:
1159 d[b'fieldsfollowing'] = followingmeta
1179 d[b'fieldsfollowing'] = followingmeta
1160
1180
1161 yield d
1181 yield d
1162
1182
1163 for extra in followingdata:
1183 for extra in followingdata:
1164 yield extra
1184 yield extra
1165
1185
1166 @wireprotocommand(
1186 @wireprotocommand(
1167 'pushkey',
1187 'pushkey',
1168 args={
1188 args={
1169 'namespace': {
1189 'namespace': {
1170 'type': 'bytes',
1190 'type': 'bytes',
1171 'example': b'ns',
1191 'example': b'ns',
1172 },
1192 },
1173 'key': {
1193 'key': {
1174 'type': 'bytes',
1194 'type': 'bytes',
1175 'example': b'key',
1195 'example': b'key',
1176 },
1196 },
1177 'old': {
1197 'old': {
1178 'type': 'bytes',
1198 'type': 'bytes',
1179 'example': b'old',
1199 'example': b'old',
1180 },
1200 },
1181 'new': {
1201 'new': {
1182 'type': 'bytes',
1202 'type': 'bytes',
1183 'example': 'new',
1203 'example': 'new',
1184 },
1204 },
1185 },
1205 },
1186 permission='push')
1206 permission='push')
1187 def pushkeyv2(repo, proto, namespace, key, old, new):
1207 def pushkeyv2(repo, proto, namespace, key, old, new):
1188 # TODO handle ui output redirection
1208 # TODO handle ui output redirection
1189 yield repo.pushkey(encoding.tolocal(namespace),
1209 yield repo.pushkey(encoding.tolocal(namespace),
1190 encoding.tolocal(key),
1210 encoding.tolocal(key),
1191 encoding.tolocal(old),
1211 encoding.tolocal(old),
1192 encoding.tolocal(new))
1212 encoding.tolocal(new))
@@ -1,759 +1,759 b''
1 #require no-chg
1 #require no-chg
2
2
3 $ . $TESTDIR/wireprotohelpers.sh
3 $ . $TESTDIR/wireprotohelpers.sh
4
4
5 $ cat >> $HGRCPATH << EOF
5 $ cat >> $HGRCPATH << EOF
6 > [web]
6 > [web]
7 > push_ssl = false
7 > push_ssl = false
8 > allow_push = *
8 > allow_push = *
9 > EOF
9 > EOF
10
10
11 $ hg init server
11 $ hg init server
12 $ cd server
12 $ cd server
13 $ touch a
13 $ touch a
14 $ hg -q commit -A -m initial
14 $ hg -q commit -A -m initial
15 $ cd ..
15 $ cd ..
16
16
17 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
17 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
18 $ cat hg.pid >> $DAEMON_PIDS
18 $ cat hg.pid >> $DAEMON_PIDS
19
19
20 compression formats are advertised in compression capability
20 compression formats are advertised in compression capability
21
21
22 #if zstd
22 #if zstd
23 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zstd,zlib$' > /dev/null
23 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zstd,zlib$' > /dev/null
24 #else
24 #else
25 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zlib$' > /dev/null
25 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zlib$' > /dev/null
26 #endif
26 #endif
27
27
28 $ killdaemons.py
28 $ killdaemons.py
29
29
30 server.compressionengines can replace engines list wholesale
30 server.compressionengines can replace engines list wholesale
31
31
32 $ hg serve --config server.compressionengines=none -R server -p $HGPORT -d --pid-file hg.pid
32 $ hg serve --config server.compressionengines=none -R server -p $HGPORT -d --pid-file hg.pid
33 $ cat hg.pid > $DAEMON_PIDS
33 $ cat hg.pid > $DAEMON_PIDS
34 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none$' > /dev/null
34 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none$' > /dev/null
35
35
36 $ killdaemons.py
36 $ killdaemons.py
37
37
38 Order of engines can also change
38 Order of engines can also change
39
39
40 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
40 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
41 $ cat hg.pid > $DAEMON_PIDS
41 $ cat hg.pid > $DAEMON_PIDS
42 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none,zlib$' > /dev/null
42 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none,zlib$' > /dev/null
43
43
44 $ killdaemons.py
44 $ killdaemons.py
45
45
46 Start a default server again
46 Start a default server again
47
47
48 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
48 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
49 $ cat hg.pid > $DAEMON_PIDS
49 $ cat hg.pid > $DAEMON_PIDS
50
50
51 Server should send application/mercurial-0.1 to clients if no Accept is used
51 Server should send application/mercurial-0.1 to clients if no Accept is used
52
52
53 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
53 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
54 200 Script output follows
54 200 Script output follows
55 content-type: application/mercurial-0.1
55 content-type: application/mercurial-0.1
56 date: $HTTP_DATE$
56 date: $HTTP_DATE$
57 server: testing stub value
57 server: testing stub value
58 transfer-encoding: chunked
58 transfer-encoding: chunked
59
59
60 Server should send application/mercurial-0.1 when client says it wants it
60 Server should send application/mercurial-0.1 when client says it wants it
61
61
62 $ get-with-headers.py --hgproto '0.1' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
62 $ get-with-headers.py --hgproto '0.1' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
63 200 Script output follows
63 200 Script output follows
64 content-type: application/mercurial-0.1
64 content-type: application/mercurial-0.1
65 date: $HTTP_DATE$
65 date: $HTTP_DATE$
66 server: testing stub value
66 server: testing stub value
67 transfer-encoding: chunked
67 transfer-encoding: chunked
68
68
69 Server should send application/mercurial-0.2 when client says it wants it
69 Server should send application/mercurial-0.2 when client says it wants it
70
70
71 $ get-with-headers.py --hgproto '0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
71 $ get-with-headers.py --hgproto '0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
72 200 Script output follows
72 200 Script output follows
73 content-type: application/mercurial-0.2
73 content-type: application/mercurial-0.2
74 date: $HTTP_DATE$
74 date: $HTTP_DATE$
75 server: testing stub value
75 server: testing stub value
76 transfer-encoding: chunked
76 transfer-encoding: chunked
77
77
78 $ get-with-headers.py --hgproto '0.1 0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
78 $ get-with-headers.py --hgproto '0.1 0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
79 200 Script output follows
79 200 Script output follows
80 content-type: application/mercurial-0.2
80 content-type: application/mercurial-0.2
81 date: $HTTP_DATE$
81 date: $HTTP_DATE$
82 server: testing stub value
82 server: testing stub value
83 transfer-encoding: chunked
83 transfer-encoding: chunked
84
84
85 Requesting a compression format that server doesn't support results will fall back to 0.1
85 Requesting a compression format that server doesn't support results will fall back to 0.1
86
86
87 $ get-with-headers.py --hgproto '0.2 comp=aa' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
87 $ get-with-headers.py --hgproto '0.2 comp=aa' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
88 200 Script output follows
88 200 Script output follows
89 content-type: application/mercurial-0.1
89 content-type: application/mercurial-0.1
90 date: $HTTP_DATE$
90 date: $HTTP_DATE$
91 server: testing stub value
91 server: testing stub value
92 transfer-encoding: chunked
92 transfer-encoding: chunked
93
93
94 #if zstd
94 #if zstd
95 zstd is used if available
95 zstd is used if available
96
96
97 $ get-with-headers.py --hgproto '0.2 comp=zstd' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
97 $ get-with-headers.py --hgproto '0.2 comp=zstd' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
98 $ f --size --hexdump --bytes 36 --sha1 resp
98 $ f --size --hexdump --bytes 36 --sha1 resp
99 resp: size=248, sha1=4d8d8f87fb82bd542ce52881fdc94f850748
99 resp: size=248, sha1=4d8d8f87fb82bd542ce52881fdc94f850748
100 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
100 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
101 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 73 74 64 |t follows...zstd|
101 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 73 74 64 |t follows...zstd|
102 0020: 28 b5 2f fd |(./.|
102 0020: 28 b5 2f fd |(./.|
103
103
104 #endif
104 #endif
105
105
106 application/mercurial-0.2 is not yet used on non-streaming responses
106 application/mercurial-0.2 is not yet used on non-streaming responses
107
107
108 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=heads' -
108 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=heads' -
109 200 Script output follows
109 200 Script output follows
110 content-length: 41
110 content-length: 41
111 content-type: application/mercurial-0.1
111 content-type: application/mercurial-0.1
112 date: $HTTP_DATE$
112 date: $HTTP_DATE$
113 server: testing stub value
113 server: testing stub value
114
114
115 e93700bd72895c5addab234c56d4024b487a362f
115 e93700bd72895c5addab234c56d4024b487a362f
116
116
117 Now test protocol preference usage
117 Now test protocol preference usage
118
118
119 $ killdaemons.py
119 $ killdaemons.py
120 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
120 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
121 $ cat hg.pid > $DAEMON_PIDS
121 $ cat hg.pid > $DAEMON_PIDS
122
122
123 No Accept will send 0.1+zlib, even though "none" is preferred b/c "none" isn't supported on 0.1
123 No Accept will send 0.1+zlib, even though "none" is preferred b/c "none" isn't supported on 0.1
124
124
125 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' Content-Type
125 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' Content-Type
126 200 Script output follows
126 200 Script output follows
127 content-type: application/mercurial-0.1
127 content-type: application/mercurial-0.1
128
128
129 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
129 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
130 $ f --size --hexdump --bytes 28 --sha1 resp
130 $ f --size --hexdump --bytes 28 --sha1 resp
131 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
131 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
132 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
132 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
133 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
133 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
134
134
135 Explicit 0.1 will send zlib because "none" isn't supported on 0.1
135 Explicit 0.1 will send zlib because "none" isn't supported on 0.1
136
136
137 $ get-with-headers.py --hgproto '0.1' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
137 $ get-with-headers.py --hgproto '0.1' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
138 $ f --size --hexdump --bytes 28 --sha1 resp
138 $ f --size --hexdump --bytes 28 --sha1 resp
139 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
139 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
140 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
140 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
141 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
141 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
142
142
143 0.2 with no compression will get "none" because that is server's preference
143 0.2 with no compression will get "none" because that is server's preference
144 (spec says ZL and UN are implicitly supported)
144 (spec says ZL and UN are implicitly supported)
145
145
146 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
146 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
147 $ f --size --hexdump --bytes 32 --sha1 resp
147 $ f --size --hexdump --bytes 32 --sha1 resp
148 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
148 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
149 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
149 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
150 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
150 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
151
151
152 Client receives server preference even if local order doesn't match
152 Client receives server preference even if local order doesn't match
153
153
154 $ get-with-headers.py --hgproto '0.2 comp=zlib,none' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
154 $ get-with-headers.py --hgproto '0.2 comp=zlib,none' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
155 $ f --size --hexdump --bytes 32 --sha1 resp
155 $ f --size --hexdump --bytes 32 --sha1 resp
156 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
156 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
157 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
157 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
158 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
158 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
159
159
160 Client receives only supported format even if not server preferred format
160 Client receives only supported format even if not server preferred format
161
161
162 $ get-with-headers.py --hgproto '0.2 comp=zlib' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
162 $ get-with-headers.py --hgproto '0.2 comp=zlib' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
163 $ f --size --hexdump --bytes 33 --sha1 resp
163 $ f --size --hexdump --bytes 33 --sha1 resp
164 resp: size=232, sha1=a1c727f0c9693ca15742a75c30419bc36
164 resp: size=232, sha1=a1c727f0c9693ca15742a75c30419bc36
165 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
165 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
166 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib|
166 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib|
167 0020: 78 |x|
167 0020: 78 |x|
168
168
169 $ killdaemons.py
169 $ killdaemons.py
170 $ cd ..
170 $ cd ..
171
171
172 Test listkeys for listing namespaces
172 Test listkeys for listing namespaces
173
173
174 $ hg init empty
174 $ hg init empty
175 $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
175 $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
176 $ cat hg.pid > $DAEMON_PIDS
176 $ cat hg.pid > $DAEMON_PIDS
177
177
178 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
178 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
179 > command listkeys
179 > command listkeys
180 > namespace namespaces
180 > namespace namespaces
181 > EOF
181 > EOF
182 s> GET /?cmd=capabilities HTTP/1.1\r\n
182 s> GET /?cmd=capabilities HTTP/1.1\r\n
183 s> Accept-Encoding: identity\r\n
183 s> Accept-Encoding: identity\r\n
184 s> accept: application/mercurial-0.1\r\n
184 s> accept: application/mercurial-0.1\r\n
185 s> host: $LOCALIP:$HGPORT\r\n (glob)
185 s> host: $LOCALIP:$HGPORT\r\n (glob)
186 s> user-agent: Mercurial debugwireproto\r\n
186 s> user-agent: Mercurial debugwireproto\r\n
187 s> \r\n
187 s> \r\n
188 s> makefile('rb', None)
188 s> makefile('rb', None)
189 s> HTTP/1.1 200 Script output follows\r\n
189 s> HTTP/1.1 200 Script output follows\r\n
190 s> Server: testing stub value\r\n
190 s> Server: testing stub value\r\n
191 s> Date: $HTTP_DATE$\r\n
191 s> Date: $HTTP_DATE$\r\n
192 s> Content-Type: application/mercurial-0.1\r\n
192 s> Content-Type: application/mercurial-0.1\r\n
193 s> Content-Length: *\r\n (glob)
193 s> Content-Length: *\r\n (glob)
194 s> \r\n
194 s> \r\n
195 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
195 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
196 sending listkeys command
196 sending listkeys command
197 s> GET /?cmd=listkeys HTTP/1.1\r\n
197 s> GET /?cmd=listkeys HTTP/1.1\r\n
198 s> Accept-Encoding: identity\r\n
198 s> Accept-Encoding: identity\r\n
199 s> vary: X-HgArg-1,X-HgProto-1\r\n
199 s> vary: X-HgArg-1,X-HgProto-1\r\n
200 s> x-hgarg-1: namespace=namespaces\r\n
200 s> x-hgarg-1: namespace=namespaces\r\n
201 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
201 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
202 s> accept: application/mercurial-0.1\r\n
202 s> accept: application/mercurial-0.1\r\n
203 s> host: $LOCALIP:$HGPORT\r\n (glob)
203 s> host: $LOCALIP:$HGPORT\r\n (glob)
204 s> user-agent: Mercurial debugwireproto\r\n
204 s> user-agent: Mercurial debugwireproto\r\n
205 s> \r\n
205 s> \r\n
206 s> makefile('rb', None)
206 s> makefile('rb', None)
207 s> HTTP/1.1 200 Script output follows\r\n
207 s> HTTP/1.1 200 Script output follows\r\n
208 s> Server: testing stub value\r\n
208 s> Server: testing stub value\r\n
209 s> Date: $HTTP_DATE$\r\n
209 s> Date: $HTTP_DATE$\r\n
210 s> Content-Type: application/mercurial-0.1\r\n
210 s> Content-Type: application/mercurial-0.1\r\n
211 s> Content-Length: 30\r\n
211 s> Content-Length: 30\r\n
212 s> \r\n
212 s> \r\n
213 s> bookmarks\t\n
213 s> bookmarks\t\n
214 s> namespaces\t\n
214 s> namespaces\t\n
215 s> phases\t
215 s> phases\t
216 response: {
216 response: {
217 b'bookmarks': b'',
217 b'bookmarks': b'',
218 b'namespaces': b'',
218 b'namespaces': b'',
219 b'phases': b''
219 b'phases': b''
220 }
220 }
221 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
221 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
222
222
223 Same thing, but with "httprequest" command
223 Same thing, but with "httprequest" command
224
224
225 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
225 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
226 > httprequest GET ?cmd=listkeys
226 > httprequest GET ?cmd=listkeys
227 > user-agent: test
227 > user-agent: test
228 > x-hgarg-1: namespace=namespaces
228 > x-hgarg-1: namespace=namespaces
229 > EOF
229 > EOF
230 using raw connection to peer
230 using raw connection to peer
231 s> GET /?cmd=listkeys HTTP/1.1\r\n
231 s> GET /?cmd=listkeys HTTP/1.1\r\n
232 s> Accept-Encoding: identity\r\n
232 s> Accept-Encoding: identity\r\n
233 s> user-agent: test\r\n
233 s> user-agent: test\r\n
234 s> x-hgarg-1: namespace=namespaces\r\n
234 s> x-hgarg-1: namespace=namespaces\r\n
235 s> host: $LOCALIP:$HGPORT\r\n (glob)
235 s> host: $LOCALIP:$HGPORT\r\n (glob)
236 s> \r\n
236 s> \r\n
237 s> makefile('rb', None)
237 s> makefile('rb', None)
238 s> HTTP/1.1 200 Script output follows\r\n
238 s> HTTP/1.1 200 Script output follows\r\n
239 s> Server: testing stub value\r\n
239 s> Server: testing stub value\r\n
240 s> Date: $HTTP_DATE$\r\n
240 s> Date: $HTTP_DATE$\r\n
241 s> Content-Type: application/mercurial-0.1\r\n
241 s> Content-Type: application/mercurial-0.1\r\n
242 s> Content-Length: 30\r\n
242 s> Content-Length: 30\r\n
243 s> \r\n
243 s> \r\n
244 s> bookmarks\t\n
244 s> bookmarks\t\n
245 s> namespaces\t\n
245 s> namespaces\t\n
246 s> phases\t
246 s> phases\t
247
247
248 Client with HTTPv2 enabled advertises that and gets old capabilities response from old server
248 Client with HTTPv2 enabled advertises that and gets old capabilities response from old server
249
249
250 $ hg --config experimental.httppeer.advertise-v2=true --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
250 $ hg --config experimental.httppeer.advertise-v2=true --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
251 > command heads
251 > command heads
252 > EOF
252 > EOF
253 s> GET /?cmd=capabilities HTTP/1.1\r\n
253 s> GET /?cmd=capabilities HTTP/1.1\r\n
254 s> Accept-Encoding: identity\r\n
254 s> Accept-Encoding: identity\r\n
255 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
255 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
256 s> x-hgproto-1: cbor\r\n
256 s> x-hgproto-1: cbor\r\n
257 s> x-hgupgrade-1: exp-http-v2-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 --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
299 $ hg --config experimental.httppeer.advertise-v2=true --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
300 > command heads
300 > command heads
301 > EOF
301 > EOF
302 s> GET /?cmd=capabilities HTTP/1.1\r\n
302 s> GET /?cmd=capabilities HTTP/1.1\r\n
303 s> Accept-Encoding: identity\r\n
303 s> Accept-Encoding: identity\r\n
304 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
304 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
305 s> x-hgproto-1: cbor\r\n
305 s> x-hgproto-1: cbor\r\n
306 s> x-hgupgrade-1: exp-http-v2-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\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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
318 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
319 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-0006\r\n
322 s> accept: application/mercurial-exp-framing-0006\r\n
323 s> content-type: application/mercurial-exp-framing-0006\r\n
323 s> content-type: application/mercurial-exp-framing-0006\r\n
324 s> content-length: 56\r\n
324 s> content-length: 56\r\n
325 s> host: $LOCALIP:$HGPORT\r\n (glob)
325 s> host: $LOCALIP:$HGPORT\r\n (glob)
326 s> user-agent: Mercurial debugwireproto\r\n
326 s> user-agent: Mercurial debugwireproto\r\n
327 s> \r\n
327 s> \r\n
328 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads
328 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads
329 s> makefile('rb', None)
329 s> makefile('rb', None)
330 s> HTTP/1.1 200 OK\r\n
330 s> HTTP/1.1 200 OK\r\n
331 s> Server: testing stub value\r\n
331 s> Server: testing stub value\r\n
332 s> Date: $HTTP_DATE$\r\n
332 s> Date: $HTTP_DATE$\r\n
333 s> Content-Type: application/mercurial-exp-framing-0006\r\n
333 s> Content-Type: application/mercurial-exp-framing-0006\r\n
334 s> Transfer-Encoding: chunked\r\n
334 s> Transfer-Encoding: chunked\r\n
335 s> \r\n
335 s> \r\n
336 s> 11\r\n
336 s> 11\r\n
337 s> \t\x00\x00\x01\x00\x02\x01\x92
337 s> \t\x00\x00\x01\x00\x02\x01\x92
338 s> Hidentity
338 s> Hidentity
339 s> \r\n
339 s> \r\n
340 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
340 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
341 s> 13\r\n
341 s> 13\r\n
342 s> \x0b\x00\x00\x01\x00\x02\x041
342 s> \x0b\x00\x00\x01\x00\x02\x041
343 s> \xa1FstatusBok
343 s> \xa1FstatusBok
344 s> \r\n
344 s> \r\n
345 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
345 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
346 s> 1e\r\n
346 s> 1e\r\n
347 s> \x16\x00\x00\x01\x00\x02\x041
347 s> \x16\x00\x00\x01\x00\x02\x041
348 s> \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
348 s> \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
349 s> \r\n
349 s> \r\n
350 received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
350 received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
351 s> 8\r\n
351 s> 8\r\n
352 s> \x00\x00\x00\x01\x00\x02\x002
352 s> \x00\x00\x00\x01\x00\x02\x002
353 s> \r\n
353 s> \r\n
354 s> 0\r\n
354 s> 0\r\n
355 s> \r\n
355 s> \r\n
356 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
356 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
357 response: [
357 response: [
358 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
358 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
359 ]
359 ]
360 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
360 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
361
361
362 $ killdaemons.py
362 $ killdaemons.py
363
363
364 HTTP client follows HTTP redirect on handshake to new repo
364 HTTP client follows HTTP redirect on handshake to new repo
365
365
366 $ cd $TESTTMP
366 $ cd $TESTTMP
367
367
368 $ hg init redirector
368 $ hg init redirector
369 $ hg init redirected
369 $ hg init redirected
370 $ cd redirected
370 $ cd redirected
371 $ touch foo
371 $ touch foo
372 $ hg -q commit -A -m initial
372 $ hg -q commit -A -m initial
373 $ cd ..
373 $ cd ..
374
374
375 $ cat > paths.conf << EOF
375 $ cat > paths.conf << EOF
376 > [paths]
376 > [paths]
377 > / = $TESTTMP/*
377 > / = $TESTTMP/*
378 > EOF
378 > EOF
379
379
380 $ cat > redirectext.py << EOF
380 $ cat > redirectext.py << EOF
381 > from mercurial import extensions, wireprotoserver
381 > from mercurial import extensions, wireprotoserver
382 > def wrappedcallhttp(orig, repo, req, res, proto, cmd):
382 > def wrappedcallhttp(orig, repo, req, res, proto, cmd):
383 > path = req.advertisedurl[len(req.advertisedbaseurl):]
383 > path = req.advertisedurl[len(req.advertisedbaseurl):]
384 > if not path.startswith(b'/redirector'):
384 > if not path.startswith(b'/redirector'):
385 > return orig(repo, req, res, proto, cmd)
385 > return orig(repo, req, res, proto, cmd)
386 > relpath = path[len(b'/redirector'):]
386 > relpath = path[len(b'/redirector'):]
387 > res.status = b'301 Redirect'
387 > res.status = b'301 Redirect'
388 > newurl = b'%s/redirected%s' % (req.baseurl, relpath)
388 > newurl = b'%s/redirected%s' % (req.baseurl, relpath)
389 > if not repo.ui.configbool('testing', 'redirectqs', True) and b'?' in newurl:
389 > if not repo.ui.configbool('testing', 'redirectqs', True) and b'?' in newurl:
390 > newurl = newurl[0:newurl.index(b'?')]
390 > newurl = newurl[0:newurl.index(b'?')]
391 > res.headers[b'Location'] = newurl
391 > res.headers[b'Location'] = newurl
392 > res.headers[b'Content-Type'] = b'text/plain'
392 > res.headers[b'Content-Type'] = b'text/plain'
393 > res.setbodybytes(b'redirected')
393 > res.setbodybytes(b'redirected')
394 > return True
394 > return True
395 >
395 >
396 > extensions.wrapfunction(wireprotoserver, '_callhttp', wrappedcallhttp)
396 > extensions.wrapfunction(wireprotoserver, '_callhttp', wrappedcallhttp)
397 > EOF
397 > EOF
398
398
399 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
399 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
400 > --config server.compressionengines=zlib \
400 > --config server.compressionengines=zlib \
401 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
401 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
402 $ cat hg.pid > $DAEMON_PIDS
402 $ cat hg.pid > $DAEMON_PIDS
403
403
404 Verify our HTTP 301 is served properly
404 Verify our HTTP 301 is served properly
405
405
406 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
406 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
407 > httprequest GET /redirector?cmd=capabilities
407 > httprequest GET /redirector?cmd=capabilities
408 > user-agent: test
408 > user-agent: test
409 > EOF
409 > EOF
410 using raw connection to peer
410 using raw connection to peer
411 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
411 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
412 s> Accept-Encoding: identity\r\n
412 s> Accept-Encoding: identity\r\n
413 s> user-agent: test\r\n
413 s> user-agent: test\r\n
414 s> host: $LOCALIP:$HGPORT\r\n (glob)
414 s> host: $LOCALIP:$HGPORT\r\n (glob)
415 s> \r\n
415 s> \r\n
416 s> makefile('rb', None)
416 s> makefile('rb', None)
417 s> HTTP/1.1 301 Redirect\r\n
417 s> HTTP/1.1 301 Redirect\r\n
418 s> Server: testing stub value\r\n
418 s> Server: testing stub value\r\n
419 s> Date: $HTTP_DATE$\r\n
419 s> Date: $HTTP_DATE$\r\n
420 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
420 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
421 s> Content-Type: text/plain\r\n
421 s> Content-Type: text/plain\r\n
422 s> Content-Length: 10\r\n
422 s> Content-Length: 10\r\n
423 s> \r\n
423 s> \r\n
424 s> redirected
424 s> redirected
425 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
425 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
426 s> Accept-Encoding: identity\r\n
426 s> Accept-Encoding: identity\r\n
427 s> user-agent: test\r\n
427 s> user-agent: test\r\n
428 s> host: $LOCALIP:$HGPORT\r\n (glob)
428 s> host: $LOCALIP:$HGPORT\r\n (glob)
429 s> \r\n
429 s> \r\n
430 s> makefile('rb', None)
430 s> makefile('rb', None)
431 s> HTTP/1.1 200 Script output follows\r\n
431 s> HTTP/1.1 200 Script output follows\r\n
432 s> Server: testing stub value\r\n
432 s> Server: testing stub value\r\n
433 s> Date: $HTTP_DATE$\r\n
433 s> Date: $HTTP_DATE$\r\n
434 s> Content-Type: application/mercurial-0.1\r\n
434 s> Content-Type: application/mercurial-0.1\r\n
435 s> Content-Length: 467\r\n
435 s> Content-Length: 467\r\n
436 s> \r\n
436 s> \r\n
437 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
437 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
438
438
439 Test with the HTTP peer
439 Test with the HTTP peer
440
440
441 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
441 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
442 > command heads
442 > command heads
443 > EOF
443 > EOF
444 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
444 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
445 s> Accept-Encoding: identity\r\n
445 s> Accept-Encoding: identity\r\n
446 s> accept: application/mercurial-0.1\r\n
446 s> accept: application/mercurial-0.1\r\n
447 s> host: $LOCALIP:$HGPORT\r\n (glob)
447 s> host: $LOCALIP:$HGPORT\r\n (glob)
448 s> user-agent: Mercurial debugwireproto\r\n
448 s> user-agent: Mercurial debugwireproto\r\n
449 s> \r\n
449 s> \r\n
450 s> makefile('rb', None)
450 s> makefile('rb', None)
451 s> HTTP/1.1 301 Redirect\r\n
451 s> HTTP/1.1 301 Redirect\r\n
452 s> Server: testing stub value\r\n
452 s> Server: testing stub value\r\n
453 s> Date: $HTTP_DATE$\r\n
453 s> Date: $HTTP_DATE$\r\n
454 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
454 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
455 s> Content-Type: text/plain\r\n
455 s> Content-Type: text/plain\r\n
456 s> Content-Length: 10\r\n
456 s> Content-Length: 10\r\n
457 s> \r\n
457 s> \r\n
458 s> redirected
458 s> redirected
459 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
459 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
460 s> Accept-Encoding: identity\r\n
460 s> Accept-Encoding: identity\r\n
461 s> accept: application/mercurial-0.1\r\n
461 s> accept: application/mercurial-0.1\r\n
462 s> host: $LOCALIP:$HGPORT\r\n (glob)
462 s> host: $LOCALIP:$HGPORT\r\n (glob)
463 s> user-agent: Mercurial debugwireproto\r\n
463 s> user-agent: Mercurial debugwireproto\r\n
464 s> \r\n
464 s> \r\n
465 s> makefile('rb', None)
465 s> makefile('rb', None)
466 s> HTTP/1.1 200 Script output follows\r\n
466 s> HTTP/1.1 200 Script output follows\r\n
467 s> Server: testing stub value\r\n
467 s> Server: testing stub value\r\n
468 s> Date: $HTTP_DATE$\r\n
468 s> Date: $HTTP_DATE$\r\n
469 s> Content-Type: application/mercurial-0.1\r\n
469 s> Content-Type: application/mercurial-0.1\r\n
470 s> Content-Length: 467\r\n
470 s> Content-Length: 467\r\n
471 s> \r\n
471 s> \r\n
472 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
472 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
473 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
473 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
474 sending heads command
474 sending heads command
475 s> GET /redirected?cmd=heads HTTP/1.1\r\n
475 s> GET /redirected?cmd=heads HTTP/1.1\r\n
476 s> Accept-Encoding: identity\r\n
476 s> Accept-Encoding: identity\r\n
477 s> vary: X-HgProto-1\r\n
477 s> vary: X-HgProto-1\r\n
478 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
478 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
479 s> accept: application/mercurial-0.1\r\n
479 s> accept: application/mercurial-0.1\r\n
480 s> host: $LOCALIP:$HGPORT\r\n (glob)
480 s> host: $LOCALIP:$HGPORT\r\n (glob)
481 s> user-agent: Mercurial debugwireproto\r\n
481 s> user-agent: Mercurial debugwireproto\r\n
482 s> \r\n
482 s> \r\n
483 s> makefile('rb', None)
483 s> makefile('rb', None)
484 s> HTTP/1.1 200 Script output follows\r\n
484 s> HTTP/1.1 200 Script output follows\r\n
485 s> Server: testing stub value\r\n
485 s> Server: testing stub value\r\n
486 s> Date: $HTTP_DATE$\r\n
486 s> Date: $HTTP_DATE$\r\n
487 s> Content-Type: application/mercurial-0.1\r\n
487 s> Content-Type: application/mercurial-0.1\r\n
488 s> Content-Length: 41\r\n
488 s> Content-Length: 41\r\n
489 s> \r\n
489 s> \r\n
490 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
490 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
491 response: [
491 response: [
492 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
492 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
493 ]
493 ]
494 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
494 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
495
495
496 $ killdaemons.py
496 $ killdaemons.py
497
497
498 Now test a variation where we strip the query string from the redirect URL.
498 Now test a variation where we strip the query string from the redirect URL.
499 (SCM Manager apparently did this and clients would recover from it)
499 (SCM Manager apparently did this and clients would recover from it)
500
500
501 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
501 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
502 > --config server.compressionengines=zlib \
502 > --config server.compressionengines=zlib \
503 > --config testing.redirectqs=false \
503 > --config testing.redirectqs=false \
504 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
504 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
505 $ cat hg.pid > $DAEMON_PIDS
505 $ cat hg.pid > $DAEMON_PIDS
506
506
507 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
507 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
508 > httprequest GET /redirector?cmd=capabilities
508 > httprequest GET /redirector?cmd=capabilities
509 > user-agent: test
509 > user-agent: test
510 > EOF
510 > EOF
511 using raw connection to peer
511 using raw connection to peer
512 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
512 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
513 s> Accept-Encoding: identity\r\n
513 s> Accept-Encoding: identity\r\n
514 s> user-agent: test\r\n
514 s> user-agent: test\r\n
515 s> host: $LOCALIP:$HGPORT\r\n (glob)
515 s> host: $LOCALIP:$HGPORT\r\n (glob)
516 s> \r\n
516 s> \r\n
517 s> makefile('rb', None)
517 s> makefile('rb', None)
518 s> HTTP/1.1 301 Redirect\r\n
518 s> HTTP/1.1 301 Redirect\r\n
519 s> Server: testing stub value\r\n
519 s> Server: testing stub value\r\n
520 s> Date: $HTTP_DATE$\r\n
520 s> Date: $HTTP_DATE$\r\n
521 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
521 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
522 s> Content-Type: text/plain\r\n
522 s> Content-Type: text/plain\r\n
523 s> Content-Length: 10\r\n
523 s> Content-Length: 10\r\n
524 s> \r\n
524 s> \r\n
525 s> redirected
525 s> redirected
526 s> GET /redirected HTTP/1.1\r\n
526 s> GET /redirected HTTP/1.1\r\n
527 s> Accept-Encoding: identity\r\n
527 s> Accept-Encoding: identity\r\n
528 s> user-agent: test\r\n
528 s> user-agent: test\r\n
529 s> host: $LOCALIP:$HGPORT\r\n (glob)
529 s> host: $LOCALIP:$HGPORT\r\n (glob)
530 s> \r\n
530 s> \r\n
531 s> makefile('rb', None)
531 s> makefile('rb', None)
532 s> HTTP/1.1 200 Script output follows\r\n
532 s> HTTP/1.1 200 Script output follows\r\n
533 s> Server: testing stub value\r\n
533 s> Server: testing stub value\r\n
534 s> Date: $HTTP_DATE$\r\n
534 s> Date: $HTTP_DATE$\r\n
535 s> ETag: W/"*"\r\n (glob)
535 s> ETag: W/"*"\r\n (glob)
536 s> Content-Type: text/html; charset=ascii\r\n
536 s> Content-Type: text/html; charset=ascii\r\n
537 s> Transfer-Encoding: chunked\r\n
537 s> Transfer-Encoding: chunked\r\n
538 s> \r\n
538 s> \r\n
539 s> 414\r\n
539 s> 414\r\n
540 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
540 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
541 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
541 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
542 s> <head>\n
542 s> <head>\n
543 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
543 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
544 s> <meta name="robots" content="index, nofollow" />\n
544 s> <meta name="robots" content="index, nofollow" />\n
545 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
545 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
546 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
546 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
547 s> \n
547 s> \n
548 s> <title>redirected: log</title>\n
548 s> <title>redirected: log</title>\n
549 s> <link rel="alternate" type="application/atom+xml"\n
549 s> <link rel="alternate" type="application/atom+xml"\n
550 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
550 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
551 s> <link rel="alternate" type="application/rss+xml"\n
551 s> <link rel="alternate" type="application/rss+xml"\n
552 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
552 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
553 s> </head>\n
553 s> </head>\n
554 s> <body>\n
554 s> <body>\n
555 s> \n
555 s> \n
556 s> <div class="container">\n
556 s> <div class="container">\n
557 s> <div class="menu">\n
557 s> <div class="menu">\n
558 s> <div class="logo">\n
558 s> <div class="logo">\n
559 s> <a href="https://mercurial-scm.org/">\n
559 s> <a href="https://mercurial-scm.org/">\n
560 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
560 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
561 s> </div>\n
561 s> </div>\n
562 s> <ul>\n
562 s> <ul>\n
563 s> <li class="active">log</li>\n
563 s> <li class="active">log</li>\n
564 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
564 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
565 s> <li><a href="/redirected/tags">tags</a></li>\n
565 s> <li><a href="/redirected/tags">tags</a></li>\n
566 s> <li><a href="
566 s> <li><a href="
567 s> \r\n
567 s> \r\n
568 s> 810\r\n
568 s> 810\r\n
569 s> /redirected/bookmarks">bookmarks</a></li>\n
569 s> /redirected/bookmarks">bookmarks</a></li>\n
570 s> <li><a href="/redirected/branches">branches</a></li>\n
570 s> <li><a href="/redirected/branches">branches</a></li>\n
571 s> </ul>\n
571 s> </ul>\n
572 s> <ul>\n
572 s> <ul>\n
573 s> <li><a href="/redirected/rev/tip">changeset</a></li>\n
573 s> <li><a href="/redirected/rev/tip">changeset</a></li>\n
574 s> <li><a href="/redirected/file/tip">browse</a></li>\n
574 s> <li><a href="/redirected/file/tip">browse</a></li>\n
575 s> </ul>\n
575 s> </ul>\n
576 s> <ul>\n
576 s> <ul>\n
577 s> \n
577 s> \n
578 s> </ul>\n
578 s> </ul>\n
579 s> <ul>\n
579 s> <ul>\n
580 s> <li><a href="/redirected/help">help</a></li>\n
580 s> <li><a href="/redirected/help">help</a></li>\n
581 s> </ul>\n
581 s> </ul>\n
582 s> <div class="atom-logo">\n
582 s> <div class="atom-logo">\n
583 s> <a href="/redirected/atom-log" title="subscribe to atom feed">\n
583 s> <a href="/redirected/atom-log" title="subscribe to atom feed">\n
584 s> <img class="atom-logo" src="/redirected/static/feed-icon-14x14.png" alt="atom feed" />\n
584 s> <img class="atom-logo" src="/redirected/static/feed-icon-14x14.png" alt="atom feed" />\n
585 s> </a>\n
585 s> </a>\n
586 s> </div>\n
586 s> </div>\n
587 s> </div>\n
587 s> </div>\n
588 s> \n
588 s> \n
589 s> <div class="main">\n
589 s> <div class="main">\n
590 s> <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/redirected">redirected</a> </h2>\n
590 s> <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/redirected">redirected</a> </h2>\n
591 s> <h3>log</h3>\n
591 s> <h3>log</h3>\n
592 s> \n
592 s> \n
593 s> \n
593 s> \n
594 s> <form class="search" action="/redirected/log">\n
594 s> <form class="search" action="/redirected/log">\n
595 s> \n
595 s> \n
596 s> <p><input name="rev" id="search1" type="text" size="30" value="" /></p>\n
596 s> <p><input name="rev" id="search1" type="text" size="30" value="" /></p>\n
597 s> <div id="hint">Find changesets by keywords (author, files, the commit message), revision\n
597 s> <div id="hint">Find changesets by keywords (author, files, the commit message), revision\n
598 s> number or hash, or <a href="/redirected/help/revsets">revset expression</a>.</div>\n
598 s> number or hash, or <a href="/redirected/help/revsets">revset expression</a>.</div>\n
599 s> </form>\n
599 s> </form>\n
600 s> \n
600 s> \n
601 s> <div class="navigate">\n
601 s> <div class="navigate">\n
602 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
602 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
603 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
603 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
604 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
604 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
605 s> </div>\n
605 s> </div>\n
606 s> \n
606 s> \n
607 s> <table class="bigtable">\n
607 s> <table class="bigtable">\n
608 s> <thead>\n
608 s> <thead>\n
609 s> <tr>\n
609 s> <tr>\n
610 s> <th class="age">age</th>\n
610 s> <th class="age">age</th>\n
611 s> <th class="author">author</th>\n
611 s> <th class="author">author</th>\n
612 s> <th class="description">description</th>\n
612 s> <th class="description">description</th>\n
613 s> </tr>\n
613 s> </tr>\n
614 s> </thead>\n
614 s> </thead>\n
615 s> <tbody class="stripes2">\n
615 s> <tbody class="stripes2">\n
616 s> <tr>\n
616 s> <tr>\n
617 s> <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>\n
617 s> <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>\n
618 s> <td class="author">test</td>\n
618 s> <td class="author">test</td>\n
619 s> <td class="description">\n
619 s> <td class="description">\n
620 s> <a href="/redirected/rev/96ee1d7354c4">initial</a>\n
620 s> <a href="/redirected/rev/96ee1d7354c4">initial</a>\n
621 s> <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span> \n
621 s> <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span> \n
622 s> </td>\n
622 s> </td>\n
623 s> </tr>\n
623 s> </tr>\n
624 s> \n
624 s> \n
625 s> </tbody>\n
625 s> </tbody>\n
626 s> </table>\n
626 s> </table>\n
627 s> \n
627 s> \n
628 s> <div class="navigate">\n
628 s> <div class="navigate">\n
629 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
629 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
630 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
630 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
631 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
631 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
632 s> </div>\n
632 s> </div>\n
633 s> \n
633 s> \n
634 s> <script type="text/javascript">\n
634 s> <script type="text/javascript">\n
635 s> ajaxScrollInit(\n
635 s> ajaxScrollInit(\n
636 s> \'/redirected/shortlog/%next%\',\n
636 s> \'/redirected/shortlog/%next%\',\n
637 s> \'\', <!-- NEXTHASH\n
637 s> \'\', <!-- NEXTHASH\n
638 s> function (htmlText) {
638 s> function (htmlText) {
639 s> \r\n
639 s> \r\n
640 s> 14a\r\n
640 s> 14a\r\n
641 s> \n
641 s> \n
642 s> var m = htmlText.match(/\'(\\w+)\', <!-- NEXTHASH/);\n
642 s> var m = htmlText.match(/\'(\\w+)\', <!-- NEXTHASH/);\n
643 s> return m ? m[1] : null;\n
643 s> return m ? m[1] : null;\n
644 s> },\n
644 s> },\n
645 s> \'.bigtable > tbody\',\n
645 s> \'.bigtable > tbody\',\n
646 s> \'<tr class="%class%">\\\n
646 s> \'<tr class="%class%">\\\n
647 s> <td colspan="3" style="text-align: center;">%text%</td>\\\n
647 s> <td colspan="3" style="text-align: center;">%text%</td>\\\n
648 s> </tr>\'\n
648 s> </tr>\'\n
649 s> );\n
649 s> );\n
650 s> </script>\n
650 s> </script>\n
651 s> \n
651 s> \n
652 s> </div>\n
652 s> </div>\n
653 s> </div>\n
653 s> </div>\n
654 s> \n
654 s> \n
655 s> \n
655 s> \n
656 s> \n
656 s> \n
657 s> </body>\n
657 s> </body>\n
658 s> </html>\n
658 s> </html>\n
659 s> \n
659 s> \n
660 s> \r\n
660 s> \r\n
661 s> 0\r\n
661 s> 0\r\n
662 s> \r\n
662 s> \r\n
663
663
664 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
664 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
665 > command heads
665 > command heads
666 > EOF
666 > EOF
667 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
667 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
668 s> Accept-Encoding: identity\r\n
668 s> Accept-Encoding: identity\r\n
669 s> accept: application/mercurial-0.1\r\n
669 s> accept: application/mercurial-0.1\r\n
670 s> host: $LOCALIP:$HGPORT\r\n (glob)
670 s> host: $LOCALIP:$HGPORT\r\n (glob)
671 s> user-agent: Mercurial debugwireproto\r\n
671 s> user-agent: Mercurial debugwireproto\r\n
672 s> \r\n
672 s> \r\n
673 s> makefile('rb', None)
673 s> makefile('rb', None)
674 s> HTTP/1.1 301 Redirect\r\n
674 s> HTTP/1.1 301 Redirect\r\n
675 s> Server: testing stub value\r\n
675 s> Server: testing stub value\r\n
676 s> Date: $HTTP_DATE$\r\n
676 s> Date: $HTTP_DATE$\r\n
677 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
677 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
678 s> Content-Type: text/plain\r\n
678 s> Content-Type: text/plain\r\n
679 s> Content-Length: 10\r\n
679 s> Content-Length: 10\r\n
680 s> \r\n
680 s> \r\n
681 s> redirected
681 s> redirected
682 s> GET /redirected HTTP/1.1\r\n
682 s> GET /redirected HTTP/1.1\r\n
683 s> Accept-Encoding: identity\r\n
683 s> Accept-Encoding: identity\r\n
684 s> accept: application/mercurial-0.1\r\n
684 s> accept: application/mercurial-0.1\r\n
685 s> host: $LOCALIP:$HGPORT\r\n (glob)
685 s> host: $LOCALIP:$HGPORT\r\n (glob)
686 s> user-agent: Mercurial debugwireproto\r\n
686 s> user-agent: Mercurial debugwireproto\r\n
687 s> \r\n
687 s> \r\n
688 s> makefile('rb', None)
688 s> makefile('rb', None)
689 s> HTTP/1.1 200 Script output follows\r\n
689 s> HTTP/1.1 200 Script output follows\r\n
690 s> Server: testing stub value\r\n
690 s> Server: testing stub value\r\n
691 s> Date: $HTTP_DATE$\r\n
691 s> Date: $HTTP_DATE$\r\n
692 s> ETag: W/"*"\r\n (glob)
692 s> ETag: W/"*"\r\n (glob)
693 s> Content-Type: text/html; charset=ascii\r\n
693 s> Content-Type: text/html; charset=ascii\r\n
694 s> Transfer-Encoding: chunked\r\n
694 s> Transfer-Encoding: chunked\r\n
695 s> \r\n
695 s> \r\n
696 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
696 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
697 s> 414\r\n
697 s> 414\r\n
698 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
698 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
699 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
699 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
700 s> <head>\n
700 s> <head>\n
701 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
701 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
702 s> <meta name="robots" content="index, nofollow" />\n
702 s> <meta name="robots" content="index, nofollow" />\n
703 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
703 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
704 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
704 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
705 s> \n
705 s> \n
706 s> <title>redirected: log</title>\n
706 s> <title>redirected: log</title>\n
707 s> <link rel="alternate" type="application/atom+xml"\n
707 s> <link rel="alternate" type="application/atom+xml"\n
708 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
708 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
709 s> <link rel="alternate" type="application/rss+xml"\n
709 s> <link rel="alternate" type="application/rss+xml"\n
710 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
710 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
711 s> </head>\n
711 s> </head>\n
712 s> <body>\n
712 s> <body>\n
713 s> \n
713 s> \n
714 s> <div class="container">\n
714 s> <div class="container">\n
715 s> <div class="menu">\n
715 s> <div class="menu">\n
716 s> <div class="logo">\n
716 s> <div class="logo">\n
717 s> <a href="https://mercurial-scm.org/">\n
717 s> <a href="https://mercurial-scm.org/">\n
718 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
718 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
719 s> </div>\n
719 s> </div>\n
720 s> <ul>\n
720 s> <ul>\n
721 s> <li class="active">log</li>\n
721 s> <li class="active">log</li>\n
722 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
722 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
723 s> <li><a href="/redirected/tags">tags</a
723 s> <li><a href="/redirected/tags">tags</a
724 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
724 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
725 s> Accept-Encoding: identity\r\n
725 s> Accept-Encoding: identity\r\n
726 s> accept: application/mercurial-0.1\r\n
726 s> accept: application/mercurial-0.1\r\n
727 s> host: $LOCALIP:$HGPORT\r\n (glob)
727 s> host: $LOCALIP:$HGPORT\r\n (glob)
728 s> user-agent: Mercurial debugwireproto\r\n
728 s> user-agent: Mercurial debugwireproto\r\n
729 s> \r\n
729 s> \r\n
730 s> makefile('rb', None)
730 s> makefile('rb', None)
731 s> HTTP/1.1 200 Script output follows\r\n
731 s> HTTP/1.1 200 Script output follows\r\n
732 s> Server: testing stub value\r\n
732 s> Server: testing stub value\r\n
733 s> Date: $HTTP_DATE$\r\n
733 s> Date: $HTTP_DATE$\r\n
734 s> Content-Type: application/mercurial-0.1\r\n
734 s> Content-Type: application/mercurial-0.1\r\n
735 s> Content-Length: 467\r\n
735 s> Content-Length: 467\r\n
736 s> \r\n
736 s> \r\n
737 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
737 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
738 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
738 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
739 sending heads command
739 sending heads command
740 s> GET /redirected?cmd=heads HTTP/1.1\r\n
740 s> GET /redirected?cmd=heads HTTP/1.1\r\n
741 s> Accept-Encoding: identity\r\n
741 s> Accept-Encoding: identity\r\n
742 s> vary: X-HgProto-1\r\n
742 s> vary: X-HgProto-1\r\n
743 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
743 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
744 s> accept: application/mercurial-0.1\r\n
744 s> accept: application/mercurial-0.1\r\n
745 s> host: $LOCALIP:$HGPORT\r\n (glob)
745 s> host: $LOCALIP:$HGPORT\r\n (glob)
746 s> user-agent: Mercurial debugwireproto\r\n
746 s> user-agent: Mercurial debugwireproto\r\n
747 s> \r\n
747 s> \r\n
748 s> makefile('rb', None)
748 s> makefile('rb', None)
749 s> HTTP/1.1 200 Script output follows\r\n
749 s> HTTP/1.1 200 Script output follows\r\n
750 s> Server: testing stub value\r\n
750 s> Server: testing stub value\r\n
751 s> Date: $HTTP_DATE$\r\n
751 s> Date: $HTTP_DATE$\r\n
752 s> Content-Type: application/mercurial-0.1\r\n
752 s> Content-Type: application/mercurial-0.1\r\n
753 s> Content-Length: 41\r\n
753 s> Content-Length: 41\r\n
754 s> \r\n
754 s> \r\n
755 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
755 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
756 response: [
756 response: [
757 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
757 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
758 ]
758 ]
759 (sent 4 HTTP requests and * bytes; received * bytes in responses) (glob)
759 (sent 4 HTTP requests and * bytes; received * bytes in responses) (glob)
@@ -1,422 +1,423 b''
1 $ . $TESTDIR/wireprotohelpers.sh
1 $ . $TESTDIR/wireprotohelpers.sh
2 $ cat >> $HGRCPATH << EOF
2 $ cat >> $HGRCPATH << EOF
3 > [extensions]
3 > [extensions]
4 > blackbox =
4 > blackbox =
5 > [blackbox]
5 > [blackbox]
6 > track = simplecache
6 > track = simplecache
7 > EOF
7 > EOF
8 $ hg init server
8 $ hg init server
9 $ enablehttpv2 server
9 $ enablehttpv2 server
10 $ cd server
10 $ cd server
11 $ cat >> .hg/hgrc << EOF
11 $ cat >> .hg/hgrc << EOF
12 > [extensions]
12 > [extensions]
13 > simplecache = $TESTDIR/wireprotosimplecache.py
13 > simplecache = $TESTDIR/wireprotosimplecache.py
14 > EOF
14 > EOF
15
15
16 $ echo a0 > a
16 $ echo a0 > a
17 $ echo b0 > b
17 $ echo b0 > b
18 $ hg -q commit -A -m 'commit 0'
18 $ hg -q commit -A -m 'commit 0'
19 $ echo a1 > a
19 $ echo a1 > a
20 $ hg commit -m 'commit 1'
20 $ hg commit -m 'commit 1'
21 $ echo b1 > b
21 $ echo b1 > b
22 $ hg commit -m 'commit 2'
22 $ hg commit -m 'commit 2'
23 $ echo a2 > a
23 $ echo a2 > a
24 $ echo b2 > b
24 $ echo b2 > b
25 $ hg commit -m 'commit 3'
25 $ hg commit -m 'commit 3'
26
26
27 $ hg log -G -T '{rev}:{node} {desc}'
27 $ hg log -G -T '{rev}:{node} {desc}'
28 @ 3:50590a86f3ff5d1e9a1624a7a6957884565cc8e8 commit 3
28 @ 3:50590a86f3ff5d1e9a1624a7a6957884565cc8e8 commit 3
29 |
29 |
30 o 2:4d01eda50c6ac5f7e89cbe1880143a32f559c302 commit 2
30 o 2:4d01eda50c6ac5f7e89cbe1880143a32f559c302 commit 2
31 |
31 |
32 o 1:4432d83626e8a98655f062ec1f2a43b07f7fbbb0 commit 1
32 o 1:4432d83626e8a98655f062ec1f2a43b07f7fbbb0 commit 1
33 |
33 |
34 o 0:3390ef850073fbc2f0dfff2244342c8e9229013a commit 0
34 o 0:3390ef850073fbc2f0dfff2244342c8e9229013a commit 0
35
35
36
36
37 $ hg --debug debugindex -m
37 $ hg --debug debugindex -m
38 rev linkrev nodeid p1 p2
38 rev linkrev nodeid p1 p2
39 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
39 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
40 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
40 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
41 2 2 a8853dafacfca6fc807055a660d8b835141a3bb4 a988fb43583e871d1ed5750ee074c6d840bbbfc8 0000000000000000000000000000000000000000
41 2 2 a8853dafacfca6fc807055a660d8b835141a3bb4 a988fb43583e871d1ed5750ee074c6d840bbbfc8 0000000000000000000000000000000000000000
42 3 3 3fe11dfbb13645782b0addafbe75a87c210ffddc a8853dafacfca6fc807055a660d8b835141a3bb4 0000000000000000000000000000000000000000
42 3 3 3fe11dfbb13645782b0addafbe75a87c210ffddc a8853dafacfca6fc807055a660d8b835141a3bb4 0000000000000000000000000000000000000000
43
43
44 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
44 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
45 $ cat hg.pid > $DAEMON_PIDS
45 $ cat hg.pid > $DAEMON_PIDS
46
46
47 Performing the same request should result in same result, with 2nd response
47 Performing the same request should result in same result, with 2nd response
48 coming from cache.
48 coming from cache.
49
49
50 $ sendhttpv2peer << EOF
50 $ sendhttpv2peer << EOF
51 > command manifestdata
51 > command manifestdata
52 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
52 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
53 > tree eval:b''
53 > tree eval:b''
54 > fields eval:[b'parents']
54 > fields eval:[b'parents']
55 > EOF
55 > EOF
56 creating http peer for wire protocol version 2
56 creating http peer for wire protocol version 2
57 sending manifestdata command
57 sending manifestdata command
58 response: gen[
58 response: gen[
59 {
59 {
60 b'totalitems': 1
60 b'totalitems': 1
61 },
61 },
62 {
62 {
63 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
63 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
64 b'parents': [
64 b'parents': [
65 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
65 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
66 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
66 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
67 ]
67 ]
68 }
68 }
69 ]
69 ]
70
70
71 $ sendhttpv2peer << EOF
71 $ sendhttpv2peer << EOF
72 > command manifestdata
72 > command manifestdata
73 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
73 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
74 > tree eval:b''
74 > tree eval:b''
75 > fields eval:[b'parents']
75 > fields eval:[b'parents']
76 > EOF
76 > EOF
77 creating http peer for wire protocol version 2
77 creating http peer for wire protocol version 2
78 sending manifestdata command
78 sending manifestdata command
79 response: gen[
79 response: gen[
80 {
80 {
81 b'totalitems': 1
81 b'totalitems': 1
82 },
82 },
83 {
83 {
84 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
84 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
85 b'parents': [
85 b'parents': [
86 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
86 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
87 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
87 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
88 ]
88 ]
89 }
89 }
90 ]
90 ]
91
91
92 Sending different request doesn't yield cache hit.
92 Sending different request doesn't yield cache hit.
93
93
94 $ sendhttpv2peer << EOF
94 $ sendhttpv2peer << EOF
95 > command manifestdata
95 > command manifestdata
96 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41', b'\xa9\x88\xfb\x43\x58\x3e\x87\x1d\x1e\xd5\x75\x0e\xe0\x74\xc6\xd8\x40\xbb\xbf\xc8']
96 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41', b'\xa9\x88\xfb\x43\x58\x3e\x87\x1d\x1e\xd5\x75\x0e\xe0\x74\xc6\xd8\x40\xbb\xbf\xc8']
97 > tree eval:b''
97 > tree eval:b''
98 > fields eval:[b'parents']
98 > fields eval:[b'parents']
99 > EOF
99 > EOF
100 creating http peer for wire protocol version 2
100 creating http peer for wire protocol version 2
101 sending manifestdata command
101 sending manifestdata command
102 response: gen[
102 response: gen[
103 {
103 {
104 b'totalitems': 2
104 b'totalitems': 2
105 },
105 },
106 {
106 {
107 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
107 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
108 b'parents': [
108 b'parents': [
109 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
109 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
110 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
110 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
111 ]
111 ]
112 },
112 },
113 {
113 {
114 b'node': b'\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8',
114 b'node': b'\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8',
115 b'parents': [
115 b'parents': [
116 b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
116 b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
117 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
117 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
118 ]
118 ]
119 }
119 }
120 ]
120 ]
121
121
122 $ cat .hg/blackbox.log
122 $ cat .hg/blackbox.log
123 *> cacher constructed for manifestdata (glob)
123 *> cacher constructed for manifestdata (glob)
124 *> cache miss for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
124 *> cache miss for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
125 *> storing cache entry for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
125 *> storing cache entry for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
126 *> cacher constructed for manifestdata (glob)
126 *> cacher constructed for manifestdata (glob)
127 *> cache hit for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
127 *> cache hit for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
128 *> cacher constructed for manifestdata (glob)
128 *> cacher constructed for manifestdata (glob)
129 *> cache miss for 1cf89363ec234c6b92d5961281eaa5713e7493f9 (glob)
129 *> cache miss for 1cf89363ec234c6b92d5961281eaa5713e7493f9 (glob)
130 *> storing cache entry for 1cf89363ec234c6b92d5961281eaa5713e7493f9 (glob)
130 *> storing cache entry for 1cf89363ec234c6b92d5961281eaa5713e7493f9 (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 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
191 *> cache miss for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
192 *> storing cache entry for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
192 *> storing cache entry for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
193 *> cacher constructed for manifestdata (glob)
193 *> cacher constructed for manifestdata (glob)
194 *> cache hit for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
194 *> cache hit for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (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 b'recommendedbatchsize': 100000
361 },
362 },
362 b'pushkey': {
363 b'pushkey': {
363 b'args': {
364 b'args': {
364 b'key': {
365 b'key': {
365 b'required': True,
366 b'required': True,
366 b'type': b'bytes'
367 b'type': b'bytes'
367 },
368 },
368 b'namespace': {
369 b'namespace': {
369 b'required': True,
370 b'required': True,
370 b'type': b'bytes'
371 b'type': b'bytes'
371 },
372 },
372 b'new': {
373 b'new': {
373 b'required': True,
374 b'required': True,
374 b'type': b'bytes'
375 b'type': b'bytes'
375 },
376 },
376 b'old': {
377 b'old': {
377 b'required': True,
378 b'required': True,
378 b'type': b'bytes'
379 b'type': b'bytes'
379 }
380 }
380 },
381 },
381 b'permissions': [
382 b'permissions': [
382 b'push'
383 b'push'
383 ]
384 ]
384 }
385 }
385 },
386 },
386 b'framingmediatypes': [
387 b'framingmediatypes': [
387 b'application/mercurial-exp-framing-0006'
388 b'application/mercurial-exp-framing-0006'
388 ],
389 ],
389 b'pathfilterprefixes': set([
390 b'pathfilterprefixes': set([
390 b'path:',
391 b'path:',
391 b'rootfilesin:'
392 b'rootfilesin:'
392 ]),
393 ]),
393 b'rawrepoformats': [
394 b'rawrepoformats': [
394 b'generaldelta',
395 b'generaldelta',
395 b'revlogv1'
396 b'revlogv1'
396 ]
397 ]
397 }
398 }
398 ]
399 ]
399
400
400 $ test -f .hg/blackbox.log
401 $ test -f .hg/blackbox.log
401 [1]
402 [1]
402
403
403 An error is not cached
404 An error is not cached
404
405
405 $ sendhttpv2peer << EOF
406 $ sendhttpv2peer << EOF
406 > command manifestdata
407 > command manifestdata
407 > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
408 > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
408 > tree eval:b''
409 > tree eval:b''
409 > fields eval:[b'parents']
410 > fields eval:[b'parents']
410 > EOF
411 > EOF
411 creating http peer for wire protocol version 2
412 creating http peer for wire protocol version 2
412 sending manifestdata command
413 sending manifestdata command
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)
414 abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa! (esc)
414 [255]
415 [255]
415
416
416 $ cat .hg/blackbox.log
417 $ cat .hg/blackbox.log
417 *> cacher constructed for manifestdata (glob)
418 *> cacher constructed for manifestdata (glob)
418 *> cache miss for 904560928eb95650358f0829d9399b256822eb26 (glob)
419 *> cache miss for 904560928eb95650358f0829d9399b256822eb26 (glob)
419 *> cacher exiting due to error (glob)
420 *> cacher exiting due to error (glob)
420
421
421 $ killdaemons.py
422 $ killdaemons.py
422 $ rm .hg/blackbox.log
423 $ rm .hg/blackbox.log
@@ -1,668 +1,670 b''
1 #require no-chg
1 #require no-chg
2
2
3 $ . $TESTDIR/wireprotohelpers.sh
3 $ . $TESTDIR/wireprotohelpers.sh
4
4
5 $ hg init server
5 $ hg init server
6
6
7 zstd isn't present in plain builds. Make tests easier by removing
7 zstd isn't present in plain builds. Make tests easier by removing
8 zstd from the equation.
8 zstd from the equation.
9
9
10 $ cat >> server/.hg/hgrc << EOF
10 $ cat >> server/.hg/hgrc << EOF
11 > [server]
11 > [server]
12 > compressionengines = zlib
12 > compressionengines = zlib
13 > EOF
13 > EOF
14
14
15 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
15 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
16 $ cat hg.pid > $DAEMON_PIDS
16 $ cat hg.pid > $DAEMON_PIDS
17
17
18 A normal capabilities request is serviced for version 1
18 A normal capabilities request is serviced for version 1
19
19
20 $ sendhttpraw << EOF
20 $ sendhttpraw << EOF
21 > httprequest GET ?cmd=capabilities
21 > httprequest GET ?cmd=capabilities
22 > user-agent: test
22 > user-agent: test
23 > EOF
23 > EOF
24 using raw connection to peer
24 using raw connection to peer
25 s> GET /?cmd=capabilities HTTP/1.1\r\n
25 s> GET /?cmd=capabilities HTTP/1.1\r\n
26 s> Accept-Encoding: identity\r\n
26 s> Accept-Encoding: identity\r\n
27 s> user-agent: test\r\n
27 s> user-agent: test\r\n
28 s> host: $LOCALIP:$HGPORT\r\n (glob)
28 s> host: $LOCALIP:$HGPORT\r\n (glob)
29 s> \r\n
29 s> \r\n
30 s> makefile('rb', None)
30 s> makefile('rb', None)
31 s> HTTP/1.1 200 Script output follows\r\n
31 s> HTTP/1.1 200 Script output follows\r\n
32 s> Server: testing stub value\r\n
32 s> Server: testing stub value\r\n
33 s> Date: $HTTP_DATE$\r\n
33 s> Date: $HTTP_DATE$\r\n
34 s> Content-Type: application/mercurial-0.1\r\n
34 s> Content-Type: application/mercurial-0.1\r\n
35 s> Content-Length: *\r\n (glob)
35 s> Content-Length: *\r\n (glob)
36 s> \r\n
36 s> \r\n
37 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
37 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
38
38
39 A proper request without the API server enabled returns the legacy response
39 A proper request without the API server enabled returns the legacy response
40
40
41 $ sendhttpraw << EOF
41 $ sendhttpraw << EOF
42 > httprequest GET ?cmd=capabilities
42 > httprequest GET ?cmd=capabilities
43 > user-agent: test
43 > user-agent: test
44 > x-hgupgrade-1: foo
44 > x-hgupgrade-1: foo
45 > x-hgproto-1: cbor
45 > x-hgproto-1: cbor
46 > EOF
46 > EOF
47 using raw connection to peer
47 using raw connection to peer
48 s> GET /?cmd=capabilities HTTP/1.1\r\n
48 s> GET /?cmd=capabilities HTTP/1.1\r\n
49 s> Accept-Encoding: identity\r\n
49 s> Accept-Encoding: identity\r\n
50 s> user-agent: test\r\n
50 s> user-agent: test\r\n
51 s> x-hgproto-1: cbor\r\n
51 s> x-hgproto-1: cbor\r\n
52 s> x-hgupgrade-1: foo\r\n
52 s> x-hgupgrade-1: foo\r\n
53 s> host: $LOCALIP:$HGPORT\r\n (glob)
53 s> host: $LOCALIP:$HGPORT\r\n (glob)
54 s> \r\n
54 s> \r\n
55 s> makefile('rb', None)
55 s> makefile('rb', None)
56 s> HTTP/1.1 200 Script output follows\r\n
56 s> HTTP/1.1 200 Script output follows\r\n
57 s> Server: testing stub value\r\n
57 s> Server: testing stub value\r\n
58 s> Date: $HTTP_DATE$\r\n
58 s> Date: $HTTP_DATE$\r\n
59 s> Content-Type: application/mercurial-0.1\r\n
59 s> Content-Type: application/mercurial-0.1\r\n
60 s> Content-Length: *\r\n (glob)
60 s> Content-Length: *\r\n (glob)
61 s> \r\n
61 s> \r\n
62 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
62 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
63
63
64 Restart with just API server enabled. This enables serving the new format.
64 Restart with just API server enabled. This enables serving the new format.
65
65
66 $ killdaemons.py
66 $ killdaemons.py
67 $ cat error.log
67 $ cat error.log
68
68
69 $ cat >> server/.hg/hgrc << EOF
69 $ cat >> server/.hg/hgrc << EOF
70 > [experimental]
70 > [experimental]
71 > web.apiserver = true
71 > web.apiserver = true
72 > EOF
72 > EOF
73
73
74 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
74 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
75 $ cat hg.pid > $DAEMON_PIDS
75 $ cat hg.pid > $DAEMON_PIDS
76
76
77 X-HgUpgrade-<N> without CBOR advertisement uses legacy response
77 X-HgUpgrade-<N> without CBOR advertisement uses legacy response
78
78
79 $ sendhttpraw << EOF
79 $ sendhttpraw << EOF
80 > httprequest GET ?cmd=capabilities
80 > httprequest GET ?cmd=capabilities
81 > user-agent: test
81 > user-agent: test
82 > x-hgupgrade-1: foo bar
82 > x-hgupgrade-1: foo bar
83 > EOF
83 > EOF
84 using raw connection to peer
84 using raw connection to peer
85 s> GET /?cmd=capabilities HTTP/1.1\r\n
85 s> GET /?cmd=capabilities HTTP/1.1\r\n
86 s> Accept-Encoding: identity\r\n
86 s> Accept-Encoding: identity\r\n
87 s> user-agent: test\r\n
87 s> user-agent: test\r\n
88 s> x-hgupgrade-1: foo bar\r\n
88 s> x-hgupgrade-1: foo bar\r\n
89 s> host: $LOCALIP:$HGPORT\r\n (glob)
89 s> host: $LOCALIP:$HGPORT\r\n (glob)
90 s> \r\n
90 s> \r\n
91 s> makefile('rb', None)
91 s> makefile('rb', None)
92 s> HTTP/1.1 200 Script output follows\r\n
92 s> HTTP/1.1 200 Script output follows\r\n
93 s> Server: testing stub value\r\n
93 s> Server: testing stub value\r\n
94 s> Date: $HTTP_DATE$\r\n
94 s> Date: $HTTP_DATE$\r\n
95 s> Content-Type: application/mercurial-0.1\r\n
95 s> Content-Type: application/mercurial-0.1\r\n
96 s> Content-Length: *\r\n (glob)
96 s> Content-Length: *\r\n (glob)
97 s> \r\n
97 s> \r\n
98 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
98 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
99
99
100 X-HgUpgrade-<N> without known serialization in X-HgProto-<N> uses legacy response
100 X-HgUpgrade-<N> without known serialization in X-HgProto-<N> uses legacy response
101
101
102 $ sendhttpraw << EOF
102 $ sendhttpraw << EOF
103 > httprequest GET ?cmd=capabilities
103 > httprequest GET ?cmd=capabilities
104 > user-agent: test
104 > user-agent: test
105 > x-hgupgrade-1: foo bar
105 > x-hgupgrade-1: foo bar
106 > x-hgproto-1: some value
106 > x-hgproto-1: some value
107 > EOF
107 > EOF
108 using raw connection to peer
108 using raw connection to peer
109 s> GET /?cmd=capabilities HTTP/1.1\r\n
109 s> GET /?cmd=capabilities HTTP/1.1\r\n
110 s> Accept-Encoding: identity\r\n
110 s> Accept-Encoding: identity\r\n
111 s> user-agent: test\r\n
111 s> user-agent: test\r\n
112 s> x-hgproto-1: some value\r\n
112 s> x-hgproto-1: some value\r\n
113 s> x-hgupgrade-1: foo bar\r\n
113 s> x-hgupgrade-1: foo bar\r\n
114 s> host: $LOCALIP:$HGPORT\r\n (glob)
114 s> host: $LOCALIP:$HGPORT\r\n (glob)
115 s> \r\n
115 s> \r\n
116 s> makefile('rb', None)
116 s> makefile('rb', None)
117 s> HTTP/1.1 200 Script output follows\r\n
117 s> HTTP/1.1 200 Script output follows\r\n
118 s> Server: testing stub value\r\n
118 s> Server: testing stub value\r\n
119 s> Date: $HTTP_DATE$\r\n
119 s> Date: $HTTP_DATE$\r\n
120 s> Content-Type: application/mercurial-0.1\r\n
120 s> Content-Type: application/mercurial-0.1\r\n
121 s> Content-Length: *\r\n (glob)
121 s> Content-Length: *\r\n (glob)
122 s> \r\n
122 s> \r\n
123 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
123 s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
124
124
125 X-HgUpgrade-<N> + X-HgProto-<N> headers trigger new response format
125 X-HgUpgrade-<N> + X-HgProto-<N> headers trigger new response format
126
126
127 $ sendhttpraw << EOF
127 $ sendhttpraw << EOF
128 > httprequest GET ?cmd=capabilities
128 > httprequest GET ?cmd=capabilities
129 > user-agent: test
129 > user-agent: test
130 > x-hgupgrade-1: foo bar
130 > x-hgupgrade-1: foo bar
131 > x-hgproto-1: cbor
131 > x-hgproto-1: cbor
132 > EOF
132 > EOF
133 using raw connection to peer
133 using raw connection to peer
134 s> GET /?cmd=capabilities HTTP/1.1\r\n
134 s> GET /?cmd=capabilities HTTP/1.1\r\n
135 s> Accept-Encoding: identity\r\n
135 s> Accept-Encoding: identity\r\n
136 s> user-agent: test\r\n
136 s> user-agent: test\r\n
137 s> x-hgproto-1: cbor\r\n
137 s> x-hgproto-1: cbor\r\n
138 s> x-hgupgrade-1: foo bar\r\n
138 s> x-hgupgrade-1: foo bar\r\n
139 s> host: $LOCALIP:$HGPORT\r\n (glob)
139 s> host: $LOCALIP:$HGPORT\r\n (glob)
140 s> \r\n
140 s> \r\n
141 s> makefile('rb', None)
141 s> makefile('rb', None)
142 s> HTTP/1.1 200 OK\r\n
142 s> HTTP/1.1 200 OK\r\n
143 s> Server: testing stub value\r\n
143 s> Server: testing stub value\r\n
144 s> Date: $HTTP_DATE$\r\n
144 s> Date: $HTTP_DATE$\r\n
145 s> Content-Type: application/mercurial-cbor\r\n
145 s> Content-Type: application/mercurial-cbor\r\n
146 s> Content-Length: *\r\n (glob)
146 s> Content-Length: *\r\n (glob)
147 s> \r\n
147 s> \r\n
148 s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
148 s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
149 cbor> [
149 cbor> [
150 {
150 {
151 b'apibase': b'api/',
151 b'apibase': b'api/',
152 b'apis': {},
152 b'apis': {},
153 b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
153 b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
154 }
154 }
155 ]
155 ]
156
156
157 Restart server to enable HTTPv2
157 Restart server to enable HTTPv2
158
158
159 $ killdaemons.py
159 $ killdaemons.py
160 $ enablehttpv2 server
160 $ enablehttpv2 server
161 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
161 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
162 $ cat hg.pid > $DAEMON_PIDS
162 $ cat hg.pid > $DAEMON_PIDS
163
163
164 Only requested API services are returned
164 Only requested API services are returned
165
165
166 $ sendhttpraw << EOF
166 $ sendhttpraw << EOF
167 > httprequest GET ?cmd=capabilities
167 > httprequest GET ?cmd=capabilities
168 > user-agent: test
168 > user-agent: test
169 > x-hgupgrade-1: foo bar
169 > x-hgupgrade-1: foo bar
170 > x-hgproto-1: cbor
170 > x-hgproto-1: cbor
171 > EOF
171 > EOF
172 using raw connection to peer
172 using raw connection to peer
173 s> GET /?cmd=capabilities HTTP/1.1\r\n
173 s> GET /?cmd=capabilities HTTP/1.1\r\n
174 s> Accept-Encoding: identity\r\n
174 s> Accept-Encoding: identity\r\n
175 s> user-agent: test\r\n
175 s> user-agent: test\r\n
176 s> x-hgproto-1: cbor\r\n
176 s> x-hgproto-1: cbor\r\n
177 s> x-hgupgrade-1: foo bar\r\n
177 s> x-hgupgrade-1: foo bar\r\n
178 s> host: $LOCALIP:$HGPORT\r\n (glob)
178 s> host: $LOCALIP:$HGPORT\r\n (glob)
179 s> \r\n
179 s> \r\n
180 s> makefile('rb', None)
180 s> makefile('rb', None)
181 s> HTTP/1.1 200 OK\r\n
181 s> HTTP/1.1 200 OK\r\n
182 s> Server: testing stub value\r\n
182 s> Server: testing stub value\r\n
183 s> Date: $HTTP_DATE$\r\n
183 s> Date: $HTTP_DATE$\r\n
184 s> Content-Type: application/mercurial-cbor\r\n
184 s> Content-Type: application/mercurial-cbor\r\n
185 s> Content-Length: *\r\n (glob)
185 s> Content-Length: *\r\n (glob)
186 s> \r\n
186 s> \r\n
187 s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
187 s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
188 cbor> [
188 cbor> [
189 {
189 {
190 b'apibase': b'api/',
190 b'apibase': b'api/',
191 b'apis': {},
191 b'apis': {},
192 b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
192 b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
193 }
193 }
194 ]
194 ]
195
195
196 Request for HTTPv2 service returns information about it
196 Request for HTTPv2 service returns information about it
197
197
198 $ sendhttpraw << EOF
198 $ sendhttpraw << EOF
199 > httprequest GET ?cmd=capabilities
199 > httprequest GET ?cmd=capabilities
200 > user-agent: test
200 > user-agent: test
201 > x-hgupgrade-1: exp-http-v2-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\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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
219 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
220 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 b'recommendedbatchsize': 100000
374 },
375 },
375 b'pushkey': {
376 b'pushkey': {
376 b'args': {
377 b'args': {
377 b'key': {
378 b'key': {
378 b'required': True,
379 b'required': True,
379 b'type': b'bytes'
380 b'type': b'bytes'
380 },
381 },
381 b'namespace': {
382 b'namespace': {
382 b'required': True,
383 b'required': True,
383 b'type': b'bytes'
384 b'type': b'bytes'
384 },
385 },
385 b'new': {
386 b'new': {
386 b'required': True,
387 b'required': True,
387 b'type': b'bytes'
388 b'type': b'bytes'
388 },
389 },
389 b'old': {
390 b'old': {
390 b'required': True,
391 b'required': True,
391 b'type': b'bytes'
392 b'type': b'bytes'
392 }
393 }
393 },
394 },
394 b'permissions': [
395 b'permissions': [
395 b'push'
396 b'push'
396 ]
397 ]
397 }
398 }
398 },
399 },
399 b'framingmediatypes': [
400 b'framingmediatypes': [
400 b'application/mercurial-exp-framing-0006'
401 b'application/mercurial-exp-framing-0006'
401 ],
402 ],
402 b'pathfilterprefixes': set([
403 b'pathfilterprefixes': set([
403 b'path:',
404 b'path:',
404 b'rootfilesin:'
405 b'rootfilesin:'
405 ]),
406 ]),
406 b'rawrepoformats': [
407 b'rawrepoformats': [
407 b'generaldelta',
408 b'generaldelta',
408 b'revlogv1'
409 b'revlogv1'
409 ]
410 ]
410 }
411 }
411 },
412 },
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'
413 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'
413 }
414 }
414 ]
415 ]
415
416
416 capabilities command returns expected info
417 capabilities command returns expected info
417
418
418 $ sendhttpv2peerhandshake << EOF
419 $ sendhttpv2peerhandshake << EOF
419 > command capabilities
420 > command capabilities
420 > EOF
421 > EOF
421 creating http peer for wire protocol version 2
422 creating http peer for wire protocol version 2
422 s> GET /?cmd=capabilities HTTP/1.1\r\n
423 s> GET /?cmd=capabilities HTTP/1.1\r\n
423 s> Accept-Encoding: identity\r\n
424 s> Accept-Encoding: identity\r\n
424 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
425 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
425 s> x-hgproto-1: cbor\r\n
426 s> x-hgproto-1: cbor\r\n
426 s> x-hgupgrade-1: exp-http-v2-0002\r\n
427 s> x-hgupgrade-1: exp-http-v2-0002\r\n
427 s> accept: application/mercurial-0.1\r\n
428 s> accept: application/mercurial-0.1\r\n
428 s> host: $LOCALIP:$HGPORT\r\n (glob)
429 s> host: $LOCALIP:$HGPORT\r\n (glob)
429 s> user-agent: Mercurial debugwireproto\r\n
430 s> user-agent: Mercurial debugwireproto\r\n
430 s> \r\n
431 s> \r\n
431 s> makefile('rb', None)
432 s> makefile('rb', None)
432 s> HTTP/1.1 200 OK\r\n
433 s> HTTP/1.1 200 OK\r\n
433 s> Server: testing stub value\r\n
434 s> Server: testing stub value\r\n
434 s> Date: $HTTP_DATE$\r\n
435 s> Date: $HTTP_DATE$\r\n
435 s> Content-Type: application/mercurial-cbor\r\n
436 s> Content-Type: application/mercurial-cbor\r\n
436 s> Content-Length: *\r\n (glob)
437 s> Content-Length: *\r\n (glob)
437 s> \r\n
438 s> \r\n
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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
439 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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
439 sending capabilities command
440 sending capabilities command
440 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
441 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
441 s> Accept-Encoding: identity\r\n
442 s> Accept-Encoding: identity\r\n
442 s> accept: application/mercurial-exp-framing-0006\r\n
443 s> accept: application/mercurial-exp-framing-0006\r\n
443 s> content-type: application/mercurial-exp-framing-0006\r\n
444 s> content-type: application/mercurial-exp-framing-0006\r\n
444 s> content-length: 63\r\n
445 s> content-length: 63\r\n
445 s> host: $LOCALIP:$HGPORT\r\n (glob)
446 s> host: $LOCALIP:$HGPORT\r\n (glob)
446 s> user-agent: Mercurial debugwireproto\r\n
447 s> user-agent: Mercurial debugwireproto\r\n
447 s> \r\n
448 s> \r\n
448 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x13\x00\x00\x01\x00\x01\x00\x11\xa1DnameLcapabilities
449 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x13\x00\x00\x01\x00\x01\x00\x11\xa1DnameLcapabilities
449 s> makefile('rb', None)
450 s> makefile('rb', None)
450 s> HTTP/1.1 200 OK\r\n
451 s> HTTP/1.1 200 OK\r\n
451 s> Server: testing stub value\r\n
452 s> Server: testing stub value\r\n
452 s> Date: $HTTP_DATE$\r\n
453 s> Date: $HTTP_DATE$\r\n
453 s> Content-Type: application/mercurial-exp-framing-0006\r\n
454 s> Content-Type: application/mercurial-exp-framing-0006\r\n
454 s> Transfer-Encoding: chunked\r\n
455 s> Transfer-Encoding: chunked\r\n
455 s> \r\n
456 s> \r\n
456 s> 11\r\n
457 s> 11\r\n
457 s> \t\x00\x00\x01\x00\x02\x01\x92
458 s> \t\x00\x00\x01\x00\x02\x01\x92
458 s> Hidentity
459 s> Hidentity
459 s> \r\n
460 s> \r\n
460 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
461 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
461 s> 13\r\n
462 s> 13\r\n
462 s> \x0b\x00\x00\x01\x00\x02\x041
463 s> \x0b\x00\x00\x01\x00\x02\x041
463 s> \xa1FstatusBok
464 s> \xa1FstatusBok
464 s> \r\n
465 s> \r\n
465 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
466 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
466 s> 508\r\n
467 s> 522\r\n
467 s> \x00\x05\x00\x01\x00\x02\x041
468 s> \x1a\x05\x00\x01\x00\x02\x041
468 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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1
469 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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1
469 s> \r\n
470 s> \r\n
470 received frame(size=1280; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
471 received frame(size=1306; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
471 s> 8\r\n
472 s> 8\r\n
472 s> \x00\x00\x00\x01\x00\x02\x002
473 s> \x00\x00\x00\x01\x00\x02\x002
473 s> \r\n
474 s> \r\n
474 s> 0\r\n
475 s> 0\r\n
475 s> \r\n
476 s> \r\n
476 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
477 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
477 response: gen[
478 response: gen[
478 {
479 {
479 b'commands': {
480 b'commands': {
480 b'branchmap': {
481 b'branchmap': {
481 b'args': {},
482 b'args': {},
482 b'permissions': [
483 b'permissions': [
483 b'pull'
484 b'pull'
484 ]
485 ]
485 },
486 },
486 b'capabilities': {
487 b'capabilities': {
487 b'args': {},
488 b'args': {},
488 b'permissions': [
489 b'permissions': [
489 b'pull'
490 b'pull'
490 ]
491 ]
491 },
492 },
492 b'changesetdata': {
493 b'changesetdata': {
493 b'args': {
494 b'args': {
494 b'fields': {
495 b'fields': {
495 b'default': set([]),
496 b'default': set([]),
496 b'required': False,
497 b'required': False,
497 b'type': b'set',
498 b'type': b'set',
498 b'validvalues': set([
499 b'validvalues': set([
499 b'bookmarks',
500 b'bookmarks',
500 b'parents',
501 b'parents',
501 b'phase',
502 b'phase',
502 b'revision'
503 b'revision'
503 ])
504 ])
504 },
505 },
505 b'noderange': {
506 b'noderange': {
506 b'default': None,
507 b'default': None,
507 b'required': False,
508 b'required': False,
508 b'type': b'list'
509 b'type': b'list'
509 },
510 },
510 b'nodes': {
511 b'nodes': {
511 b'default': None,
512 b'default': None,
512 b'required': False,
513 b'required': False,
513 b'type': b'list'
514 b'type': b'list'
514 },
515 },
515 b'nodesdepth': {
516 b'nodesdepth': {
516 b'default': None,
517 b'default': None,
517 b'required': False,
518 b'required': False,
518 b'type': b'int'
519 b'type': b'int'
519 }
520 }
520 },
521 },
521 b'permissions': [
522 b'permissions': [
522 b'pull'
523 b'pull'
523 ]
524 ]
524 },
525 },
525 b'filedata': {
526 b'filedata': {
526 b'args': {
527 b'args': {
527 b'fields': {
528 b'fields': {
528 b'default': set([]),
529 b'default': set([]),
529 b'required': False,
530 b'required': False,
530 b'type': b'set',
531 b'type': b'set',
531 b'validvalues': set([
532 b'validvalues': set([
532 b'parents',
533 b'parents',
533 b'revision'
534 b'revision'
534 ])
535 ])
535 },
536 },
536 b'haveparents': {
537 b'haveparents': {
537 b'default': False,
538 b'default': False,
538 b'required': False,
539 b'required': False,
539 b'type': b'bool'
540 b'type': b'bool'
540 },
541 },
541 b'nodes': {
542 b'nodes': {
542 b'required': True,
543 b'required': True,
543 b'type': b'list'
544 b'type': b'list'
544 },
545 },
545 b'path': {
546 b'path': {
546 b'required': True,
547 b'required': True,
547 b'type': b'bytes'
548 b'type': b'bytes'
548 }
549 }
549 },
550 },
550 b'permissions': [
551 b'permissions': [
551 b'pull'
552 b'pull'
552 ]
553 ]
553 },
554 },
554 b'heads': {
555 b'heads': {
555 b'args': {
556 b'args': {
556 b'publiconly': {
557 b'publiconly': {
557 b'default': False,
558 b'default': False,
558 b'required': False,
559 b'required': False,
559 b'type': b'bool'
560 b'type': b'bool'
560 }
561 }
561 },
562 },
562 b'permissions': [
563 b'permissions': [
563 b'pull'
564 b'pull'
564 ]
565 ]
565 },
566 },
566 b'known': {
567 b'known': {
567 b'args': {
568 b'args': {
568 b'nodes': {
569 b'nodes': {
569 b'default': [],
570 b'default': [],
570 b'required': False,
571 b'required': False,
571 b'type': b'list'
572 b'type': b'list'
572 }
573 }
573 },
574 },
574 b'permissions': [
575 b'permissions': [
575 b'pull'
576 b'pull'
576 ]
577 ]
577 },
578 },
578 b'listkeys': {
579 b'listkeys': {
579 b'args': {
580 b'args': {
580 b'namespace': {
581 b'namespace': {
581 b'required': True,
582 b'required': True,
582 b'type': b'bytes'
583 b'type': b'bytes'
583 }
584 }
584 },
585 },
585 b'permissions': [
586 b'permissions': [
586 b'pull'
587 b'pull'
587 ]
588 ]
588 },
589 },
589 b'lookup': {
590 b'lookup': {
590 b'args': {
591 b'args': {
591 b'key': {
592 b'key': {
592 b'required': True,
593 b'required': True,
593 b'type': b'bytes'
594 b'type': b'bytes'
594 }
595 }
595 },
596 },
596 b'permissions': [
597 b'permissions': [
597 b'pull'
598 b'pull'
598 ]
599 ]
599 },
600 },
600 b'manifestdata': {
601 b'manifestdata': {
601 b'args': {
602 b'args': {
602 b'fields': {
603 b'fields': {
603 b'default': set([]),
604 b'default': set([]),
604 b'required': False,
605 b'required': False,
605 b'type': b'set',
606 b'type': b'set',
606 b'validvalues': set([
607 b'validvalues': set([
607 b'parents',
608 b'parents',
608 b'revision'
609 b'revision'
609 ])
610 ])
610 },
611 },
611 b'haveparents': {
612 b'haveparents': {
612 b'default': False,
613 b'default': False,
613 b'required': False,
614 b'required': False,
614 b'type': b'bool'
615 b'type': b'bool'
615 },
616 },
616 b'nodes': {
617 b'nodes': {
617 b'required': True,
618 b'required': True,
618 b'type': b'list'
619 b'type': b'list'
619 },
620 },
620 b'tree': {
621 b'tree': {
621 b'required': True,
622 b'required': True,
622 b'type': b'bytes'
623 b'type': b'bytes'
623 }
624 }
624 },
625 },
625 b'permissions': [
626 b'permissions': [
626 b'pull'
627 b'pull'
627 ]
628 ],
629 b'recommendedbatchsize': 100000
628 },
630 },
629 b'pushkey': {
631 b'pushkey': {
630 b'args': {
632 b'args': {
631 b'key': {
633 b'key': {
632 b'required': True,
634 b'required': True,
633 b'type': b'bytes'
635 b'type': b'bytes'
634 },
636 },
635 b'namespace': {
637 b'namespace': {
636 b'required': True,
638 b'required': True,
637 b'type': b'bytes'
639 b'type': b'bytes'
638 },
640 },
639 b'new': {
641 b'new': {
640 b'required': True,
642 b'required': True,
641 b'type': b'bytes'
643 b'type': b'bytes'
642 },
644 },
643 b'old': {
645 b'old': {
644 b'required': True,
646 b'required': True,
645 b'type': b'bytes'
647 b'type': b'bytes'
646 }
648 }
647 },
649 },
648 b'permissions': [
650 b'permissions': [
649 b'push'
651 b'push'
650 ]
652 ]
651 }
653 }
652 },
654 },
653 b'framingmediatypes': [
655 b'framingmediatypes': [
654 b'application/mercurial-exp-framing-0006'
656 b'application/mercurial-exp-framing-0006'
655 ],
657 ],
656 b'pathfilterprefixes': set([
658 b'pathfilterprefixes': set([
657 b'path:',
659 b'path:',
658 b'rootfilesin:'
660 b'rootfilesin:'
659 ]),
661 ]),
660 b'rawrepoformats': [
662 b'rawrepoformats': [
661 b'generaldelta',
663 b'generaldelta',
662 b'revlogv1'
664 b'revlogv1'
663 ]
665 ]
664 }
666 }
665 ]
667 ]
666 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
668 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
667
669
668 $ cat error.log
670 $ cat error.log
@@ -1,1310 +1,1314 b''
1 $ . $TESTDIR/wireprotohelpers.sh
1 $ . $TESTDIR/wireprotohelpers.sh
2
2
3 $ cat >> $HGRCPATH << EOF
3 $ cat >> $HGRCPATH << EOF
4 > [extensions]
4 > [extensions]
5 > blackbox =
5 > blackbox =
6 > [blackbox]
6 > [blackbox]
7 > track = simplecache
7 > track = simplecache
8 > EOF
8 > EOF
9
9
10 $ hg init server
10 $ hg init server
11 $ enablehttpv2 server
11 $ enablehttpv2 server
12 $ cd server
12 $ cd server
13 $ cat >> .hg/hgrc << EOF
13 $ cat >> .hg/hgrc << EOF
14 > [server]
14 > [server]
15 > compressionengines = zlib
15 > compressionengines = zlib
16 > [extensions]
16 > [extensions]
17 > simplecache = $TESTDIR/wireprotosimplecache.py
17 > simplecache = $TESTDIR/wireprotosimplecache.py
18 > [simplecache]
18 > [simplecache]
19 > cacheapi = true
19 > cacheapi = true
20 > EOF
20 > EOF
21
21
22 $ echo a0 > a
22 $ echo a0 > a
23 $ echo b0 > b
23 $ echo b0 > b
24 $ hg -q commit -A -m 'commit 0'
24 $ hg -q commit -A -m 'commit 0'
25 $ echo a1 > a
25 $ echo a1 > a
26 $ hg commit -m 'commit 1'
26 $ hg commit -m 'commit 1'
27
27
28 $ hg --debug debugindex -m
28 $ hg --debug debugindex -m
29 rev linkrev nodeid p1 p2
29 rev linkrev nodeid p1 p2
30 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
30 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
31 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
31 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
32
32
33 $ hg --config simplecache.redirectsfile=redirects.py serve -p $HGPORT -d --pid-file hg.pid -E error.log
33 $ hg --config simplecache.redirectsfile=redirects.py serve -p $HGPORT -d --pid-file hg.pid -E error.log
34 $ cat hg.pid > $DAEMON_PIDS
34 $ cat hg.pid > $DAEMON_PIDS
35
35
36 $ cat > redirects.py << EOF
36 $ cat > redirects.py << EOF
37 > [
37 > [
38 > {
38 > {
39 > b'name': b'target-a',
39 > b'name': b'target-a',
40 > b'protocol': b'http',
40 > b'protocol': b'http',
41 > b'snirequired': False,
41 > b'snirequired': False,
42 > b'tlsversions': [b'1.2', b'1.3'],
42 > b'tlsversions': [b'1.2', b'1.3'],
43 > b'uris': [b'http://example.com/'],
43 > b'uris': [b'http://example.com/'],
44 > },
44 > },
45 > ]
45 > ]
46 > EOF
46 > EOF
47
47
48 Redirect targets advertised when configured
48 Redirect targets advertised when configured
49
49
50 $ sendhttpv2peerhandshake << EOF
50 $ sendhttpv2peerhandshake << EOF
51 > command capabilities
51 > command capabilities
52 > EOF
52 > EOF
53 creating http peer for wire protocol version 2
53 creating http peer for wire protocol version 2
54 s> GET /?cmd=capabilities HTTP/1.1\r\n
54 s> GET /?cmd=capabilities HTTP/1.1\r\n
55 s> Accept-Encoding: identity\r\n
55 s> Accept-Encoding: identity\r\n
56 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
56 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
57 s> x-hgproto-1: cbor\r\n
57 s> x-hgproto-1: cbor\r\n
58 s> x-hgupgrade-1: exp-http-v2-0002\r\n
58 s> x-hgupgrade-1: exp-http-v2-0002\r\n
59 s> accept: application/mercurial-0.1\r\n
59 s> accept: application/mercurial-0.1\r\n
60 s> host: $LOCALIP:$HGPORT\r\n (glob)
60 s> host: $LOCALIP:$HGPORT\r\n (glob)
61 s> user-agent: Mercurial debugwireproto\r\n
61 s> user-agent: Mercurial debugwireproto\r\n
62 s> \r\n
62 s> \r\n
63 s> makefile('rb', None)
63 s> makefile('rb', None)
64 s> HTTP/1.1 200 OK\r\n
64 s> HTTP/1.1 200 OK\r\n
65 s> Server: testing stub value\r\n
65 s> Server: testing stub value\r\n
66 s> Date: $HTTP_DATE$\r\n
66 s> Date: $HTTP_DATE$\r\n
67 s> Content-Type: application/mercurial-cbor\r\n
67 s> Content-Type: application/mercurial-cbor\r\n
68 s> Content-Length: 1930\r\n
68 s> Content-Length: 1956\r\n
69 s> \r\n
69 s> \r\n
70 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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
70 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
71 (remote redirect target target-a is compatible)
71 (remote redirect target target-a is compatible)
72 sending capabilities command
72 sending capabilities command
73 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
73 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
74 s> Accept-Encoding: identity\r\n
74 s> Accept-Encoding: identity\r\n
75 s> accept: application/mercurial-exp-framing-0006\r\n
75 s> accept: application/mercurial-exp-framing-0006\r\n
76 s> content-type: application/mercurial-exp-framing-0006\r\n
76 s> content-type: application/mercurial-exp-framing-0006\r\n
77 s> content-length: 111\r\n
77 s> content-length: 111\r\n
78 s> host: $LOCALIP:$HGPORT\r\n (glob)
78 s> host: $LOCALIP:$HGPORT\r\n (glob)
79 s> user-agent: Mercurial debugwireproto\r\n
79 s> user-agent: Mercurial debugwireproto\r\n
80 s> \r\n
80 s> \r\n
81 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
81 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
82 s> makefile('rb', None)
82 s> makefile('rb', None)
83 s> HTTP/1.1 200 OK\r\n
83 s> HTTP/1.1 200 OK\r\n
84 s> Server: testing stub value\r\n
84 s> Server: testing stub value\r\n
85 s> Date: $HTTP_DATE$\r\n
85 s> Date: $HTTP_DATE$\r\n
86 s> Content-Type: application/mercurial-exp-framing-0006\r\n
86 s> Content-Type: application/mercurial-exp-framing-0006\r\n
87 s> Transfer-Encoding: chunked\r\n
87 s> Transfer-Encoding: chunked\r\n
88 s> \r\n
88 s> \r\n
89 s> 11\r\n
89 s> 11\r\n
90 s> \t\x00\x00\x01\x00\x02\x01\x92
90 s> \t\x00\x00\x01\x00\x02\x01\x92
91 s> Hidentity
91 s> Hidentity
92 s> \r\n
92 s> \r\n
93 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
93 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
94 s> 13\r\n
94 s> 13\r\n
95 s> \x0b\x00\x00\x01\x00\x02\x041
95 s> \x0b\x00\x00\x01\x00\x02\x041
96 s> \xa1FstatusBok
96 s> \xa1FstatusBok
97 s> \r\n
97 s> \r\n
98 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
98 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
99 s> 588\r\n
99 s> 5a2\r\n
100 s> \x80\x05\x00\x01\x00\x02\x041
100 s> \x9a\x05\x00\x01\x00\x02\x041
101 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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/
101 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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/
102 s> \r\n
102 s> \r\n
103 received frame(size=1408; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
103 received frame(size=1434; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
104 s> 8\r\n
104 s> 8\r\n
105 s> \x00\x00\x00\x01\x00\x02\x002
105 s> \x00\x00\x00\x01\x00\x02\x002
106 s> \r\n
106 s> \r\n
107 s> 0\r\n
107 s> 0\r\n
108 s> \r\n
108 s> \r\n
109 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
109 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
110 response: gen[
110 response: gen[
111 {
111 {
112 b'commands': {
112 b'commands': {
113 b'branchmap': {
113 b'branchmap': {
114 b'args': {},
114 b'args': {},
115 b'permissions': [
115 b'permissions': [
116 b'pull'
116 b'pull'
117 ]
117 ]
118 },
118 },
119 b'capabilities': {
119 b'capabilities': {
120 b'args': {},
120 b'args': {},
121 b'permissions': [
121 b'permissions': [
122 b'pull'
122 b'pull'
123 ]
123 ]
124 },
124 },
125 b'changesetdata': {
125 b'changesetdata': {
126 b'args': {
126 b'args': {
127 b'fields': {
127 b'fields': {
128 b'default': set([]),
128 b'default': set([]),
129 b'required': False,
129 b'required': False,
130 b'type': b'set',
130 b'type': b'set',
131 b'validvalues': set([
131 b'validvalues': set([
132 b'bookmarks',
132 b'bookmarks',
133 b'parents',
133 b'parents',
134 b'phase',
134 b'phase',
135 b'revision'
135 b'revision'
136 ])
136 ])
137 },
137 },
138 b'noderange': {
138 b'noderange': {
139 b'default': None,
139 b'default': None,
140 b'required': False,
140 b'required': False,
141 b'type': b'list'
141 b'type': b'list'
142 },
142 },
143 b'nodes': {
143 b'nodes': {
144 b'default': None,
144 b'default': None,
145 b'required': False,
145 b'required': False,
146 b'type': b'list'
146 b'type': b'list'
147 },
147 },
148 b'nodesdepth': {
148 b'nodesdepth': {
149 b'default': None,
149 b'default': None,
150 b'required': False,
150 b'required': False,
151 b'type': b'int'
151 b'type': b'int'
152 }
152 }
153 },
153 },
154 b'permissions': [
154 b'permissions': [
155 b'pull'
155 b'pull'
156 ]
156 ]
157 },
157 },
158 b'filedata': {
158 b'filedata': {
159 b'args': {
159 b'args': {
160 b'fields': {
160 b'fields': {
161 b'default': set([]),
161 b'default': set([]),
162 b'required': False,
162 b'required': False,
163 b'type': b'set',
163 b'type': b'set',
164 b'validvalues': set([
164 b'validvalues': set([
165 b'parents',
165 b'parents',
166 b'revision'
166 b'revision'
167 ])
167 ])
168 },
168 },
169 b'haveparents': {
169 b'haveparents': {
170 b'default': False,
170 b'default': False,
171 b'required': False,
171 b'required': False,
172 b'type': b'bool'
172 b'type': b'bool'
173 },
173 },
174 b'nodes': {
174 b'nodes': {
175 b'required': True,
175 b'required': True,
176 b'type': b'list'
176 b'type': b'list'
177 },
177 },
178 b'path': {
178 b'path': {
179 b'required': True,
179 b'required': True,
180 b'type': b'bytes'
180 b'type': b'bytes'
181 }
181 }
182 },
182 },
183 b'permissions': [
183 b'permissions': [
184 b'pull'
184 b'pull'
185 ]
185 ]
186 },
186 },
187 b'heads': {
187 b'heads': {
188 b'args': {
188 b'args': {
189 b'publiconly': {
189 b'publiconly': {
190 b'default': False,
190 b'default': False,
191 b'required': False,
191 b'required': False,
192 b'type': b'bool'
192 b'type': b'bool'
193 }
193 }
194 },
194 },
195 b'permissions': [
195 b'permissions': [
196 b'pull'
196 b'pull'
197 ]
197 ]
198 },
198 },
199 b'known': {
199 b'known': {
200 b'args': {
200 b'args': {
201 b'nodes': {
201 b'nodes': {
202 b'default': [],
202 b'default': [],
203 b'required': False,
203 b'required': False,
204 b'type': b'list'
204 b'type': b'list'
205 }
205 }
206 },
206 },
207 b'permissions': [
207 b'permissions': [
208 b'pull'
208 b'pull'
209 ]
209 ]
210 },
210 },
211 b'listkeys': {
211 b'listkeys': {
212 b'args': {
212 b'args': {
213 b'namespace': {
213 b'namespace': {
214 b'required': True,
214 b'required': True,
215 b'type': b'bytes'
215 b'type': b'bytes'
216 }
216 }
217 },
217 },
218 b'permissions': [
218 b'permissions': [
219 b'pull'
219 b'pull'
220 ]
220 ]
221 },
221 },
222 b'lookup': {
222 b'lookup': {
223 b'args': {
223 b'args': {
224 b'key': {
224 b'key': {
225 b'required': True,
225 b'required': True,
226 b'type': b'bytes'
226 b'type': b'bytes'
227 }
227 }
228 },
228 },
229 b'permissions': [
229 b'permissions': [
230 b'pull'
230 b'pull'
231 ]
231 ]
232 },
232 },
233 b'manifestdata': {
233 b'manifestdata': {
234 b'args': {
234 b'args': {
235 b'fields': {
235 b'fields': {
236 b'default': set([]),
236 b'default': set([]),
237 b'required': False,
237 b'required': False,
238 b'type': b'set',
238 b'type': b'set',
239 b'validvalues': set([
239 b'validvalues': set([
240 b'parents',
240 b'parents',
241 b'revision'
241 b'revision'
242 ])
242 ])
243 },
243 },
244 b'haveparents': {
244 b'haveparents': {
245 b'default': False,
245 b'default': False,
246 b'required': False,
246 b'required': False,
247 b'type': b'bool'
247 b'type': b'bool'
248 },
248 },
249 b'nodes': {
249 b'nodes': {
250 b'required': True,
250 b'required': True,
251 b'type': b'list'
251 b'type': b'list'
252 },
252 },
253 b'tree': {
253 b'tree': {
254 b'required': True,
254 b'required': True,
255 b'type': b'bytes'
255 b'type': b'bytes'
256 }
256 }
257 },
257 },
258 b'permissions': [
258 b'permissions': [
259 b'pull'
259 b'pull'
260 ]
260 ],
261 b'recommendedbatchsize': 100000
261 },
262 },
262 b'pushkey': {
263 b'pushkey': {
263 b'args': {
264 b'args': {
264 b'key': {
265 b'key': {
265 b'required': True,
266 b'required': True,
266 b'type': b'bytes'
267 b'type': b'bytes'
267 },
268 },
268 b'namespace': {
269 b'namespace': {
269 b'required': True,
270 b'required': True,
270 b'type': b'bytes'
271 b'type': b'bytes'
271 },
272 },
272 b'new': {
273 b'new': {
273 b'required': True,
274 b'required': True,
274 b'type': b'bytes'
275 b'type': b'bytes'
275 },
276 },
276 b'old': {
277 b'old': {
277 b'required': True,
278 b'required': True,
278 b'type': b'bytes'
279 b'type': b'bytes'
279 }
280 }
280 },
281 },
281 b'permissions': [
282 b'permissions': [
282 b'push'
283 b'push'
283 ]
284 ]
284 }
285 }
285 },
286 },
286 b'framingmediatypes': [
287 b'framingmediatypes': [
287 b'application/mercurial-exp-framing-0006'
288 b'application/mercurial-exp-framing-0006'
288 ],
289 ],
289 b'pathfilterprefixes': set([
290 b'pathfilterprefixes': set([
290 b'path:',
291 b'path:',
291 b'rootfilesin:'
292 b'rootfilesin:'
292 ]),
293 ]),
293 b'rawrepoformats': [
294 b'rawrepoformats': [
294 b'generaldelta',
295 b'generaldelta',
295 b'revlogv1'
296 b'revlogv1'
296 ],
297 ],
297 b'redirect': {
298 b'redirect': {
298 b'hashes': [
299 b'hashes': [
299 b'sha256',
300 b'sha256',
300 b'sha1'
301 b'sha1'
301 ],
302 ],
302 b'targets': [
303 b'targets': [
303 {
304 {
304 b'name': b'target-a',
305 b'name': b'target-a',
305 b'protocol': b'http',
306 b'protocol': b'http',
306 b'snirequired': False,
307 b'snirequired': False,
307 b'tlsversions': [
308 b'tlsversions': [
308 b'1.2',
309 b'1.2',
309 b'1.3'
310 b'1.3'
310 ],
311 ],
311 b'uris': [
312 b'uris': [
312 b'http://example.com/'
313 b'http://example.com/'
313 ]
314 ]
314 }
315 }
315 ]
316 ]
316 }
317 }
317 }
318 }
318 ]
319 ]
319 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
320 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
320
321
321 Unknown protocol is filtered from compatible targets
322 Unknown protocol is filtered from compatible targets
322
323
323 $ cat > redirects.py << EOF
324 $ cat > redirects.py << EOF
324 > [
325 > [
325 > {
326 > {
326 > b'name': b'target-a',
327 > b'name': b'target-a',
327 > b'protocol': b'http',
328 > b'protocol': b'http',
328 > b'uris': [b'http://example.com/'],
329 > b'uris': [b'http://example.com/'],
329 > },
330 > },
330 > {
331 > {
331 > b'name': b'target-b',
332 > b'name': b'target-b',
332 > b'protocol': b'unknown',
333 > b'protocol': b'unknown',
333 > b'uris': [b'unknown://example.com/'],
334 > b'uris': [b'unknown://example.com/'],
334 > },
335 > },
335 > ]
336 > ]
336 > EOF
337 > EOF
337
338
338 $ sendhttpv2peerhandshake << EOF
339 $ sendhttpv2peerhandshake << EOF
339 > command capabilities
340 > command capabilities
340 > EOF
341 > EOF
341 creating http peer for wire protocol version 2
342 creating http peer for wire protocol version 2
342 s> GET /?cmd=capabilities HTTP/1.1\r\n
343 s> GET /?cmd=capabilities HTTP/1.1\r\n
343 s> Accept-Encoding: identity\r\n
344 s> Accept-Encoding: identity\r\n
344 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
345 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
345 s> x-hgproto-1: cbor\r\n
346 s> x-hgproto-1: cbor\r\n
346 s> x-hgupgrade-1: exp-http-v2-0002\r\n
347 s> x-hgupgrade-1: exp-http-v2-0002\r\n
347 s> accept: application/mercurial-0.1\r\n
348 s> accept: application/mercurial-0.1\r\n
348 s> host: $LOCALIP:$HGPORT\r\n (glob)
349 s> host: $LOCALIP:$HGPORT\r\n (glob)
349 s> user-agent: Mercurial debugwireproto\r\n
350 s> user-agent: Mercurial debugwireproto\r\n
350 s> \r\n
351 s> \r\n
351 s> makefile('rb', None)
352 s> makefile('rb', None)
352 s> HTTP/1.1 200 OK\r\n
353 s> HTTP/1.1 200 OK\r\n
353 s> Server: testing stub value\r\n
354 s> Server: testing stub value\r\n
354 s> Date: $HTTP_DATE$\r\n
355 s> Date: $HTTP_DATE$\r\n
355 s> Content-Type: application/mercurial-cbor\r\n
356 s> Content-Type: application/mercurial-cbor\r\n
356 s> Content-Length: 1957\r\n
357 s> Content-Length: 1983\r\n
357 s> \r\n
358 s> \r\n
358 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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
359 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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
359 (remote redirect target target-a is compatible)
360 (remote redirect target target-a is compatible)
360 (remote redirect target target-b uses unsupported protocol: unknown)
361 (remote redirect target target-b uses unsupported protocol: unknown)
361 sending capabilities command
362 sending capabilities command
362 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
363 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
363 s> Accept-Encoding: identity\r\n
364 s> Accept-Encoding: identity\r\n
364 s> accept: application/mercurial-exp-framing-0006\r\n
365 s> accept: application/mercurial-exp-framing-0006\r\n
365 s> content-type: application/mercurial-exp-framing-0006\r\n
366 s> content-type: application/mercurial-exp-framing-0006\r\n
366 s> content-length: 111\r\n
367 s> content-length: 111\r\n
367 s> host: $LOCALIP:$HGPORT\r\n (glob)
368 s> host: $LOCALIP:$HGPORT\r\n (glob)
368 s> user-agent: Mercurial debugwireproto\r\n
369 s> user-agent: Mercurial debugwireproto\r\n
369 s> \r\n
370 s> \r\n
370 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
371 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
371 s> makefile('rb', None)
372 s> makefile('rb', None)
372 s> HTTP/1.1 200 OK\r\n
373 s> HTTP/1.1 200 OK\r\n
373 s> Server: testing stub value\r\n
374 s> Server: testing stub value\r\n
374 s> Date: $HTTP_DATE$\r\n
375 s> Date: $HTTP_DATE$\r\n
375 s> Content-Type: application/mercurial-exp-framing-0006\r\n
376 s> Content-Type: application/mercurial-exp-framing-0006\r\n
376 s> Transfer-Encoding: chunked\r\n
377 s> Transfer-Encoding: chunked\r\n
377 s> \r\n
378 s> \r\n
378 s> 11\r\n
379 s> 11\r\n
379 s> \t\x00\x00\x01\x00\x02\x01\x92
380 s> \t\x00\x00\x01\x00\x02\x01\x92
380 s> Hidentity
381 s> Hidentity
381 s> \r\n
382 s> \r\n
382 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
383 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
383 s> 13\r\n
384 s> 13\r\n
384 s> \x0b\x00\x00\x01\x00\x02\x041
385 s> \x0b\x00\x00\x01\x00\x02\x041
385 s> \xa1FstatusBok
386 s> \xa1FstatusBok
386 s> \r\n
387 s> \r\n
387 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
388 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
388 s> 5a3\r\n
389 s> 5bd\r\n
389 s> \x9b\x05\x00\x01\x00\x02\x041
390 s> \xb5\x05\x00\x01\x00\x02\x041
390 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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/
391 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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/
391 s> \r\n
392 s> \r\n
392 received frame(size=1435; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
393 received frame(size=1461; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
393 s> 8\r\n
394 s> 8\r\n
394 s> \x00\x00\x00\x01\x00\x02\x002
395 s> \x00\x00\x00\x01\x00\x02\x002
395 s> \r\n
396 s> \r\n
396 s> 0\r\n
397 s> 0\r\n
397 s> \r\n
398 s> \r\n
398 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
399 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
399 response: gen[
400 response: gen[
400 {
401 {
401 b'commands': {
402 b'commands': {
402 b'branchmap': {
403 b'branchmap': {
403 b'args': {},
404 b'args': {},
404 b'permissions': [
405 b'permissions': [
405 b'pull'
406 b'pull'
406 ]
407 ]
407 },
408 },
408 b'capabilities': {
409 b'capabilities': {
409 b'args': {},
410 b'args': {},
410 b'permissions': [
411 b'permissions': [
411 b'pull'
412 b'pull'
412 ]
413 ]
413 },
414 },
414 b'changesetdata': {
415 b'changesetdata': {
415 b'args': {
416 b'args': {
416 b'fields': {
417 b'fields': {
417 b'default': set([]),
418 b'default': set([]),
418 b'required': False,
419 b'required': False,
419 b'type': b'set',
420 b'type': b'set',
420 b'validvalues': set([
421 b'validvalues': set([
421 b'bookmarks',
422 b'bookmarks',
422 b'parents',
423 b'parents',
423 b'phase',
424 b'phase',
424 b'revision'
425 b'revision'
425 ])
426 ])
426 },
427 },
427 b'noderange': {
428 b'noderange': {
428 b'default': None,
429 b'default': None,
429 b'required': False,
430 b'required': False,
430 b'type': b'list'
431 b'type': b'list'
431 },
432 },
432 b'nodes': {
433 b'nodes': {
433 b'default': None,
434 b'default': None,
434 b'required': False,
435 b'required': False,
435 b'type': b'list'
436 b'type': b'list'
436 },
437 },
437 b'nodesdepth': {
438 b'nodesdepth': {
438 b'default': None,
439 b'default': None,
439 b'required': False,
440 b'required': False,
440 b'type': b'int'
441 b'type': b'int'
441 }
442 }
442 },
443 },
443 b'permissions': [
444 b'permissions': [
444 b'pull'
445 b'pull'
445 ]
446 ]
446 },
447 },
447 b'filedata': {
448 b'filedata': {
448 b'args': {
449 b'args': {
449 b'fields': {
450 b'fields': {
450 b'default': set([]),
451 b'default': set([]),
451 b'required': False,
452 b'required': False,
452 b'type': b'set',
453 b'type': b'set',
453 b'validvalues': set([
454 b'validvalues': set([
454 b'parents',
455 b'parents',
455 b'revision'
456 b'revision'
456 ])
457 ])
457 },
458 },
458 b'haveparents': {
459 b'haveparents': {
459 b'default': False,
460 b'default': False,
460 b'required': False,
461 b'required': False,
461 b'type': b'bool'
462 b'type': b'bool'
462 },
463 },
463 b'nodes': {
464 b'nodes': {
464 b'required': True,
465 b'required': True,
465 b'type': b'list'
466 b'type': b'list'
466 },
467 },
467 b'path': {
468 b'path': {
468 b'required': True,
469 b'required': True,
469 b'type': b'bytes'
470 b'type': b'bytes'
470 }
471 }
471 },
472 },
472 b'permissions': [
473 b'permissions': [
473 b'pull'
474 b'pull'
474 ]
475 ]
475 },
476 },
476 b'heads': {
477 b'heads': {
477 b'args': {
478 b'args': {
478 b'publiconly': {
479 b'publiconly': {
479 b'default': False,
480 b'default': False,
480 b'required': False,
481 b'required': False,
481 b'type': b'bool'
482 b'type': b'bool'
482 }
483 }
483 },
484 },
484 b'permissions': [
485 b'permissions': [
485 b'pull'
486 b'pull'
486 ]
487 ]
487 },
488 },
488 b'known': {
489 b'known': {
489 b'args': {
490 b'args': {
490 b'nodes': {
491 b'nodes': {
491 b'default': [],
492 b'default': [],
492 b'required': False,
493 b'required': False,
493 b'type': b'list'
494 b'type': b'list'
494 }
495 }
495 },
496 },
496 b'permissions': [
497 b'permissions': [
497 b'pull'
498 b'pull'
498 ]
499 ]
499 },
500 },
500 b'listkeys': {
501 b'listkeys': {
501 b'args': {
502 b'args': {
502 b'namespace': {
503 b'namespace': {
503 b'required': True,
504 b'required': True,
504 b'type': b'bytes'
505 b'type': b'bytes'
505 }
506 }
506 },
507 },
507 b'permissions': [
508 b'permissions': [
508 b'pull'
509 b'pull'
509 ]
510 ]
510 },
511 },
511 b'lookup': {
512 b'lookup': {
512 b'args': {
513 b'args': {
513 b'key': {
514 b'key': {
514 b'required': True,
515 b'required': True,
515 b'type': b'bytes'
516 b'type': b'bytes'
516 }
517 }
517 },
518 },
518 b'permissions': [
519 b'permissions': [
519 b'pull'
520 b'pull'
520 ]
521 ]
521 },
522 },
522 b'manifestdata': {
523 b'manifestdata': {
523 b'args': {
524 b'args': {
524 b'fields': {
525 b'fields': {
525 b'default': set([]),
526 b'default': set([]),
526 b'required': False,
527 b'required': False,
527 b'type': b'set',
528 b'type': b'set',
528 b'validvalues': set([
529 b'validvalues': set([
529 b'parents',
530 b'parents',
530 b'revision'
531 b'revision'
531 ])
532 ])
532 },
533 },
533 b'haveparents': {
534 b'haveparents': {
534 b'default': False,
535 b'default': False,
535 b'required': False,
536 b'required': False,
536 b'type': b'bool'
537 b'type': b'bool'
537 },
538 },
538 b'nodes': {
539 b'nodes': {
539 b'required': True,
540 b'required': True,
540 b'type': b'list'
541 b'type': b'list'
541 },
542 },
542 b'tree': {
543 b'tree': {
543 b'required': True,
544 b'required': True,
544 b'type': b'bytes'
545 b'type': b'bytes'
545 }
546 }
546 },
547 },
547 b'permissions': [
548 b'permissions': [
548 b'pull'
549 b'pull'
549 ]
550 ],
551 b'recommendedbatchsize': 100000
550 },
552 },
551 b'pushkey': {
553 b'pushkey': {
552 b'args': {
554 b'args': {
553 b'key': {
555 b'key': {
554 b'required': True,
556 b'required': True,
555 b'type': b'bytes'
557 b'type': b'bytes'
556 },
558 },
557 b'namespace': {
559 b'namespace': {
558 b'required': True,
560 b'required': True,
559 b'type': b'bytes'
561 b'type': b'bytes'
560 },
562 },
561 b'new': {
563 b'new': {
562 b'required': True,
564 b'required': True,
563 b'type': b'bytes'
565 b'type': b'bytes'
564 },
566 },
565 b'old': {
567 b'old': {
566 b'required': True,
568 b'required': True,
567 b'type': b'bytes'
569 b'type': b'bytes'
568 }
570 }
569 },
571 },
570 b'permissions': [
572 b'permissions': [
571 b'push'
573 b'push'
572 ]
574 ]
573 }
575 }
574 },
576 },
575 b'framingmediatypes': [
577 b'framingmediatypes': [
576 b'application/mercurial-exp-framing-0006'
578 b'application/mercurial-exp-framing-0006'
577 ],
579 ],
578 b'pathfilterprefixes': set([
580 b'pathfilterprefixes': set([
579 b'path:',
581 b'path:',
580 b'rootfilesin:'
582 b'rootfilesin:'
581 ]),
583 ]),
582 b'rawrepoformats': [
584 b'rawrepoformats': [
583 b'generaldelta',
585 b'generaldelta',
584 b'revlogv1'
586 b'revlogv1'
585 ],
587 ],
586 b'redirect': {
588 b'redirect': {
587 b'hashes': [
589 b'hashes': [
588 b'sha256',
590 b'sha256',
589 b'sha1'
591 b'sha1'
590 ],
592 ],
591 b'targets': [
593 b'targets': [
592 {
594 {
593 b'name': b'target-a',
595 b'name': b'target-a',
594 b'protocol': b'http',
596 b'protocol': b'http',
595 b'uris': [
597 b'uris': [
596 b'http://example.com/'
598 b'http://example.com/'
597 ]
599 ]
598 },
600 },
599 {
601 {
600 b'name': b'target-b',
602 b'name': b'target-b',
601 b'protocol': b'unknown',
603 b'protocol': b'unknown',
602 b'uris': [
604 b'uris': [
603 b'unknown://example.com/'
605 b'unknown://example.com/'
604 ]
606 ]
605 }
607 }
606 ]
608 ]
607 }
609 }
608 }
610 }
609 ]
611 ]
610 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
612 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
611
613
612 Missing SNI support filters targets that require SNI
614 Missing SNI support filters targets that require SNI
613
615
614 $ cat > nosni.py << EOF
616 $ cat > nosni.py << EOF
615 > from mercurial import sslutil
617 > from mercurial import sslutil
616 > sslutil.hassni = False
618 > sslutil.hassni = False
617 > EOF
619 > EOF
618 $ cat >> $HGRCPATH << EOF
620 $ cat >> $HGRCPATH << EOF
619 > [extensions]
621 > [extensions]
620 > nosni=`pwd`/nosni.py
622 > nosni=`pwd`/nosni.py
621 > EOF
623 > EOF
622
624
623 $ cat > redirects.py << EOF
625 $ cat > redirects.py << EOF
624 > [
626 > [
625 > {
627 > {
626 > b'name': b'target-bad-tls',
628 > b'name': b'target-bad-tls',
627 > b'protocol': b'https',
629 > b'protocol': b'https',
628 > b'uris': [b'https://example.com/'],
630 > b'uris': [b'https://example.com/'],
629 > b'snirequired': True,
631 > b'snirequired': True,
630 > },
632 > },
631 > ]
633 > ]
632 > EOF
634 > EOF
633
635
634 $ sendhttpv2peerhandshake << EOF
636 $ sendhttpv2peerhandshake << EOF
635 > command capabilities
637 > command capabilities
636 > EOF
638 > EOF
637 creating http peer for wire protocol version 2
639 creating http peer for wire protocol version 2
638 s> GET /?cmd=capabilities HTTP/1.1\r\n
640 s> GET /?cmd=capabilities HTTP/1.1\r\n
639 s> Accept-Encoding: identity\r\n
641 s> Accept-Encoding: identity\r\n
640 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
642 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
641 s> x-hgproto-1: cbor\r\n
643 s> x-hgproto-1: cbor\r\n
642 s> x-hgupgrade-1: exp-http-v2-0002\r\n
644 s> x-hgupgrade-1: exp-http-v2-0002\r\n
643 s> accept: application/mercurial-0.1\r\n
645 s> accept: application/mercurial-0.1\r\n
644 s> host: $LOCALIP:$HGPORT\r\n (glob)
646 s> host: $LOCALIP:$HGPORT\r\n (glob)
645 s> user-agent: Mercurial debugwireproto\r\n
647 s> user-agent: Mercurial debugwireproto\r\n
646 s> \r\n
648 s> \r\n
647 s> makefile('rb', None)
649 s> makefile('rb', None)
648 s> HTTP/1.1 200 OK\r\n
650 s> HTTP/1.1 200 OK\r\n
649 s> Server: testing stub value\r\n
651 s> Server: testing stub value\r\n
650 s> Date: $HTTP_DATE$\r\n
652 s> Date: $HTTP_DATE$\r\n
651 s> Content-Type: application/mercurial-cbor\r\n
653 s> Content-Type: application/mercurial-cbor\r\n
652 s> Content-Length: 1917\r\n
654 s> Content-Length: 1943\r\n
653 s> \r\n
655 s> \r\n
654 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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
656 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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
655 (redirect target target-bad-tls requires SNI, which is unsupported)
657 (redirect target target-bad-tls requires SNI, which is unsupported)
656 sending capabilities command
658 sending capabilities command
657 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
659 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
658 s> Accept-Encoding: identity\r\n
660 s> Accept-Encoding: identity\r\n
659 s> accept: application/mercurial-exp-framing-0006\r\n
661 s> accept: application/mercurial-exp-framing-0006\r\n
660 s> content-type: application/mercurial-exp-framing-0006\r\n
662 s> content-type: application/mercurial-exp-framing-0006\r\n
661 s> content-length: 102\r\n
663 s> content-length: 102\r\n
662 s> host: $LOCALIP:$HGPORT\r\n (glob)
664 s> host: $LOCALIP:$HGPORT\r\n (glob)
663 s> user-agent: Mercurial debugwireproto\r\n
665 s> user-agent: Mercurial debugwireproto\r\n
664 s> \r\n
666 s> \r\n
665 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
667 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
666 s> makefile('rb', None)
668 s> makefile('rb', None)
667 s> HTTP/1.1 200 OK\r\n
669 s> HTTP/1.1 200 OK\r\n
668 s> Server: testing stub value\r\n
670 s> Server: testing stub value\r\n
669 s> Date: $HTTP_DATE$\r\n
671 s> Date: $HTTP_DATE$\r\n
670 s> Content-Type: application/mercurial-exp-framing-0006\r\n
672 s> Content-Type: application/mercurial-exp-framing-0006\r\n
671 s> Transfer-Encoding: chunked\r\n
673 s> Transfer-Encoding: chunked\r\n
672 s> \r\n
674 s> \r\n
673 s> 11\r\n
675 s> 11\r\n
674 s> \t\x00\x00\x01\x00\x02\x01\x92
676 s> \t\x00\x00\x01\x00\x02\x01\x92
675 s> Hidentity
677 s> Hidentity
676 s> \r\n
678 s> \r\n
677 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
679 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
678 s> 13\r\n
680 s> 13\r\n
679 s> \x0b\x00\x00\x01\x00\x02\x041
681 s> \x0b\x00\x00\x01\x00\x02\x041
680 s> \xa1FstatusBok
682 s> \xa1FstatusBok
681 s> \r\n
683 s> \r\n
682 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
684 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
683 s> 57b\r\n
685 s> 595\r\n
684 s> s\x05\x00\x01\x00\x02\x041
686 s> \x8d\x05\x00\x01\x00\x02\x041
685 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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
687 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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
686 s> \r\n
688 s> \r\n
687 received frame(size=1395; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
689 received frame(size=1421; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
688 s> 8\r\n
690 s> 8\r\n
689 s> \x00\x00\x00\x01\x00\x02\x002
691 s> \x00\x00\x00\x01\x00\x02\x002
690 s> \r\n
692 s> \r\n
691 s> 0\r\n
693 s> 0\r\n
692 s> \r\n
694 s> \r\n
693 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
695 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
694 response: gen[
696 response: gen[
695 {
697 {
696 b'commands': {
698 b'commands': {
697 b'branchmap': {
699 b'branchmap': {
698 b'args': {},
700 b'args': {},
699 b'permissions': [
701 b'permissions': [
700 b'pull'
702 b'pull'
701 ]
703 ]
702 },
704 },
703 b'capabilities': {
705 b'capabilities': {
704 b'args': {},
706 b'args': {},
705 b'permissions': [
707 b'permissions': [
706 b'pull'
708 b'pull'
707 ]
709 ]
708 },
710 },
709 b'changesetdata': {
711 b'changesetdata': {
710 b'args': {
712 b'args': {
711 b'fields': {
713 b'fields': {
712 b'default': set([]),
714 b'default': set([]),
713 b'required': False,
715 b'required': False,
714 b'type': b'set',
716 b'type': b'set',
715 b'validvalues': set([
717 b'validvalues': set([
716 b'bookmarks',
718 b'bookmarks',
717 b'parents',
719 b'parents',
718 b'phase',
720 b'phase',
719 b'revision'
721 b'revision'
720 ])
722 ])
721 },
723 },
722 b'noderange': {
724 b'noderange': {
723 b'default': None,
725 b'default': None,
724 b'required': False,
726 b'required': False,
725 b'type': b'list'
727 b'type': b'list'
726 },
728 },
727 b'nodes': {
729 b'nodes': {
728 b'default': None,
730 b'default': None,
729 b'required': False,
731 b'required': False,
730 b'type': b'list'
732 b'type': b'list'
731 },
733 },
732 b'nodesdepth': {
734 b'nodesdepth': {
733 b'default': None,
735 b'default': None,
734 b'required': False,
736 b'required': False,
735 b'type': b'int'
737 b'type': b'int'
736 }
738 }
737 },
739 },
738 b'permissions': [
740 b'permissions': [
739 b'pull'
741 b'pull'
740 ]
742 ]
741 },
743 },
742 b'filedata': {
744 b'filedata': {
743 b'args': {
745 b'args': {
744 b'fields': {
746 b'fields': {
745 b'default': set([]),
747 b'default': set([]),
746 b'required': False,
748 b'required': False,
747 b'type': b'set',
749 b'type': b'set',
748 b'validvalues': set([
750 b'validvalues': set([
749 b'parents',
751 b'parents',
750 b'revision'
752 b'revision'
751 ])
753 ])
752 },
754 },
753 b'haveparents': {
755 b'haveparents': {
754 b'default': False,
756 b'default': False,
755 b'required': False,
757 b'required': False,
756 b'type': b'bool'
758 b'type': b'bool'
757 },
759 },
758 b'nodes': {
760 b'nodes': {
759 b'required': True,
761 b'required': True,
760 b'type': b'list'
762 b'type': b'list'
761 },
763 },
762 b'path': {
764 b'path': {
763 b'required': True,
765 b'required': True,
764 b'type': b'bytes'
766 b'type': b'bytes'
765 }
767 }
766 },
768 },
767 b'permissions': [
769 b'permissions': [
768 b'pull'
770 b'pull'
769 ]
771 ]
770 },
772 },
771 b'heads': {
773 b'heads': {
772 b'args': {
774 b'args': {
773 b'publiconly': {
775 b'publiconly': {
774 b'default': False,
776 b'default': False,
775 b'required': False,
777 b'required': False,
776 b'type': b'bool'
778 b'type': b'bool'
777 }
779 }
778 },
780 },
779 b'permissions': [
781 b'permissions': [
780 b'pull'
782 b'pull'
781 ]
783 ]
782 },
784 },
783 b'known': {
785 b'known': {
784 b'args': {
786 b'args': {
785 b'nodes': {
787 b'nodes': {
786 b'default': [],
788 b'default': [],
787 b'required': False,
789 b'required': False,
788 b'type': b'list'
790 b'type': b'list'
789 }
791 }
790 },
792 },
791 b'permissions': [
793 b'permissions': [
792 b'pull'
794 b'pull'
793 ]
795 ]
794 },
796 },
795 b'listkeys': {
797 b'listkeys': {
796 b'args': {
798 b'args': {
797 b'namespace': {
799 b'namespace': {
798 b'required': True,
800 b'required': True,
799 b'type': b'bytes'
801 b'type': b'bytes'
800 }
802 }
801 },
803 },
802 b'permissions': [
804 b'permissions': [
803 b'pull'
805 b'pull'
804 ]
806 ]
805 },
807 },
806 b'lookup': {
808 b'lookup': {
807 b'args': {
809 b'args': {
808 b'key': {
810 b'key': {
809 b'required': True,
811 b'required': True,
810 b'type': b'bytes'
812 b'type': b'bytes'
811 }
813 }
812 },
814 },
813 b'permissions': [
815 b'permissions': [
814 b'pull'
816 b'pull'
815 ]
817 ]
816 },
818 },
817 b'manifestdata': {
819 b'manifestdata': {
818 b'args': {
820 b'args': {
819 b'fields': {
821 b'fields': {
820 b'default': set([]),
822 b'default': set([]),
821 b'required': False,
823 b'required': False,
822 b'type': b'set',
824 b'type': b'set',
823 b'validvalues': set([
825 b'validvalues': set([
824 b'parents',
826 b'parents',
825 b'revision'
827 b'revision'
826 ])
828 ])
827 },
829 },
828 b'haveparents': {
830 b'haveparents': {
829 b'default': False,
831 b'default': False,
830 b'required': False,
832 b'required': False,
831 b'type': b'bool'
833 b'type': b'bool'
832 },
834 },
833 b'nodes': {
835 b'nodes': {
834 b'required': True,
836 b'required': True,
835 b'type': b'list'
837 b'type': b'list'
836 },
838 },
837 b'tree': {
839 b'tree': {
838 b'required': True,
840 b'required': True,
839 b'type': b'bytes'
841 b'type': b'bytes'
840 }
842 }
841 },
843 },
842 b'permissions': [
844 b'permissions': [
843 b'pull'
845 b'pull'
844 ]
846 ],
847 b'recommendedbatchsize': 100000
845 },
848 },
846 b'pushkey': {
849 b'pushkey': {
847 b'args': {
850 b'args': {
848 b'key': {
851 b'key': {
849 b'required': True,
852 b'required': True,
850 b'type': b'bytes'
853 b'type': b'bytes'
851 },
854 },
852 b'namespace': {
855 b'namespace': {
853 b'required': True,
856 b'required': True,
854 b'type': b'bytes'
857 b'type': b'bytes'
855 },
858 },
856 b'new': {
859 b'new': {
857 b'required': True,
860 b'required': True,
858 b'type': b'bytes'
861 b'type': b'bytes'
859 },
862 },
860 b'old': {
863 b'old': {
861 b'required': True,
864 b'required': True,
862 b'type': b'bytes'
865 b'type': b'bytes'
863 }
866 }
864 },
867 },
865 b'permissions': [
868 b'permissions': [
866 b'push'
869 b'push'
867 ]
870 ]
868 }
871 }
869 },
872 },
870 b'framingmediatypes': [
873 b'framingmediatypes': [
871 b'application/mercurial-exp-framing-0006'
874 b'application/mercurial-exp-framing-0006'
872 ],
875 ],
873 b'pathfilterprefixes': set([
876 b'pathfilterprefixes': set([
874 b'path:',
877 b'path:',
875 b'rootfilesin:'
878 b'rootfilesin:'
876 ]),
879 ]),
877 b'rawrepoformats': [
880 b'rawrepoformats': [
878 b'generaldelta',
881 b'generaldelta',
879 b'revlogv1'
882 b'revlogv1'
880 ],
883 ],
881 b'redirect': {
884 b'redirect': {
882 b'hashes': [
885 b'hashes': [
883 b'sha256',
886 b'sha256',
884 b'sha1'
887 b'sha1'
885 ],
888 ],
886 b'targets': [
889 b'targets': [
887 {
890 {
888 b'name': b'target-bad-tls',
891 b'name': b'target-bad-tls',
889 b'protocol': b'https',
892 b'protocol': b'https',
890 b'snirequired': True,
893 b'snirequired': True,
891 b'uris': [
894 b'uris': [
892 b'https://example.com/'
895 b'https://example.com/'
893 ]
896 ]
894 }
897 }
895 ]
898 ]
896 }
899 }
897 }
900 }
898 ]
901 ]
899 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
902 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
900
903
901 $ cat >> $HGRCPATH << EOF
904 $ cat >> $HGRCPATH << EOF
902 > [extensions]
905 > [extensions]
903 > nosni=!
906 > nosni=!
904 > EOF
907 > EOF
905
908
906 Unknown tls value is filtered from compatible targets
909 Unknown tls value is filtered from compatible targets
907
910
908 $ cat > redirects.py << EOF
911 $ cat > redirects.py << EOF
909 > [
912 > [
910 > {
913 > {
911 > b'name': b'target-bad-tls',
914 > b'name': b'target-bad-tls',
912 > b'protocol': b'https',
915 > b'protocol': b'https',
913 > b'uris': [b'https://example.com/'],
916 > b'uris': [b'https://example.com/'],
914 > b'tlsversions': [b'42', b'39'],
917 > b'tlsversions': [b'42', b'39'],
915 > },
918 > },
916 > ]
919 > ]
917 > EOF
920 > EOF
918
921
919 $ sendhttpv2peerhandshake << EOF
922 $ sendhttpv2peerhandshake << EOF
920 > command capabilities
923 > command capabilities
921 > EOF
924 > EOF
922 creating http peer for wire protocol version 2
925 creating http peer for wire protocol version 2
923 s> GET /?cmd=capabilities HTTP/1.1\r\n
926 s> GET /?cmd=capabilities HTTP/1.1\r\n
924 s> Accept-Encoding: identity\r\n
927 s> Accept-Encoding: identity\r\n
925 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
928 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
926 s> x-hgproto-1: cbor\r\n
929 s> x-hgproto-1: cbor\r\n
927 s> x-hgupgrade-1: exp-http-v2-0002\r\n
930 s> x-hgupgrade-1: exp-http-v2-0002\r\n
928 s> accept: application/mercurial-0.1\r\n
931 s> accept: application/mercurial-0.1\r\n
929 s> host: $LOCALIP:$HGPORT\r\n (glob)
932 s> host: $LOCALIP:$HGPORT\r\n (glob)
930 s> user-agent: Mercurial debugwireproto\r\n
933 s> user-agent: Mercurial debugwireproto\r\n
931 s> \r\n
934 s> \r\n
932 s> makefile('rb', None)
935 s> makefile('rb', None)
933 s> HTTP/1.1 200 OK\r\n
936 s> HTTP/1.1 200 OK\r\n
934 s> Server: testing stub value\r\n
937 s> Server: testing stub value\r\n
935 s> Date: $HTTP_DATE$\r\n
938 s> Date: $HTTP_DATE$\r\n
936 s> Content-Type: application/mercurial-cbor\r\n
939 s> Content-Type: application/mercurial-cbor\r\n
937 s> Content-Length: 1923\r\n
940 s> Content-Length: 1949\r\n
938 s> \r\n
941 s> \r\n
939 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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
942 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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
940 (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42)
943 (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42)
941 sending capabilities command
944 sending capabilities command
942 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
945 s> POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
943 s> Accept-Encoding: identity\r\n
946 s> Accept-Encoding: identity\r\n
944 s> accept: application/mercurial-exp-framing-0006\r\n
947 s> accept: application/mercurial-exp-framing-0006\r\n
945 s> content-type: application/mercurial-exp-framing-0006\r\n
948 s> content-type: application/mercurial-exp-framing-0006\r\n
946 s> content-length: 102\r\n
949 s> content-length: 102\r\n
947 s> host: $LOCALIP:$HGPORT\r\n (glob)
950 s> host: $LOCALIP:$HGPORT\r\n (glob)
948 s> user-agent: Mercurial debugwireproto\r\n
951 s> user-agent: Mercurial debugwireproto\r\n
949 s> \r\n
952 s> \r\n
950 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
953 s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
951 s> makefile('rb', None)
954 s> makefile('rb', None)
952 s> HTTP/1.1 200 OK\r\n
955 s> HTTP/1.1 200 OK\r\n
953 s> Server: testing stub value\r\n
956 s> Server: testing stub value\r\n
954 s> Date: $HTTP_DATE$\r\n
957 s> Date: $HTTP_DATE$\r\n
955 s> Content-Type: application/mercurial-exp-framing-0006\r\n
958 s> Content-Type: application/mercurial-exp-framing-0006\r\n
956 s> Transfer-Encoding: chunked\r\n
959 s> Transfer-Encoding: chunked\r\n
957 s> \r\n
960 s> \r\n
958 s> 11\r\n
961 s> 11\r\n
959 s> \t\x00\x00\x01\x00\x02\x01\x92
962 s> \t\x00\x00\x01\x00\x02\x01\x92
960 s> Hidentity
963 s> Hidentity
961 s> \r\n
964 s> \r\n
962 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
965 received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
963 s> 13\r\n
966 s> 13\r\n
964 s> \x0b\x00\x00\x01\x00\x02\x041
967 s> \x0b\x00\x00\x01\x00\x02\x041
965 s> \xa1FstatusBok
968 s> \xa1FstatusBok
966 s> \r\n
969 s> \r\n
967 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
970 received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
968 s> 581\r\n
971 s> 59b\r\n
969 s> y\x05\x00\x01\x00\x02\x041
972 s> \x93\x05\x00\x01\x00\x02\x041
970 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-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
973 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\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
971 s> \r\n
974 s> \r\n
972 received frame(size=1401; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
975 received frame(size=1427; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
973 s> 8\r\n
976 s> 8\r\n
974 s> \x00\x00\x00\x01\x00\x02\x002
977 s> \x00\x00\x00\x01\x00\x02\x002
975 s> \r\n
978 s> \r\n
976 s> 0\r\n
979 s> 0\r\n
977 s> \r\n
980 s> \r\n
978 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
981 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
979 response: gen[
982 response: gen[
980 {
983 {
981 b'commands': {
984 b'commands': {
982 b'branchmap': {
985 b'branchmap': {
983 b'args': {},
986 b'args': {},
984 b'permissions': [
987 b'permissions': [
985 b'pull'
988 b'pull'
986 ]
989 ]
987 },
990 },
988 b'capabilities': {
991 b'capabilities': {
989 b'args': {},
992 b'args': {},
990 b'permissions': [
993 b'permissions': [
991 b'pull'
994 b'pull'
992 ]
995 ]
993 },
996 },
994 b'changesetdata': {
997 b'changesetdata': {
995 b'args': {
998 b'args': {
996 b'fields': {
999 b'fields': {
997 b'default': set([]),
1000 b'default': set([]),
998 b'required': False,
1001 b'required': False,
999 b'type': b'set',
1002 b'type': b'set',
1000 b'validvalues': set([
1003 b'validvalues': set([
1001 b'bookmarks',
1004 b'bookmarks',
1002 b'parents',
1005 b'parents',
1003 b'phase',
1006 b'phase',
1004 b'revision'
1007 b'revision'
1005 ])
1008 ])
1006 },
1009 },
1007 b'noderange': {
1010 b'noderange': {
1008 b'default': None,
1011 b'default': None,
1009 b'required': False,
1012 b'required': False,
1010 b'type': b'list'
1013 b'type': b'list'
1011 },
1014 },
1012 b'nodes': {
1015 b'nodes': {
1013 b'default': None,
1016 b'default': None,
1014 b'required': False,
1017 b'required': False,
1015 b'type': b'list'
1018 b'type': b'list'
1016 },
1019 },
1017 b'nodesdepth': {
1020 b'nodesdepth': {
1018 b'default': None,
1021 b'default': None,
1019 b'required': False,
1022 b'required': False,
1020 b'type': b'int'
1023 b'type': b'int'
1021 }
1024 }
1022 },
1025 },
1023 b'permissions': [
1026 b'permissions': [
1024 b'pull'
1027 b'pull'
1025 ]
1028 ]
1026 },
1029 },
1027 b'filedata': {
1030 b'filedata': {
1028 b'args': {
1031 b'args': {
1029 b'fields': {
1032 b'fields': {
1030 b'default': set([]),
1033 b'default': set([]),
1031 b'required': False,
1034 b'required': False,
1032 b'type': b'set',
1035 b'type': b'set',
1033 b'validvalues': set([
1036 b'validvalues': set([
1034 b'parents',
1037 b'parents',
1035 b'revision'
1038 b'revision'
1036 ])
1039 ])
1037 },
1040 },
1038 b'haveparents': {
1041 b'haveparents': {
1039 b'default': False,
1042 b'default': False,
1040 b'required': False,
1043 b'required': False,
1041 b'type': b'bool'
1044 b'type': b'bool'
1042 },
1045 },
1043 b'nodes': {
1046 b'nodes': {
1044 b'required': True,
1047 b'required': True,
1045 b'type': b'list'
1048 b'type': b'list'
1046 },
1049 },
1047 b'path': {
1050 b'path': {
1048 b'required': True,
1051 b'required': True,
1049 b'type': b'bytes'
1052 b'type': b'bytes'
1050 }
1053 }
1051 },
1054 },
1052 b'permissions': [
1055 b'permissions': [
1053 b'pull'
1056 b'pull'
1054 ]
1057 ]
1055 },
1058 },
1056 b'heads': {
1059 b'heads': {
1057 b'args': {
1060 b'args': {
1058 b'publiconly': {
1061 b'publiconly': {
1059 b'default': False,
1062 b'default': False,
1060 b'required': False,
1063 b'required': False,
1061 b'type': b'bool'
1064 b'type': b'bool'
1062 }
1065 }
1063 },
1066 },
1064 b'permissions': [
1067 b'permissions': [
1065 b'pull'
1068 b'pull'
1066 ]
1069 ]
1067 },
1070 },
1068 b'known': {
1071 b'known': {
1069 b'args': {
1072 b'args': {
1070 b'nodes': {
1073 b'nodes': {
1071 b'default': [],
1074 b'default': [],
1072 b'required': False,
1075 b'required': False,
1073 b'type': b'list'
1076 b'type': b'list'
1074 }
1077 }
1075 },
1078 },
1076 b'permissions': [
1079 b'permissions': [
1077 b'pull'
1080 b'pull'
1078 ]
1081 ]
1079 },
1082 },
1080 b'listkeys': {
1083 b'listkeys': {
1081 b'args': {
1084 b'args': {
1082 b'namespace': {
1085 b'namespace': {
1083 b'required': True,
1086 b'required': True,
1084 b'type': b'bytes'
1087 b'type': b'bytes'
1085 }
1088 }
1086 },
1089 },
1087 b'permissions': [
1090 b'permissions': [
1088 b'pull'
1091 b'pull'
1089 ]
1092 ]
1090 },
1093 },
1091 b'lookup': {
1094 b'lookup': {
1092 b'args': {
1095 b'args': {
1093 b'key': {
1096 b'key': {
1094 b'required': True,
1097 b'required': True,
1095 b'type': b'bytes'
1098 b'type': b'bytes'
1096 }
1099 }
1097 },
1100 },
1098 b'permissions': [
1101 b'permissions': [
1099 b'pull'
1102 b'pull'
1100 ]
1103 ]
1101 },
1104 },
1102 b'manifestdata': {
1105 b'manifestdata': {
1103 b'args': {
1106 b'args': {
1104 b'fields': {
1107 b'fields': {
1105 b'default': set([]),
1108 b'default': set([]),
1106 b'required': False,
1109 b'required': False,
1107 b'type': b'set',
1110 b'type': b'set',
1108 b'validvalues': set([
1111 b'validvalues': set([
1109 b'parents',
1112 b'parents',
1110 b'revision'
1113 b'revision'
1111 ])
1114 ])
1112 },
1115 },
1113 b'haveparents': {
1116 b'haveparents': {
1114 b'default': False,
1117 b'default': False,
1115 b'required': False,
1118 b'required': False,
1116 b'type': b'bool'
1119 b'type': b'bool'
1117 },
1120 },
1118 b'nodes': {
1121 b'nodes': {
1119 b'required': True,
1122 b'required': True,
1120 b'type': b'list'
1123 b'type': b'list'
1121 },
1124 },
1122 b'tree': {
1125 b'tree': {
1123 b'required': True,
1126 b'required': True,
1124 b'type': b'bytes'
1127 b'type': b'bytes'
1125 }
1128 }
1126 },
1129 },
1127 b'permissions': [
1130 b'permissions': [
1128 b'pull'
1131 b'pull'
1129 ]
1132 ],
1133 b'recommendedbatchsize': 100000
1130 },
1134 },
1131 b'pushkey': {
1135 b'pushkey': {
1132 b'args': {
1136 b'args': {
1133 b'key': {
1137 b'key': {
1134 b'required': True,
1138 b'required': True,
1135 b'type': b'bytes'
1139 b'type': b'bytes'
1136 },
1140 },
1137 b'namespace': {
1141 b'namespace': {
1138 b'required': True,
1142 b'required': True,
1139 b'type': b'bytes'
1143 b'type': b'bytes'
1140 },
1144 },
1141 b'new': {
1145 b'new': {
1142 b'required': True,
1146 b'required': True,
1143 b'type': b'bytes'
1147 b'type': b'bytes'
1144 },
1148 },
1145 b'old': {
1149 b'old': {
1146 b'required': True,
1150 b'required': True,
1147 b'type': b'bytes'
1151 b'type': b'bytes'
1148 }
1152 }
1149 },
1153 },
1150 b'permissions': [
1154 b'permissions': [
1151 b'push'
1155 b'push'
1152 ]
1156 ]
1153 }
1157 }
1154 },
1158 },
1155 b'framingmediatypes': [
1159 b'framingmediatypes': [
1156 b'application/mercurial-exp-framing-0006'
1160 b'application/mercurial-exp-framing-0006'
1157 ],
1161 ],
1158 b'pathfilterprefixes': set([
1162 b'pathfilterprefixes': set([
1159 b'path:',
1163 b'path:',
1160 b'rootfilesin:'
1164 b'rootfilesin:'
1161 ]),
1165 ]),
1162 b'rawrepoformats': [
1166 b'rawrepoformats': [
1163 b'generaldelta',
1167 b'generaldelta',
1164 b'revlogv1'
1168 b'revlogv1'
1165 ],
1169 ],
1166 b'redirect': {
1170 b'redirect': {
1167 b'hashes': [
1171 b'hashes': [
1168 b'sha256',
1172 b'sha256',
1169 b'sha1'
1173 b'sha1'
1170 ],
1174 ],
1171 b'targets': [
1175 b'targets': [
1172 {
1176 {
1173 b'name': b'target-bad-tls',
1177 b'name': b'target-bad-tls',
1174 b'protocol': b'https',
1178 b'protocol': b'https',
1175 b'tlsversions': [
1179 b'tlsversions': [
1176 b'42',
1180 b'42',
1177 b'39'
1181 b'39'
1178 ],
1182 ],
1179 b'uris': [
1183 b'uris': [
1180 b'https://example.com/'
1184 b'https://example.com/'
1181 ]
1185 ]
1182 }
1186 }
1183 ]
1187 ]
1184 }
1188 }
1185 }
1189 }
1186 ]
1190 ]
1187 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1191 (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
1188
1192
1189 Set up the server to issue content redirects to its built-in API server.
1193 Set up the server to issue content redirects to its built-in API server.
1190
1194
1191 $ cat > redirects.py << EOF
1195 $ cat > redirects.py << EOF
1192 > [
1196 > [
1193 > {
1197 > {
1194 > b'name': b'local',
1198 > b'name': b'local',
1195 > b'protocol': b'http',
1199 > b'protocol': b'http',
1196 > b'uris': [b'http://example.com/'],
1200 > b'uris': [b'http://example.com/'],
1197 > },
1201 > },
1198 > ]
1202 > ]
1199 > EOF
1203 > EOF
1200
1204
1201 Request to eventual cache URL should return 404 (validating the cache server works)
1205 Request to eventual cache URL should return 404 (validating the cache server works)
1202
1206
1203 $ sendhttpraw << EOF
1207 $ sendhttpraw << EOF
1204 > httprequest GET api/simplecache/missingkey
1208 > httprequest GET api/simplecache/missingkey
1205 > user-agent: test
1209 > user-agent: test
1206 > EOF
1210 > EOF
1207 using raw connection to peer
1211 using raw connection to peer
1208 s> GET /api/simplecache/missingkey HTTP/1.1\r\n
1212 s> GET /api/simplecache/missingkey HTTP/1.1\r\n
1209 s> Accept-Encoding: identity\r\n
1213 s> Accept-Encoding: identity\r\n
1210 s> user-agent: test\r\n
1214 s> user-agent: test\r\n
1211 s> host: $LOCALIP:$HGPORT\r\n (glob)
1215 s> host: $LOCALIP:$HGPORT\r\n (glob)
1212 s> \r\n
1216 s> \r\n
1213 s> makefile('rb', None)
1217 s> makefile('rb', None)
1214 s> HTTP/1.1 404 Not Found\r\n
1218 s> HTTP/1.1 404 Not Found\r\n
1215 s> Server: testing stub value\r\n
1219 s> Server: testing stub value\r\n
1216 s> Date: $HTTP_DATE$\r\n
1220 s> Date: $HTTP_DATE$\r\n
1217 s> Content-Type: text/plain\r\n
1221 s> Content-Type: text/plain\r\n
1218 s> Content-Length: 22\r\n
1222 s> Content-Length: 22\r\n
1219 s> \r\n
1223 s> \r\n
1220 s> key not found in cache
1224 s> key not found in cache
1221
1225
1222 Send a cacheable request
1226 Send a cacheable request
1223
1227
1224 $ sendhttpv2peer << EOF
1228 $ sendhttpv2peer << EOF
1225 > command manifestdata
1229 > command manifestdata
1226 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1230 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1227 > tree eval:b''
1231 > tree eval:b''
1228 > fields eval:[b'parents']
1232 > fields eval:[b'parents']
1229 > EOF
1233 > EOF
1230 creating http peer for wire protocol version 2
1234 creating http peer for wire protocol version 2
1231 sending manifestdata command
1235 sending manifestdata command
1232 response: gen[
1236 response: gen[
1233 {
1237 {
1234 b'totalitems': 1
1238 b'totalitems': 1
1235 },
1239 },
1236 {
1240 {
1237 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1241 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1238 b'parents': [
1242 b'parents': [
1239 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1243 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1240 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1244 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1241 ]
1245 ]
1242 }
1246 }
1243 ]
1247 ]
1244
1248
1245 Cached entry should be available on server
1249 Cached entry should be available on server
1246
1250
1247 $ sendhttpraw << EOF
1251 $ sendhttpraw << EOF
1248 > httprequest GET api/simplecache/64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca
1252 > httprequest GET api/simplecache/64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca
1249 > user-agent: test
1253 > user-agent: test
1250 > EOF
1254 > EOF
1251 using raw connection to peer
1255 using raw connection to peer
1252 s> GET /api/simplecache/64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca HTTP/1.1\r\n
1256 s> GET /api/simplecache/64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca HTTP/1.1\r\n
1253 s> Accept-Encoding: identity\r\n
1257 s> Accept-Encoding: identity\r\n
1254 s> user-agent: test\r\n
1258 s> user-agent: test\r\n
1255 s> host: $LOCALIP:$HGPORT\r\n (glob)
1259 s> host: $LOCALIP:$HGPORT\r\n (glob)
1256 s> \r\n
1260 s> \r\n
1257 s> makefile('rb', None)
1261 s> makefile('rb', None)
1258 s> HTTP/1.1 200 OK\r\n
1262 s> HTTP/1.1 200 OK\r\n
1259 s> Server: testing stub value\r\n
1263 s> Server: testing stub value\r\n
1260 s> Date: $HTTP_DATE$\r\n
1264 s> Date: $HTTP_DATE$\r\n
1261 s> Content-Type: application/mercurial-cbor\r\n
1265 s> Content-Type: application/mercurial-cbor\r\n
1262 s> Content-Length: 91\r\n
1266 s> Content-Length: 91\r\n
1263 s> \r\n
1267 s> \r\n
1264 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
1268 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
1265 cbor> [
1269 cbor> [
1266 {
1270 {
1267 b'totalitems': 1
1271 b'totalitems': 1
1268 },
1272 },
1269 {
1273 {
1270 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1274 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1271 b'parents': [
1275 b'parents': [
1272 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1276 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'
1277 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1274 ]
1278 ]
1275 }
1279 }
1276 ]
1280 ]
1277
1281
1278 2nd request should result in content redirect response
1282 2nd request should result in content redirect response
1279
1283
1280 $ sendhttpv2peer << EOF
1284 $ sendhttpv2peer << EOF
1281 > command manifestdata
1285 > command manifestdata
1282 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1286 > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
1283 > tree eval:b''
1287 > tree eval:b''
1284 > fields eval:[b'parents']
1288 > fields eval:[b'parents']
1285 > EOF
1289 > EOF
1286 creating http peer for wire protocol version 2
1290 creating http peer for wire protocol version 2
1287 sending manifestdata command
1291 sending manifestdata command
1288 response: gen[
1292 response: gen[
1289 {
1293 {
1290 b'totalitems': 1
1294 b'totalitems': 1
1291 },
1295 },
1292 {
1296 {
1293 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1297 b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
1294 b'parents': [
1298 b'parents': [
1295 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1299 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
1296 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1300 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1297 ]
1301 ]
1298 }
1302 }
1299 ]
1303 ]
1300
1304
1301 $ cat error.log
1305 $ cat error.log
1302 $ killdaemons.py
1306 $ killdaemons.py
1303
1307
1304 $ cat .hg/blackbox.log
1308 $ cat .hg/blackbox.log
1305 *> cacher constructed for manifestdata (glob)
1309 *> cacher constructed for manifestdata (glob)
1306 *> cache miss for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
1310 *> cache miss for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
1307 *> storing cache entry for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
1311 *> storing cache entry for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
1308 *> cacher constructed for manifestdata (glob)
1312 *> cacher constructed for manifestdata (glob)
1309 *> cache hit for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
1313 *> cache hit for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
1310 *> sending content redirect for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca to http://*:$HGPORT/api/simplecache/64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
1314 *> sending content redirect for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca to http://*:$HGPORT/api/simplecache/64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
General Comments 0
You need to be logged in to leave comments. Login now