annotate mercurial/wireprotov2server.py @ 37724:deff7cf7eefd

wireprotov2: change frame type and name for command response There was hole at frame type value 3. And the frame is better named as a command response. Differential Revision: https://phab.mercurial-scm.org/D3384
author Gregory Szorc <gregory.szorc@gmail.com>
date Sat, 14 Apr 2018 14:37:23 -0700
parents 89a16704114c
children 3ea8323d6f95
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
1 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
2 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
3 #
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8109
diff changeset
4 # This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9713
diff changeset
5 # GNU General Public License version 2 or any later version.
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
6
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
7 from __future__ import absolute_import
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
8
36104
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
9 import contextlib
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
10
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
11 from .i18n import _
37485
0b7475ea38cf wireproto: port heads command to wire protocol v2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37414
diff changeset
12 from .thirdparty import (
0b7475ea38cf wireproto: port heads command to wire protocol v2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37414
diff changeset
13 cbor,
0b7475ea38cf wireproto: port heads command to wire protocol v2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37414
diff changeset
14 )
37296
78103e4138b1 wireproto: port protocol handler to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37295
diff changeset
15 from .thirdparty.zope import (
78103e4138b1 wireproto: port protocol handler to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37295
diff changeset
16 interface as zi,
78103e4138b1 wireproto: port protocol handler to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37295
diff changeset
17 )
35896
ef3a24a023ec wireprotoserver: rename hgweb.protocol to wireprotoserver (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35750
diff changeset
18 from . import (
37546
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
19 encoding,
34509
e21f274cccea hgweb: in protocol adapter, avoid control reaching end of non-void function
Augie Fackler <augie@google.com>
parents: 33842
diff changeset
20 error,
34742
5a9cad0dfddb hgweb: when unpacking args from request form, convert to bytes
Augie Fackler <augie@google.com>
parents: 34740
diff changeset
21 pycompat,
37657
23c4ddda7bbe wireproto: expose repository formats via capabilities
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37653
diff changeset
22 streamclone,
37546
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
23 util,
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
24 wireproto,
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
25 wireprotoframing,
36111
cd6ab329c5c7 wireprototypes: move wire protocol response types to new module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36110
diff changeset
26 wireprototypes,
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
27 )
35896
ef3a24a023ec wireprotoserver: rename hgweb.protocol to wireprotoserver (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35750
diff changeset
28
37722
89a16704114c wireprotov2: define response data as CBOR
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37657
diff changeset
29 FRAMINGTYPE = b'application/mercurial-exp-framing-0004'
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
30
37644
77c9ee77687c wireproto: rename HTTPV2 so it less like HTTP/2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37557
diff changeset
31 HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
36015
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35940
diff changeset
32
37545
93397c4633f6 wireproto: extract HTTP version 2 code to own module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37535
diff changeset
33 def handlehttpv2request(rctx, req, res, checkperm, urlparts):
37050
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
34 from .hgweb import common as hgwebcommon
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
35
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
36 # URL space looks like: <permissions>/<command>, where <permission> can
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
37 # be ``ro`` or ``rw`` to signal read-only or read-write, respectively.
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
38
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
39 # Root URL does nothing meaningful... yet.
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
40 if not urlparts:
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
41 res.status = b'200 OK'
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
42 res.headers[b'Content-Type'] = b'text/plain'
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
43 res.setbodybytes(_('HTTP version 2 API handler'))
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
44 return
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
45
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
46 if len(urlparts) == 1:
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
47 res.status = b'404 Not Found'
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
48 res.headers[b'Content-Type'] = b'text/plain'
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
49 res.setbodybytes(_('do not know how to process %s\n') %
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
50 req.dispatchpath)
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
51 return
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
52
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
53 permission, command = urlparts[0:2]
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
54
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
55 if permission not in (b'ro', b'rw'):
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
56 res.status = b'404 Not Found'
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
57 res.headers[b'Content-Type'] = b'text/plain'
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
58 res.setbodybytes(_('unknown permission: %s') % permission)
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
59 return
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
60
37051
fc5e261915b9 wireproto: require POST for all HTTPv2 requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37050
diff changeset
61 if req.method != 'POST':
fc5e261915b9 wireproto: require POST for all HTTPv2 requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37050
diff changeset
62 res.status = b'405 Method Not Allowed'
fc5e261915b9 wireproto: require POST for all HTTPv2 requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37050
diff changeset
63 res.headers[b'Allow'] = b'POST'
fc5e261915b9 wireproto: require POST for all HTTPv2 requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37050
diff changeset
64 res.setbodybytes(_('commands require POST requests'))
fc5e261915b9 wireproto: require POST for all HTTPv2 requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37050
diff changeset
65 return
fc5e261915b9 wireproto: require POST for all HTTPv2 requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37050
diff changeset
66
37050
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
67 # At some point we'll want to use our own API instead of recycling the
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
68 # behavior of version 1 of the wire protocol...
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
69 # TODO return reasonable responses - not responses that overload the
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
70 # HTTP status line message for error reporting.
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
71 try:
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
72 checkperm(rctx, req, 'pull' if permission == b'ro' else 'push')
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
73 except hgwebcommon.ErrorResponse as e:
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
74 res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e))
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
75 for k, v in e.headers:
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
76 res.headers[k] = v
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
77 res.setbodybytes('permission denied')
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
78 return
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
79
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
80 # We have a special endpoint to reflect the request back at the client.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
81 if command == b'debugreflect':
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
82 _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
83 return
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
84
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
85 # Extra commands that we handle that aren't really wire protocol
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
86 # commands. Think extra hard before making this hackery available to
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
87 # extension.
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
88 extracommands = {'multirequest'}
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
89
37295
45b39c69fae0 wireproto: separate commands tables for version 1 and 2 commands
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
90 if command not in wireproto.commandsv2 and command not in extracommands:
37050
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
91 res.status = b'404 Not Found'
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
92 res.headers[b'Content-Type'] = b'text/plain'
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
93 res.setbodybytes(_('unknown wire protocol command: %s\n') % command)
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
94 return
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
95
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
96 repo = rctx.repo
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
97 ui = repo.ui
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
98
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
99 proto = httpv2protocolhandler(req, ui)
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
100
37295
45b39c69fae0 wireproto: separate commands tables for version 1 and 2 commands
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
101 if (not wireproto.commandsv2.commandavailable(command, proto)
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
102 and command not in extracommands):
37050
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
103 res.status = b'404 Not Found'
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
104 res.headers[b'Content-Type'] = b'text/plain'
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
105 res.setbodybytes(_('invalid wire protocol command: %s') % command)
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
106 return
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
107
37132
aaabd709df72 wireproto: review fixups
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37123
diff changeset
108 # TODO consider cases where proxies may add additional Accept headers.
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37053
diff changeset
109 if req.headers.get(b'Accept') != FRAMINGTYPE:
37053
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
110 res.status = b'406 Not Acceptable'
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
111 res.headers[b'Content-Type'] = b'text/plain'
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
112 res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37053
diff changeset
113 % FRAMINGTYPE)
37053
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
114 return
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
115
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
116 if req.headers.get(b'Content-Type') != FRAMINGTYPE:
37053
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
117 res.status = b'415 Unsupported Media Type'
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
118 # TODO we should send a response with appropriate media type,
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
119 # since client does Accept it.
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
120 res.headers[b'Content-Type'] = b'text/plain'
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
121 res.setbodybytes(_('client MUST send Content-Type header with '
37054
40206e227412 wireproto: define and implement protocol for issuing requests
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37053
diff changeset
122 'value: %s\n') % FRAMINGTYPE)
37053
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
123 return
37d7a1d18b97 wireproto: define content negotiation for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37051
diff changeset
124
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
125 _processhttpv2request(ui, repo, req, res, permission, command, proto)
37049
1cfef5693203 wireproto: support /api/* URL space for exposing APIs
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36883
diff changeset
126
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
127 def _processhttpv2reflectrequest(ui, repo, req, res):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
128 """Reads unified frame protocol request and dumps out state to client.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
129
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
130 This special endpoint can be used to help debug the wire protocol.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
131
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
132 Instead of routing the request through the normal dispatch mechanism,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
133 we instead read all frames, decode them, and feed them into our state
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
134 tracker. We then dump the log of all that activity back out to the
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
135 client.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
136 """
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
137 import json
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
138
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
139 # Reflection APIs have a history of being abused, accidentally disclosing
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
140 # sensitive data, etc. So we have a config knob.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
141 if not ui.configbool('experimental', 'web.api.debugreflect'):
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
142 res.status = b'404 Not Found'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
143 res.headers[b'Content-Type'] = b'text/plain'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
144 res.setbodybytes(_('debugreflect service not available'))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
145 return
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
146
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
147 # We assume we have a unified framing protocol request body.
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
148
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
149 reactor = wireprotoframing.serverreactor()
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
150 states = []
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
151
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
152 while True:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
153 frame = wireprotoframing.readframe(req.bodyfh)
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
154
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
155 if not frame:
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
156 states.append(b'received: <no frame>')
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
157 break
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
158
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37062
diff changeset
159 states.append(b'received: %d %d %d %s' % (frame.typeid, frame.flags,
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37062
diff changeset
160 frame.requestid,
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37062
diff changeset
161 frame.payload))
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
162
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37062
diff changeset
163 action, meta = reactor.onframerecv(frame)
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
164 states.append(json.dumps((action, meta), sort_keys=True,
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
165 separators=(', ', ': ')))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
166
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
167 action, meta = reactor.oninputeof()
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
168 meta['action'] = action
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
169 states.append(json.dumps(meta, sort_keys=True, separators=(', ',': ')))
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
170
37055
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
171 res.status = b'200 OK'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
172 res.headers[b'Content-Type'] = b'text/plain'
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
173 res.setbodybytes(b'\n'.join(states))
8c3c47362934 wireproto: implement basic frame reading and processing
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37054
diff changeset
174
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
175 def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
176 """Post-validation handler for HTTPv2 requests.
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
177
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
178 Called when the HTTP request contains unified frame-based protocol
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
179 frames for evaluation.
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
180 """
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
181 # TODO Some HTTP clients are full duplex and can receive data before
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
182 # the entire request is transmitted. Figure out a way to indicate support
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
183 # for that so we can opt into full duplex mode.
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
184 reactor = wireprotoframing.serverreactor(deferoutput=True)
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
185 seencommand = False
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
186
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
187 outstream = reactor.makeoutputstream()
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
188
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
189 while True:
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
190 frame = wireprotoframing.readframe(req.bodyfh)
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
191 if not frame:
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
192 break
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
193
37064
884a0c1604ad wireproto: define attr-based classes for representing frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37062
diff changeset
194 action, meta = reactor.onframerecv(frame)
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
195
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
196 if action == 'wantframe':
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
197 # Need more data before we can do anything.
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
198 continue
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
199 elif action == 'runcommand':
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
200 sentoutput = _httpv2runcommand(ui, repo, req, res, authedperm,
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
201 reqcommand, reactor, outstream,
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
202 meta, issubsequent=seencommand)
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
203
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
204 if sentoutput:
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
205 return
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
206
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
207 seencommand = True
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
208
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
209 elif action == 'error':
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
210 # TODO define proper error mechanism.
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
211 res.status = b'200 OK'
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
212 res.headers[b'Content-Type'] = b'text/plain'
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
213 res.setbodybytes(meta['message'] + b'\n')
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
214 return
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
215 else:
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
216 raise error.ProgrammingError(
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
217 'unhandled action from frame processor: %s' % action)
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
218
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
219 action, meta = reactor.oninputeof()
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
220 if action == 'sendframes':
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
221 # We assume we haven't started sending the response yet. If we're
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
222 # wrong, the response type will raise an exception.
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
223 res.status = b'200 OK'
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
224 res.headers[b'Content-Type'] = FRAMINGTYPE
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
225 res.setbodygen(meta['framegen'])
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
226 elif action == 'noop':
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
227 pass
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
228 else:
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
229 raise error.ProgrammingError('unhandled action from frame processor: %s'
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
230 % action)
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
231
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
232 def _httpv2runcommand(ui, repo, req, res, authedperm, reqcommand, reactor,
37289
5fadc63ac99f wireproto: explicit API to create outgoing streams
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37288
diff changeset
233 outstream, command, issubsequent):
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
234 """Dispatch a wire protocol command made from HTTPv2 requests.
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
235
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
236 The authenticated permission (``authedperm``) along with the original
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
237 command from the URL (``reqcommand``) are passed in.
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
238 """
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
239 # We already validated that the session has permissions to perform the
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
240 # actions in ``authedperm``. In the unified frame protocol, the canonical
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
241 # command to run is expressed in a frame. However, the URL also requested
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
242 # to run a specific command. We need to be careful that the command we
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
243 # run doesn't have permissions requirements greater than what was granted
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
244 # by ``authedperm``.
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
245 #
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
246 # Our rule for this is we only allow one command per HTTP request and
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
247 # that command must match the command in the URL. However, we make
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
248 # an exception for the ``multirequest`` URL. This URL is allowed to
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
249 # execute multiple commands. We double check permissions of each command
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
250 # as it is invoked to ensure there is no privilege escalation.
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
251 # TODO consider allowing multiple commands to regular command URLs
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
252 # iff each command is the same.
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
253
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
254 proto = httpv2protocolhandler(req, ui, args=command['args'])
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
255
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
256 if reqcommand == b'multirequest':
37295
45b39c69fae0 wireproto: separate commands tables for version 1 and 2 commands
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
257 if not wireproto.commandsv2.commandavailable(command['command'], proto):
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
258 # TODO proper error mechanism
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
259 res.status = b'200 OK'
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
260 res.headers[b'Content-Type'] = b'text/plain'
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
261 res.setbodybytes(_('wire protocol command not available: %s') %
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
262 command['command'])
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
263 return True
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
264
37132
aaabd709df72 wireproto: review fixups
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37123
diff changeset
265 # TODO don't use assert here, since it may be elided by -O.
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
266 assert authedperm in (b'ro', b'rw')
37295
45b39c69fae0 wireproto: separate commands tables for version 1 and 2 commands
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37292
diff changeset
267 wirecommand = wireproto.commandsv2[command['command']]
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
268 assert wirecommand.permission in ('push', 'pull')
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
269
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
270 if authedperm == b'ro' and wirecommand.permission != 'pull':
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
271 # TODO proper error mechanism
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
272 res.status = b'403 Forbidden'
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
273 res.headers[b'Content-Type'] = b'text/plain'
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
274 res.setbodybytes(_('insufficient permissions to execute '
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
275 'command: %s') % command['command'])
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
276 return True
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
277
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
278 # TODO should we also call checkperm() here? Maybe not if we're going
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
279 # to overhaul that API. The granted scope from the URL check should
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
280 # be good enough.
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
281
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
282 else:
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
283 # Don't allow multiple commands outside of ``multirequest`` URL.
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
284 if issubsequent:
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
285 # TODO proper error mechanism
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
286 res.status = b'200 OK'
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
287 res.headers[b'Content-Type'] = b'text/plain'
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
288 res.setbodybytes(_('multiple commands cannot be issued to this '
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
289 'URL'))
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
290 return True
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
291
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
292 if reqcommand != command['command']:
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
293 # TODO define proper error mechanism
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
294 res.status = b'200 OK'
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
295 res.headers[b'Content-Type'] = b'text/plain'
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
296 res.setbodybytes(_('command in frame must match command in URL'))
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
297 return True
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
298
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
299 rsp = wireproto.dispatch(repo, proto, command['command'])
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
300
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
301 res.status = b'200 OK'
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37057
diff changeset
302 res.headers[b'Content-Type'] = FRAMINGTYPE
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
303
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
304 if isinstance(rsp, wireprototypes.bytesresponse):
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
305 action, meta = reactor.oncommandresponseready(outstream,
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
306 command['requestid'],
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
307 rsp.data)
37485
0b7475ea38cf wireproto: port heads command to wire protocol v2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37414
diff changeset
308 elif isinstance(rsp, wireprototypes.cborresponse):
0b7475ea38cf wireproto: port heads command to wire protocol v2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37414
diff changeset
309 encoded = cbor.dumps(rsp.value, canonical=True)
37724
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
310 action, meta = reactor.oncommandresponseready(outstream,
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
311 command['requestid'],
deff7cf7eefd wireprotov2: change frame type and name for command response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37722
diff changeset
312 encoded)
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
313 else:
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37057
diff changeset
314 action, meta = reactor.onapplicationerror(
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37057
diff changeset
315 _('unhandled response type from wire proto command'))
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37057
diff changeset
316
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37057
diff changeset
317 if action == 'sendframes':
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37057
diff changeset
318 res.setbodygen(meta['framegen'])
37062
bbea991635d0 wireproto: service multiple command requests per HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37060
diff changeset
319 return True
37059
861e9d37e56e wireproto: buffer output frames when in half duplex mode
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37058
diff changeset
320 elif action == 'noop':
37132
aaabd709df72 wireproto: review fixups
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37123
diff changeset
321 return False
37058
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37057
diff changeset
322 else:
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37057
diff changeset
323 raise error.ProgrammingError('unhandled event from reactor: %s' %
61393f888dfe wireproto: define and implement responses in framing protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37057
diff changeset
324 action)
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
325
37296
78103e4138b1 wireproto: port protocol handler to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37295
diff changeset
326 @zi.implementer(wireprototypes.baseprotocolhandler)
78103e4138b1 wireproto: port protocol handler to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37295
diff changeset
327 class httpv2protocolhandler(object):
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
328 def __init__(self, req, ui, args=None):
37050
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
329 self._req = req
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
330 self._ui = ui
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
331 self._args = args
37050
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
332
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
333 @property
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
334 def name(self):
37644
77c9ee77687c wireproto: rename HTTPV2 so it less like HTTP/2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37557
diff changeset
335 return HTTP_WIREPROTO_V2
37050
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
336
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
337 def getargs(self, args):
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
338 data = {}
37535
69e46c1834ac wireproto: define and expose types of wire command arguments
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37533
diff changeset
339 for k, typ in args.items():
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
340 if k == '*':
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
341 raise NotImplementedError('do not support * args')
37485
0b7475ea38cf wireproto: port heads command to wire protocol v2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37414
diff changeset
342 elif k in self._args:
37535
69e46c1834ac wireproto: define and expose types of wire command arguments
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37533
diff changeset
343 # TODO consider validating value types.
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
344 data[k] = self._args[k]
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
345
37485
0b7475ea38cf wireproto: port heads command to wire protocol v2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37414
diff changeset
346 return data
37050
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
347
37393
afcfdf53e4b5 wireproto: provide accessors for client capabilities
Joerg Sonnenberger <joerg@bec.de>
parents: 37296
diff changeset
348 def getprotocaps(self):
afcfdf53e4b5 wireproto: provide accessors for client capabilities
Joerg Sonnenberger <joerg@bec.de>
parents: 37296
diff changeset
349 # Protocol capabilities are currently not implemented for HTTP V2.
afcfdf53e4b5 wireproto: provide accessors for client capabilities
Joerg Sonnenberger <joerg@bec.de>
parents: 37296
diff changeset
350 return set()
afcfdf53e4b5 wireproto: provide accessors for client capabilities
Joerg Sonnenberger <joerg@bec.de>
parents: 37296
diff changeset
351
37414
2d965bfeb8f6 wireproto: allow direct stream processing for unbundle
Joerg Sonnenberger <joerg@bec.de>
parents: 37393
diff changeset
352 def getpayload(self):
37050
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
353 raise NotImplementedError
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
354
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
355 @contextlib.contextmanager
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
356 def mayberedirectstdio(self):
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
357 raise NotImplementedError
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
358
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
359 def client(self):
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
360 raise NotImplementedError
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
361
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
362 def addcapabilities(self, repo, caps):
37057
e7a012b60d6e wireproto: implement basic command dispatching for HTTPv2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37056
diff changeset
363 return caps
37050
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
364
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
365 def checkperm(self, perm):
fddcb51b5084 wireproto: define permissions-based routing of HTTPv2 wire protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37049
diff changeset
366 raise NotImplementedError
37546
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
367
37557
734515aca84d wireproto: define and implement HTTP handshake to upgrade protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
368 def httpv2apidescriptor(req, repo):
734515aca84d wireproto: define and implement HTTP handshake to upgrade protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
369 proto = httpv2protocolhandler(req, repo.ui)
734515aca84d wireproto: define and implement HTTP handshake to upgrade protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
370
734515aca84d wireproto: define and implement HTTP handshake to upgrade protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
371 return _capabilitiesv2(repo, proto)
734515aca84d wireproto: define and implement HTTP handshake to upgrade protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
372
37546
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
373 def _capabilitiesv2(repo, proto):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
374 """Obtain the set of capabilities for version 2 transports.
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
375
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
376 These capabilities are distinct from the capabilities for version 1
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
377 transports.
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
378 """
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
379 compression = []
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
380 for engine in wireproto.supportedcompengines(repo.ui, util.SERVERROLE):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
381 compression.append({
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
382 b'name': engine.wireprotosupport().name,
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
383 })
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
384
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
385 caps = {
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
386 'commands': {},
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
387 'compression': compression,
37653
b2fa1591fb44 wireproto: add media type to version 2 capabilities response
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
388 'framingmediatypes': [FRAMINGTYPE],
37546
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
389 }
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
390
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
391 for command, entry in wireproto.commandsv2.items():
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
392 caps['commands'][command] = {
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
393 'args': entry.args,
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
394 'permissions': [entry.permission],
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
395 }
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
396
37657
23c4ddda7bbe wireproto: expose repository formats via capabilities
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37653
diff changeset
397 if streamclone.allowservergeneration(repo):
23c4ddda7bbe wireproto: expose repository formats via capabilities
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37653
diff changeset
398 caps['rawrepoformats'] = sorted(repo.requirements &
23c4ddda7bbe wireproto: expose repository formats via capabilities
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37653
diff changeset
399 repo.supportedformats)
23c4ddda7bbe wireproto: expose repository formats via capabilities
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37653
diff changeset
400
37546
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
401 return proto.addcapabilities(repo, caps)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
402
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
403 def wireprotocommand(*args, **kwargs):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
404 def register(func):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
405 return wireproto.wireprotocommand(
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
406 *args, transportpolicy=wireproto.POLICY_V2_ONLY, **kwargs)(func)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
407
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
408 return register
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
409
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
410 @wireprotocommand('branchmap', permission='pull')
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
411 def branchmapv2(repo, proto):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
412 branchmap = {encoding.fromlocal(k): v
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
413 for k, v in repo.branchmap().iteritems()}
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
414
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
415 return wireprototypes.cborresponse(branchmap)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
416
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
417 @wireprotocommand('capabilities', permission='pull')
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
418 def capabilitiesv2(repo, proto):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
419 caps = _capabilitiesv2(repo, proto)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
420
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
421 return wireprototypes.cborresponse(caps)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
422
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
423 @wireprotocommand('heads',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
424 args={
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
425 'publiconly': False,
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
426 },
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
427 permission='pull')
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
428 def headsv2(repo, proto, publiconly=False):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
429 if publiconly:
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
430 repo = repo.filtered('immutable')
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
431
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
432 return wireprototypes.cborresponse(repo.heads())
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
433
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
434 @wireprotocommand('known',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
435 args={
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
436 'nodes': [b'deadbeef'],
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
437 },
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
438 permission='pull')
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
439 def knownv2(repo, proto, nodes=None):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
440 nodes = nodes or []
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
441 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
442 return wireprototypes.cborresponse(result)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
443
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
444 @wireprotocommand('listkeys',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
445 args={
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
446 'namespace': b'ns',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
447 },
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
448 permission='pull')
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
449 def listkeysv2(repo, proto, namespace=None):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
450 keys = repo.listkeys(encoding.tolocal(namespace))
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
451 keys = {encoding.fromlocal(k): encoding.fromlocal(v)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
452 for k, v in keys.iteritems()}
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
453
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
454 return wireprototypes.cborresponse(keys)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
455
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
456 @wireprotocommand('lookup',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
457 args={
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
458 'key': b'foo',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
459 },
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
460 permission='pull')
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
461 def lookupv2(repo, proto, key):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
462 key = encoding.tolocal(key)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
463
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
464 # TODO handle exception.
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
465 node = repo.lookup(key)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
466
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
467 return wireprototypes.cborresponse(node)
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
468
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
469 @wireprotocommand('pushkey',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
470 args={
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
471 'namespace': b'ns',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
472 'key': b'key',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
473 'old': b'old',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
474 'new': b'new',
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
475 },
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
476 permission='push')
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
477 def pushkeyv2(repo, proto, namespace, key, old, new):
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
478 # TODO handle ui output redirection
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
479 r = repo.pushkey(encoding.tolocal(namespace),
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
480 encoding.tolocal(key),
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
481 encoding.tolocal(old),
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
482 encoding.tolocal(new))
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
483
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
484 return wireprototypes.cborresponse(r)