From patchwork Wed Mar 14 16:43:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: D2858: wireproto: define and implement responses in framing protocol From: phabricator X-Patchwork-Id: 29504 Message-Id: <628547fef7be9a2f47b737c18fdc7ac3@localhost.localdomain> To: mercurial-devel@mercurial-scm.org Date: Wed, 14 Mar 2018 16:43:30 +0000 indygreg updated this revision to Diff 7034. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2858?vs=7032&id=7034 REVISION DETAIL https://phab.mercurial-scm.org/D2858 AFFECTED FILES mercurial/help/internals/wireprotocol.txt mercurial/wireprotoframing.py mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS To: indygreg, #hg-reviewers Cc: mercurial-devel diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -180,10 +180,14 @@ s> HTTP/1.1 200 OK\r\n s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: *\r\n (glob) + s> Content-Type: application/mercurial-exp-framing-0001\r\n + s> Transfer-Encoding: chunked\r\n s> \r\n - s> lookup branchmap pushkey known getbundle unbundlehash streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + s> *\r\n (glob) + s> Y\x01\x00Blookup branchmap pushkey known getbundle unbundlehash streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + s> \r\n + s> 0\r\n + s> \r\n Request to read-write command fails because server is read-only by default @@ -287,10 +291,14 @@ s> HTTP/1.1 200 OK\r\n s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: *\r\n (glob) + s> Content-Type: application/mercurial-exp-framing-0001\r\n + s> Transfer-Encoding: chunked\r\n s> \r\n - s> lookup branchmap pushkey known getbundle unbundlehash streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + s> *\r\n (glob) + s> Y\x01\x00Blookup branchmap pushkey known getbundle unbundlehash streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + s> \r\n + s> 0\r\n + s> \r\n Authorized request for unknown command is rejected diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py --- a/mercurial/wireprotoserver.py +++ b/mercurial/wireprotoserver.py @@ -497,15 +497,20 @@ rsp = wireproto.dispatch(repo, proto, command['command']) - # TODO use proper response format. res.status = b'200 OK' - res.headers[b'Content-Type'] = b'text/plain' + res.headers[b'Content-Type'] = FRAMINGTYPE if isinstance(rsp, wireprototypes.bytesresponse): - res.setbodybytes(rsp.data) + action = reactor.onbytesresponseready(rsp.data) else: - res.setbodybytes(b'unhandled response type from wire proto ' - 'command') + action = reactor.onapplicationerror( + _('unhandled response type from wire proto command')) + + if action['action'] == b'sendframes': + res.setbodygen(action['framegen']) + else: + raise error.ProgrammingError('unhandled event from reactor: %s' % + action['action']) # Maps API name to metadata so custom API can be registered. API_HANDLERS = { diff --git a/mercurial/wireprotoframing.py b/mercurial/wireprotoframing.py --- a/mercurial/wireprotoframing.py +++ b/mercurial/wireprotoframing.py @@ -20,15 +20,20 @@ ) FRAME_HEADER_SIZE = 4 +DEFAULT_MAX_FRAME_SIZE = 32768 FRAME_TYPE_COMMAND_NAME = 0x01 FRAME_TYPE_COMMAND_ARGUMENT = 0x02 FRAME_TYPE_COMMAND_DATA = 0x03 +FRAME_TYPE_BYTES_RESPONSE = 0x04 +FRAME_TYPE_ERROR_RESPONSE = 0x05 FRAME_TYPES = { b'command-name': FRAME_TYPE_COMMAND_NAME, b'command-argument': FRAME_TYPE_COMMAND_ARGUMENT, b'command-data': FRAME_TYPE_COMMAND_DATA, + b'bytes-response': FRAME_TYPE_BYTES_RESPONSE, + b'error-response': FRAME_TYPE_ERROR_RESPONSE, } FLAG_COMMAND_NAME_EOS = 0x01 @@ -57,11 +62,29 @@ b'eos': FLAG_COMMAND_DATA_EOS, } +FLAG_BYTES_RESPONSE_CONTINUATION = 0x01 +FLAG_BYTES_RESPONSE_EOS = 0x02 + +FLAGS_BYTES_RESPONSE = { + b'continuation': FLAG_BYTES_RESPONSE_CONTINUATION, + b'eos': FLAG_BYTES_RESPONSE_EOS, +} + +FLAG_ERROR_RESPONSE_PROTOCOL = 0x01 +FLAG_ERROR_RESPONSE_APPLICATION = 0x02 + +FLAGS_ERROR_RESPONSE = { + b'protocol': FLAG_ERROR_RESPONSE_PROTOCOL, + b'application': FLAG_ERROR_RESPONSE_APPLICATION, +} + # Maps frame types to their available flags. FRAME_TYPE_FLAGS = { FRAME_TYPE_COMMAND_NAME: FLAGS_COMMAND, FRAME_TYPE_COMMAND_ARGUMENT: FLAGS_COMMAND_ARGUMENT, FRAME_TYPE_COMMAND_DATA: FLAGS_COMMAND_DATA, + FRAME_TYPE_BYTES_RESPONSE: FLAGS_BYTES_RESPONSE, + FRAME_TYPE_ERROR_RESPONSE: FLAGS_ERROR_RESPONSE, } ARGUMENT_FRAME_HEADER = struct.Struct(r'