Show More
@@ -33,6 +33,9 b' from .node import (' | |||||
33 | nullrev, |
|
33 | nullrev, | |
34 | short, |
|
34 | short, | |
35 | ) |
|
35 | ) | |
|
36 | from .thirdparty import ( | |||
|
37 | cbor, | |||
|
38 | ) | |||
36 | from . import ( |
|
39 | from . import ( | |
37 | bundle2, |
|
40 | bundle2, | |
38 | changegroup, |
|
41 | changegroup, | |
@@ -3045,9 +3048,14 b' def debugwireproto(ui, repo, path=None, ' | |||||
3045 | req.get_method = lambda: method |
|
3048 | req.get_method = lambda: method | |
3046 |
|
3049 | |||
3047 | try: |
|
3050 | try: | |
3048 |
opener.open(req) |
|
3051 | res = opener.open(req) | |
|
3052 | body = res.read() | |||
3049 | except util.urlerr.urlerror as e: |
|
3053 | except util.urlerr.urlerror as e: | |
3050 | e.read() |
|
3054 | e.read() | |
|
3055 | continue | |||
|
3056 | ||||
|
3057 | if res.headers.get('Content-Type') == 'application/mercurial-cbor': | |||
|
3058 | ui.write(_('cbor> %s\n') % stringutil.pprint(cbor.loads(body))) | |||
3051 |
|
3059 | |||
3052 | elif action == 'close': |
|
3060 | elif action == 'close': | |
3053 | peer.close() |
|
3061 | peer.close() |
@@ -42,8 +42,44 b' Handshake' | |||||
42 | The client sends a ``capabilities`` command request (``?cmd=capabilities``) |
|
42 | The client sends a ``capabilities`` command request (``?cmd=capabilities``) | |
43 | as soon as HTTP requests may be issued. |
|
43 | as soon as HTTP requests may be issued. | |
44 |
|
44 | |||
45 |
|
|
45 | By default, the server responds with a version 1 capabilities string, which | |
46 | learn about the server's abilities. |
|
46 | the client parses to learn about the server's abilities. The ``Content-Type`` | |
|
47 | for this response is ``application/mercurial-0.1`` or | |||
|
48 | ``application/mercurial-0.2`` depending on whether the client advertised | |||
|
49 | support for version ``0.2`` in its request. (Clients aren't supposed to | |||
|
50 | advertise support for ``0.2`` until the capabilities response indicates | |||
|
51 | the server's support for that media type. However, a client could | |||
|
52 | conceivably cache this metadata and issue the capabilities request in such | |||
|
53 | a way to elicit an ``application/mercurial-0.2`` response.) | |||
|
54 | ||||
|
55 | Clients wishing to switch to a newer API service may send an | |||
|
56 | ``X-HgUpgrade-<X>`` header containing a space-delimited list of API service | |||
|
57 | names the client is capable of speaking. The request MUST also include an | |||
|
58 | ``X-HgProto-<X>`` header advertising a known serialization format for the | |||
|
59 | response. ``cbor`` is currently the only defined serialization format. | |||
|
60 | ||||
|
61 | If the request contains these headers, the response ``Content-Type`` MAY | |||
|
62 | be for a different media type. e.g. ``application/mercurial-cbor`` if the | |||
|
63 | client advertises support for CBOR. | |||
|
64 | ||||
|
65 | The response MUST be deserializable to a map with the following keys: | |||
|
66 | ||||
|
67 | apibase | |||
|
68 | URL path to API services, relative to the repository root. e.g. ``api/``. | |||
|
69 | ||||
|
70 | apis | |||
|
71 | A map of API service names to API descriptors. An API descriptor contains | |||
|
72 | more details about that API. In the case of the HTTP Version 2 Transport, | |||
|
73 | it will be the normal response to a ``capabilities`` command. | |||
|
74 | ||||
|
75 | Only the services advertised by the client that are also available on | |||
|
76 | the server are advertised. | |||
|
77 | ||||
|
78 | v1capabilities | |||
|
79 | The capabilities string that would be returned by a version 1 response. | |||
|
80 | ||||
|
81 | The client can then inspect the server-advertised APIs and decide which | |||
|
82 | API to use, including continuing to use the HTTP Version 1 Transport. | |||
47 |
|
83 | |||
48 | HTTP Version 1 Transport |
|
84 | HTTP Version 1 Transport | |
49 | ------------------------ |
|
85 | ------------------------ | |
@@ -123,6 +159,9 b' The ``application/hg-error`` media type ' | |||||
123 | The content of the HTTP response body typically holds text describing the |
|
159 | The content of the HTTP response body typically holds text describing the | |
124 | error. |
|
160 | error. | |
125 |
|
161 | |||
|
162 | The ``application/mercurial-cbor`` media type indicates a CBOR payload | |||
|
163 | and should be interpreted as identical to ``application/cbor``. | |||
|
164 | ||||
126 | Behavior of media types is further described in the ``Content Negotiation`` |
|
165 | Behavior of media types is further described in the ``Content Negotiation`` | |
127 | section below. |
|
166 | section below. | |
128 |
|
167 | |||
@@ -1252,6 +1291,12 b' 0.2' | |||||
1252 | Indicates the client supports receiving ``application/mercurial-0.2`` |
|
1291 | Indicates the client supports receiving ``application/mercurial-0.2`` | |
1253 | responses. |
|
1292 | responses. | |
1254 |
|
1293 | |||
|
1294 | cbor | |||
|
1295 | Indicates the client supports receiving ``application/mercurial-cbor`` | |||
|
1296 | responses. | |||
|
1297 | ||||
|
1298 | (Only intended to be used with version 2 transports.) | |||
|
1299 | ||||
1255 | comp |
|
1300 | comp | |
1256 | Indicates compression formats the client can decode. Value is a list of |
|
1301 | Indicates compression formats the client can decode. Value is a list of | |
1257 | comma delimited strings identifying compression formats ordered from |
|
1302 | comma delimited strings identifying compression formats ordered from |
@@ -12,6 +12,9 b' import sys' | |||||
12 | import threading |
|
12 | import threading | |
13 |
|
13 | |||
14 | from .i18n import _ |
|
14 | from .i18n import _ | |
|
15 | from .thirdparty import ( | |||
|
16 | cbor, | |||
|
17 | ) | |||
15 | from .thirdparty.zope import ( |
|
18 | from .thirdparty.zope import ( | |
16 | interface as zi, |
|
19 | interface as zi, | |
17 | ) |
|
20 | ) | |
@@ -230,6 +233,18 b' def handlewsgirequest(rctx, req, res, ch' | |||||
230 |
|
233 | |||
231 | return True |
|
234 | return True | |
232 |
|
235 | |||
|
236 | def _availableapis(repo): | |||
|
237 | apis = set() | |||
|
238 | ||||
|
239 | # Registered APIs are made available via config options of the name of | |||
|
240 | # the protocol. | |||
|
241 | for k, v in API_HANDLERS.items(): | |||
|
242 | section, option = v['config'] | |||
|
243 | if repo.ui.configbool(section, option): | |||
|
244 | apis.add(k) | |||
|
245 | ||||
|
246 | return apis | |||
|
247 | ||||
233 | def handlewsgiapirequest(rctx, req, res, checkperm): |
|
248 | def handlewsgiapirequest(rctx, req, res, checkperm): | |
234 | """Handle requests to /api/*.""" |
|
249 | """Handle requests to /api/*.""" | |
235 | assert req.dispatchparts[0] == b'api' |
|
250 | assert req.dispatchparts[0] == b'api' | |
@@ -247,13 +262,7 b' def handlewsgiapirequest(rctx, req, res,' | |||||
247 | # The URL space is /api/<protocol>/*. The structure of URLs under varies |
|
262 | # The URL space is /api/<protocol>/*. The structure of URLs under varies | |
248 | # by <protocol>. |
|
263 | # by <protocol>. | |
249 |
|
264 | |||
250 | # Registered APIs are made available via config options of the name of |
|
265 | availableapis = _availableapis(repo) | |
251 | # the protocol. |
|
|||
252 | availableapis = set() |
|
|||
253 | for k, v in API_HANDLERS.items(): |
|
|||
254 | section, option = v['config'] |
|
|||
255 | if repo.ui.configbool(section, option): |
|
|||
256 | availableapis.add(k) |
|
|||
257 |
|
266 | |||
258 | # Requests to /api/ list available APIs. |
|
267 | # Requests to /api/ list available APIs. | |
259 | if req.dispatchparts == [b'api']: |
|
268 | if req.dispatchparts == [b'api']: | |
@@ -287,10 +296,21 b' def handlewsgiapirequest(rctx, req, res,' | |||||
287 | req.dispatchparts[2:]) |
|
296 | req.dispatchparts[2:]) | |
288 |
|
297 | |||
289 | # Maps API name to metadata so custom API can be registered. |
|
298 | # Maps API name to metadata so custom API can be registered. | |
|
299 | # Keys are: | |||
|
300 | # | |||
|
301 | # config | |||
|
302 | # Config option that controls whether service is enabled. | |||
|
303 | # handler | |||
|
304 | # Callable receiving (rctx, req, res, checkperm, urlparts) that is called | |||
|
305 | # when a request to this API is received. | |||
|
306 | # apidescriptor | |||
|
307 | # Callable receiving (req, repo) that is called to obtain an API | |||
|
308 | # descriptor for this service. The response must be serializable to CBOR. | |||
290 | API_HANDLERS = { |
|
309 | API_HANDLERS = { | |
291 | wireprotov2server.HTTPV2: { |
|
310 | wireprotov2server.HTTPV2: { | |
292 | 'config': ('experimental', 'web.api.http-v2'), |
|
311 | 'config': ('experimental', 'web.api.http-v2'), | |
293 | 'handler': wireprotov2server.handlehttpv2request, |
|
312 | 'handler': wireprotov2server.handlehttpv2request, | |
|
313 | 'apidescriptor': wireprotov2server.httpv2apidescriptor, | |||
294 | }, |
|
314 | }, | |
295 | } |
|
315 | } | |
296 |
|
316 | |||
@@ -327,6 +347,54 b' def _httpresponsetype(ui, proto, prefer_' | |||||
327 | opts = {'level': ui.configint('server', 'zliblevel')} |
|
347 | opts = {'level': ui.configint('server', 'zliblevel')} | |
328 | return HGTYPE, util.compengines['zlib'], opts |
|
348 | return HGTYPE, util.compengines['zlib'], opts | |
329 |
|
349 | |||
|
350 | def processcapabilitieshandshake(repo, req, res, proto): | |||
|
351 | """Called during a ?cmd=capabilities request. | |||
|
352 | ||||
|
353 | If the client is advertising support for a newer protocol, we send | |||
|
354 | a CBOR response with information about available services. If no | |||
|
355 | advertised services are available, we don't handle the request. | |||
|
356 | """ | |||
|
357 | # Fall back to old behavior unless the API server is enabled. | |||
|
358 | if not repo.ui.configbool('experimental', 'web.apiserver'): | |||
|
359 | return False | |||
|
360 | ||||
|
361 | clientapis = decodevaluefromheaders(req, b'X-HgUpgrade') | |||
|
362 | protocaps = decodevaluefromheaders(req, b'X-HgProto') | |||
|
363 | if not clientapis or not protocaps: | |||
|
364 | return False | |||
|
365 | ||||
|
366 | # We currently only support CBOR responses. | |||
|
367 | protocaps = set(protocaps.split(' ')) | |||
|
368 | if b'cbor' not in protocaps: | |||
|
369 | return False | |||
|
370 | ||||
|
371 | descriptors = {} | |||
|
372 | ||||
|
373 | for api in sorted(set(clientapis.split()) & _availableapis(repo)): | |||
|
374 | handler = API_HANDLERS[api] | |||
|
375 | ||||
|
376 | descriptorfn = handler.get('apidescriptor') | |||
|
377 | if not descriptorfn: | |||
|
378 | continue | |||
|
379 | ||||
|
380 | descriptors[api] = descriptorfn(req, repo) | |||
|
381 | ||||
|
382 | v1caps = wireproto.dispatch(repo, proto, 'capabilities') | |||
|
383 | assert isinstance(v1caps, wireprototypes.bytesresponse) | |||
|
384 | ||||
|
385 | m = { | |||
|
386 | # TODO allow this to be configurable. | |||
|
387 | 'apibase': 'api/', | |||
|
388 | 'apis': descriptors, | |||
|
389 | 'v1capabilities': v1caps.data, | |||
|
390 | } | |||
|
391 | ||||
|
392 | res.status = b'200 OK' | |||
|
393 | res.headers[b'Content-Type'] = b'application/mercurial-cbor' | |||
|
394 | res.setbodybytes(cbor.dumps(m, canonical=True)) | |||
|
395 | ||||
|
396 | return True | |||
|
397 | ||||
330 | def _callhttp(repo, req, res, proto, cmd): |
|
398 | def _callhttp(repo, req, res, proto, cmd): | |
331 | # Avoid cycle involving hg module. |
|
399 | # Avoid cycle involving hg module. | |
332 | from .hgweb import common as hgwebcommon |
|
400 | from .hgweb import common as hgwebcommon | |
@@ -363,6 +431,12 b' def _callhttp(repo, req, res, proto, cmd' | |||||
363 |
|
431 | |||
364 | proto.checkperm(wireproto.commands[cmd].permission) |
|
432 | proto.checkperm(wireproto.commands[cmd].permission) | |
365 |
|
433 | |||
|
434 | # Possibly handle a modern client wanting to switch protocols. | |||
|
435 | if (cmd == 'capabilities' and | |||
|
436 | processcapabilitieshandshake(repo, req, res, proto)): | |||
|
437 | ||||
|
438 | return | |||
|
439 | ||||
366 | rsp = wireproto.dispatch(repo, proto, cmd) |
|
440 | rsp = wireproto.dispatch(repo, proto, cmd) | |
367 |
|
441 | |||
368 | if isinstance(rsp, bytes): |
|
442 | if isinstance(rsp, bytes): |
@@ -365,6 +365,11 b' class httpv2protocolhandler(object):' | |||||
365 | def checkperm(self, perm): |
|
365 | def checkperm(self, perm): | |
366 | raise NotImplementedError |
|
366 | raise NotImplementedError | |
367 |
|
367 | |||
|
368 | def httpv2apidescriptor(req, repo): | |||
|
369 | proto = httpv2protocolhandler(req, repo.ui) | |||
|
370 | ||||
|
371 | return _capabilitiesv2(repo, proto) | |||
|
372 | ||||
368 | def _capabilitiesv2(repo, proto): |
|
373 | def _capabilitiesv2(repo, proto): | |
369 | """Obtain the set of capabilities for version 2 transports. |
|
374 | """Obtain the set of capabilities for version 2 transports. | |
370 |
|
375 |
@@ -1,11 +1,201 b'' | |||||
1 | $ . $TESTDIR/wireprotohelpers.sh |
|
1 | $ . $TESTDIR/wireprotohelpers.sh | |
2 |
|
2 | |||
3 | $ hg init server |
|
3 | $ hg init server | |
4 | $ enablehttpv2 server |
|
4 | $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log | |
|
5 | $ cat hg.pid > $DAEMON_PIDS | |||
|
6 | ||||
|
7 | A normal capabilities request is serviced for version 1 | |||
|
8 | ||||
|
9 | $ sendhttpraw << EOF | |||
|
10 | > httprequest GET ?cmd=capabilities | |||
|
11 | > user-agent: test | |||
|
12 | > EOF | |||
|
13 | using raw connection to peer | |||
|
14 | s> GET /?cmd=capabilities HTTP/1.1\r\n | |||
|
15 | s> Accept-Encoding: identity\r\n | |||
|
16 | s> user-agent: test\r\n | |||
|
17 | s> host: $LOCALIP:$HGPORT\r\n (glob) | |||
|
18 | s> \r\n | |||
|
19 | s> makefile('rb', None) | |||
|
20 | s> HTTP/1.1 200 Script output follows\r\n | |||
|
21 | s> Server: testing stub value\r\n | |||
|
22 | s> Date: $HTTP_DATE$\r\n | |||
|
23 | s> Content-Type: application/mercurial-0.1\r\n | |||
|
24 | s> Content-Length: 458\r\n | |||
|
25 | s> \r\n | |||
|
26 | s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash | |||
|
27 | ||||
|
28 | A proper request without the API server enabled returns the legacy response | |||
|
29 | ||||
|
30 | $ sendhttpraw << EOF | |||
|
31 | > httprequest GET ?cmd=capabilities | |||
|
32 | > user-agent: test | |||
|
33 | > x-hgupgrade-1: foo | |||
|
34 | > x-hgproto-1: cbor | |||
|
35 | > EOF | |||
|
36 | using raw connection to peer | |||
|
37 | s> GET /?cmd=capabilities HTTP/1.1\r\n | |||
|
38 | s> Accept-Encoding: identity\r\n | |||
|
39 | s> user-agent: test\r\n | |||
|
40 | s> x-hgproto-1: cbor\r\n | |||
|
41 | s> x-hgupgrade-1: foo\r\n | |||
|
42 | s> host: $LOCALIP:$HGPORT\r\n (glob) | |||
|
43 | s> \r\n | |||
|
44 | s> makefile('rb', None) | |||
|
45 | s> HTTP/1.1 200 Script output follows\r\n | |||
|
46 | s> Server: testing stub value\r\n | |||
|
47 | s> Date: $HTTP_DATE$\r\n | |||
|
48 | s> Content-Type: application/mercurial-0.1\r\n | |||
|
49 | s> Content-Length: 458\r\n | |||
|
50 | s> \r\n | |||
|
51 | s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash | |||
|
52 | ||||
|
53 | Restart with just API server enabled. This enables serving the new format. | |||
|
54 | ||||
|
55 | $ killdaemons.py | |||
|
56 | $ cat error.log | |||
|
57 | ||||
|
58 | $ cat >> server/.hg/hgrc << EOF | |||
|
59 | > [experimental] | |||
|
60 | > web.apiserver = true | |||
|
61 | > EOF | |||
|
62 | ||||
5 | $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log |
|
63 | $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log | |
6 | $ cat hg.pid > $DAEMON_PIDS |
|
64 | $ cat hg.pid > $DAEMON_PIDS | |
7 |
|
65 | |||
8 | capabilities request returns an array of capability strings |
|
66 | X-HgUpgrade-<N> without CBOR advertisement uses legacy response | |
|
67 | ||||
|
68 | $ sendhttpraw << EOF | |||
|
69 | > httprequest GET ?cmd=capabilities | |||
|
70 | > user-agent: test | |||
|
71 | > x-hgupgrade-1: foo bar | |||
|
72 | > EOF | |||
|
73 | using raw connection to peer | |||
|
74 | s> GET /?cmd=capabilities HTTP/1.1\r\n | |||
|
75 | s> Accept-Encoding: identity\r\n | |||
|
76 | s> user-agent: test\r\n | |||
|
77 | s> x-hgupgrade-1: foo bar\r\n | |||
|
78 | s> host: $LOCALIP:$HGPORT\r\n (glob) | |||
|
79 | s> \r\n | |||
|
80 | s> makefile('rb', None) | |||
|
81 | s> HTTP/1.1 200 Script output follows\r\n | |||
|
82 | s> Server: testing stub value\r\n | |||
|
83 | s> Date: $HTTP_DATE$\r\n | |||
|
84 | s> Content-Type: application/mercurial-0.1\r\n | |||
|
85 | s> Content-Length: 458\r\n | |||
|
86 | s> \r\n | |||
|
87 | s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash | |||
|
88 | ||||
|
89 | X-HgUpgrade-<N> without known serialization in X-HgProto-<N> uses legacy response | |||
|
90 | ||||
|
91 | $ sendhttpraw << EOF | |||
|
92 | > httprequest GET ?cmd=capabilities | |||
|
93 | > user-agent: test | |||
|
94 | > x-hgupgrade-1: foo bar | |||
|
95 | > x-hgproto-1: some value | |||
|
96 | > EOF | |||
|
97 | using raw connection to peer | |||
|
98 | s> GET /?cmd=capabilities HTTP/1.1\r\n | |||
|
99 | s> Accept-Encoding: identity\r\n | |||
|
100 | s> user-agent: test\r\n | |||
|
101 | s> x-hgproto-1: some value\r\n | |||
|
102 | s> x-hgupgrade-1: foo bar\r\n | |||
|
103 | s> host: $LOCALIP:$HGPORT\r\n (glob) | |||
|
104 | s> \r\n | |||
|
105 | s> makefile('rb', None) | |||
|
106 | s> HTTP/1.1 200 Script output follows\r\n | |||
|
107 | s> Server: testing stub value\r\n | |||
|
108 | s> Date: $HTTP_DATE$\r\n | |||
|
109 | s> Content-Type: application/mercurial-0.1\r\n | |||
|
110 | s> Content-Length: 458\r\n | |||
|
111 | s> \r\n | |||
|
112 | s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash | |||
|
113 | ||||
|
114 | X-HgUpgrade-<N> + X-HgProto-<N> headers trigger new response format | |||
|
115 | ||||
|
116 | $ sendhttpraw << EOF | |||
|
117 | > httprequest GET ?cmd=capabilities | |||
|
118 | > user-agent: test | |||
|
119 | > x-hgupgrade-1: foo bar | |||
|
120 | > x-hgproto-1: cbor | |||
|
121 | > EOF | |||
|
122 | using raw connection to peer | |||
|
123 | s> GET /?cmd=capabilities HTTP/1.1\r\n | |||
|
124 | s> Accept-Encoding: identity\r\n | |||
|
125 | s> user-agent: test\r\n | |||
|
126 | s> x-hgproto-1: cbor\r\n | |||
|
127 | s> x-hgupgrade-1: foo bar\r\n | |||
|
128 | s> host: $LOCALIP:$HGPORT\r\n (glob) | |||
|
129 | s> \r\n | |||
|
130 | s> makefile('rb', None) | |||
|
131 | s> HTTP/1.1 200 OK\r\n | |||
|
132 | s> Server: testing stub value\r\n | |||
|
133 | s> Date: $HTTP_DATE$\r\n | |||
|
134 | s> Content-Type: application/mercurial-cbor\r\n | |||
|
135 | s> Content-Length: 496\r\n | |||
|
136 | s> \r\n | |||
|
137 | s> \xa3Dapis\xa0GapibaseDapi/Nv1capabilitiesY\x01\xcabatch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash | |||
|
138 | cbor> {b'apibase': b'api/', b'apis': {}, b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'} | |||
|
139 | ||||
|
140 | Restart server to enable HTTPv2 | |||
|
141 | ||||
|
142 | $ killdaemons.py | |||
|
143 | $ enablehttpv2 server | |||
|
144 | $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log | |||
|
145 | ||||
|
146 | Only requested API services are returned | |||
|
147 | ||||
|
148 | $ sendhttpraw << EOF | |||
|
149 | > httprequest GET ?cmd=capabilities | |||
|
150 | > user-agent: test | |||
|
151 | > x-hgupgrade-1: foo bar | |||
|
152 | > x-hgproto-1: cbor | |||
|
153 | > EOF | |||
|
154 | using raw connection to peer | |||
|
155 | s> GET /?cmd=capabilities HTTP/1.1\r\n | |||
|
156 | s> Accept-Encoding: identity\r\n | |||
|
157 | s> user-agent: test\r\n | |||
|
158 | s> x-hgproto-1: cbor\r\n | |||
|
159 | s> x-hgupgrade-1: foo bar\r\n | |||
|
160 | s> host: $LOCALIP:$HGPORT\r\n (glob) | |||
|
161 | s> \r\n | |||
|
162 | s> makefile('rb', None) | |||
|
163 | s> HTTP/1.1 200 OK\r\n | |||
|
164 | s> Server: testing stub value\r\n | |||
|
165 | s> Date: $HTTP_DATE$\r\n | |||
|
166 | s> Content-Type: application/mercurial-cbor\r\n | |||
|
167 | s> Content-Length: 496\r\n | |||
|
168 | s> \r\n | |||
|
169 | s> \xa3Dapis\xa0GapibaseDapi/Nv1capabilitiesY\x01\xcabatch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash | |||
|
170 | cbor> {b'apibase': b'api/', b'apis': {}, b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'} | |||
|
171 | ||||
|
172 | Request for HTTPv2 service returns information about it | |||
|
173 | ||||
|
174 | $ sendhttpraw << EOF | |||
|
175 | > httprequest GET ?cmd=capabilities | |||
|
176 | > user-agent: test | |||
|
177 | > x-hgupgrade-1: exp-http-v2-0001 foo bar | |||
|
178 | > x-hgproto-1: cbor | |||
|
179 | > EOF | |||
|
180 | using raw connection to peer | |||
|
181 | s> GET /?cmd=capabilities HTTP/1.1\r\n | |||
|
182 | s> Accept-Encoding: identity\r\n | |||
|
183 | s> user-agent: test\r\n | |||
|
184 | s> x-hgproto-1: cbor\r\n | |||
|
185 | s> x-hgupgrade-1: exp-http-v2-0001 foo bar\r\n | |||
|
186 | s> host: $LOCALIP:$HGPORT\r\n (glob) | |||
|
187 | s> \r\n | |||
|
188 | s> makefile('rb', None) | |||
|
189 | s> HTTP/1.1 200 OK\r\n | |||
|
190 | s> Server: testing stub value\r\n | |||
|
191 | s> Date: $HTTP_DATE$\r\n | |||
|
192 | s> Content-Type: application/mercurial-cbor\r\n | |||
|
193 | s> Content-Length: 879\r\n | |||
|
194 | s> \r\n | |||
|
195 | s> \xa3Dapis\xa1Pexp-http-v2-0001\xa2Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibGapibaseDapi/Nv1capabilitiesY\x01\xcabatch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash | |||
|
196 | cbor> {b'apibase': b'api/', b'apis': {b'exp-http-v2-0001': {b'commands': {b'branchmap': {b'args': {}, b'permissions': [b'pull']}, b'capabilities': {b'args': {}, b'permissions': [b'pull']}, b'heads': {b'args': {b'publiconly': False}, b'permissions': [b'pull']}, b'known': {b'args': {b'nodes': [b'deadbeef']}, b'permissions': [b'pull']}, b'listkeys': {b'args': {b'namespace': b'ns'}, b'permissions': [b'pull']}, b'lookup': {b'args': {b'key': b'foo'}, b'permissions': [b'pull']}, b'pushkey': {b'args': {b'key': b'key', b'namespace': b'ns', b'new': b'new', b'old': b'old'}, b'permissions': [b'push']}}, b'compression': [{b'name': b'zstd'}, {b'name': b'zlib'}]}}, b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'} | |||
|
197 | ||||
|
198 | capabilities command returns expected info | |||
9 |
|
199 | |||
10 | $ sendhttpv2peer << EOF |
|
200 | $ sendhttpv2peer << EOF | |
11 | > command capabilities |
|
201 | > command capabilities |
General Comments 0
You need to be logged in to leave comments.
Login now