comparison mercurial/debugcommands.py @ 37483:61e405fb6372

wireproto: crude support for version 2 HTTP peer As part of implementing the server-side bits of the wire protocol command handlers for version 2, we want a way to easily test those commands. Currently, we use the "httprequest" action of `hg debugwireproto`. But this requires explicitly specifying the HTTP request headers, low-level frame details, and the data structure to encode with CBOR. That's a lot of boilerplate and a lot of it can change as the wire protocol evolves. `hg debugwireproto` has a mechanism to issue commands via the peer interface. That is *much* easier to use and we prefer to test with that going forward. This commit implements enough parts of the peer API to send basic requests via the HTTP version 2 transport. The peer code is super hacky. Again, the goal is to facilitate server testing, not robustly implement a client. The client code will receive love at a later time. Differential Revision: https://phab.mercurial-scm.org/D3177
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 28 Mar 2018 15:09:34 -0700
parents 9966f44ecab4
children 835ccc2a5ef1
comparison
equal deleted inserted replaced
37482:fa9faf58959d 37483:61e405fb6372
2629 and connect to that. By default, the connection will perform a handshake 2629 and connect to that. By default, the connection will perform a handshake
2630 and establish an appropriate peer instance. 2630 and establish an appropriate peer instance.
2631 2631
2632 ``--peer`` can be used to bypass the handshake protocol and construct a 2632 ``--peer`` can be used to bypass the handshake protocol and construct a
2633 peer instance using the specified class type. Valid values are ``raw``, 2633 peer instance using the specified class type. Valid values are ``raw``,
2634 ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending raw data 2634 ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending
2635 payloads and don't support higher-level command actions. 2635 raw data payloads and don't support higher-level command actions.
2636 2636
2637 ``--noreadstderr`` can be used to disable automatic reading from stderr 2637 ``--noreadstderr`` can be used to disable automatic reading from stderr
2638 of the peer (for SSH connections only). Disabling automatic reading of 2638 of the peer (for SSH connections only). Disabling automatic reading of
2639 stderr is useful for making output more deterministic. 2639 stderr is useful for making output more deterministic.
2640 2640
2676 each line is ``<key> <value>``. e.g.:: 2676 each line is ``<key> <value>``. e.g.::
2677 2677
2678 command listkeys 2678 command listkeys
2679 namespace bookmarks 2679 namespace bookmarks
2680 2680
2681 Values are interpreted as Python b'' literals. This allows encoding 2681 If the value begins with ``eval:``, it will be interpreted as a Python
2682 special byte sequences via backslash escaping. 2682 literal expression. Otherwise values are interpreted as Python b'' literals.
2683 This allows sending complex types and encoding special byte sequences via
2684 backslash escaping.
2683 2685
2684 The following arguments have special meaning: 2686 The following arguments have special meaning:
2685 2687
2686 ``PUSHFILE`` 2688 ``PUSHFILE``
2687 When defined, the *push* mechanism of the peer will be used instead 2689 When defined, the *push* mechanism of the peer will be used instead
2801 opts = pycompat.byteskwargs(opts) 2803 opts = pycompat.byteskwargs(opts)
2802 2804
2803 if opts['localssh'] and not repo: 2805 if opts['localssh'] and not repo:
2804 raise error.Abort(_('--localssh requires a repository')) 2806 raise error.Abort(_('--localssh requires a repository'))
2805 2807
2806 if opts['peer'] and opts['peer'] not in ('raw', 'ssh1', 'ssh2'): 2808 if opts['peer'] and opts['peer'] not in ('raw', 'http2', 'ssh1', 'ssh2'):
2807 raise error.Abort(_('invalid value for --peer'), 2809 raise error.Abort(_('invalid value for --peer'),
2808 hint=_('valid values are "raw", "ssh1", and "ssh2"')) 2810 hint=_('valid values are "raw", "ssh1", and "ssh2"'))
2809 2811
2810 if path and opts['localssh']: 2812 if path and opts['localssh']:
2811 raise error.Abort(_('cannot specify --localssh with an explicit ' 2813 raise error.Abort(_('cannot specify --localssh with an explicit '
2875 u = util.url(path) 2877 u = util.url(path)
2876 if u.scheme != 'http': 2878 if u.scheme != 'http':
2877 raise error.Abort(_('only http:// paths are currently supported')) 2879 raise error.Abort(_('only http:// paths are currently supported'))
2878 2880
2879 url, authinfo = u.authinfo() 2881 url, authinfo = u.authinfo()
2880 openerargs = {} 2882 openerargs = {
2883 r'useragent': b'Mercurial debugwireproto',
2884 }
2881 2885
2882 # Turn pipes/sockets into observers so we can log I/O. 2886 # Turn pipes/sockets into observers so we can log I/O.
2883 if ui.verbose: 2887 if ui.verbose:
2884 openerargs = { 2888 openerargs.update({
2885 r'loggingfh': ui, 2889 r'loggingfh': ui,
2886 r'loggingname': b's', 2890 r'loggingname': b's',
2887 r'loggingopts': { 2891 r'loggingopts': {
2888 r'logdata': True, 2892 r'logdata': True,
2889 r'logdataapis': False, 2893 r'logdataapis': False,
2890 }, 2894 },
2891 } 2895 })
2892 2896
2893 if ui.debugflag: 2897 if ui.debugflag:
2894 openerargs[r'loggingopts'][r'logdataapis'] = True 2898 openerargs[r'loggingopts'][r'logdataapis'] = True
2895 2899
2896 # Don't send default headers when in raw mode. This allows us to 2900 # Don't send default headers when in raw mode. This allows us to
2899 if opts['peer'] == 'raw': 2903 if opts['peer'] == 'raw':
2900 openerargs[r'sendaccept'] = False 2904 openerargs[r'sendaccept'] = False
2901 2905
2902 opener = urlmod.opener(ui, authinfo, **openerargs) 2906 opener = urlmod.opener(ui, authinfo, **openerargs)
2903 2907
2904 if opts['peer'] == 'raw': 2908 if opts['peer'] == 'http2':
2909 ui.write(_('creating http peer for wire protocol version 2\n'))
2910 peer = httppeer.httpv2peer(ui, path, opener)
2911 elif opts['peer'] == 'raw':
2905 ui.write(_('using raw connection to peer\n')) 2912 ui.write(_('using raw connection to peer\n'))
2906 peer = None 2913 peer = None
2907 elif opts['peer']: 2914 elif opts['peer']:
2908 raise error.Abort(_('--peer %s not supported with HTTP peers') % 2915 raise error.Abort(_('--peer %s not supported with HTTP peers') %
2909 opts['peer']) 2916 opts['peer'])
2949 key = fields[0] 2956 key = fields[0]
2950 value = '' 2957 value = ''
2951 else: 2958 else:
2952 key, value = fields 2959 key, value = fields
2953 2960
2954 args[key] = stringutil.unescapestr(value) 2961 if value.startswith('eval:'):
2962 value = stringutil.evalpythonliteral(value[5:])
2963 else:
2964 value = stringutil.unescapestr(value)
2965
2966 args[key] = value
2955 2967
2956 if batchedcommands is not None: 2968 if batchedcommands is not None:
2957 batchedcommands.append((command, args)) 2969 batchedcommands.append((command, args))
2958 continue 2970 continue
2959 2971