##// END OF EJS Templates
wireprotov2: change behavior of error frame...
Gregory Szorc -
r37744:0c184ca5 default
parent child Browse files
Show More
@@ -688,23 +688,44 b' 0x02'
688
688
689 The ``0x01`` flag is mutually exclusive with the ``0x02`` flag.
689 The ``0x01`` flag is mutually exclusive with the ``0x02`` flag.
690
690
691 Error Response (``0x05``)
691 Error Occurred (``0x05``)
692 -------------------------
692 -------------------------
693
693
694 An error occurred when processing a request. This could indicate
694 Some kind of error occurred.
695 a protocol-level failure or an application level failure depending
695
696 on the flags for this message type.
696 There are 3 general kinds of failures that can occur:
697
697
698 The payload for this type is an error message that should be
698 * Command error encountered before any response issued
699 displayed to the user.
699 * Command error encountered after a response was issued
700 * Protocol or stream level error
701
702 This frame type is used to capture the latter cases. (The general
703 command error case is handled by the leading CBOR map in
704 ``Command Response`` frames.)
705
706 The payload of this frame contains a CBOR map detailing the error. That
707 map has the following bytestring keys:
700
708
701 The following flag values are defined for this type:
709 type
710 (bytestring) The overall type of error encountered. Can be one of the
711 following values:
712
713 protocol
714 A protocol-level error occurred. This typically means someone
715 is violating the framing protocol semantics and the server is
716 refusing to proceed.
702
717
703 0x01
718 server
704 The error occurred at the transport/protocol level. If set, the
719 A server-level error occurred. This typically indicates some kind of
705 connection should be closed.
720 logic error on the server, likely the fault of the server.
706 0x02
721
707 The error occurred at the application level. e.g. invalid command.
722 command
723 A command-level error, likely the fault of the client.
724
725 message
726 (array of maps) A richly formatted message that is intended for
727 human consumption. See the ``Human Output Side-Channel`` frame
728 section for a description of the format of this data structure.
708
729
709 Human Output Side-Channel (``0x06``)
730 Human Output Side-Channel (``0x06``)
710 ------------------------------------
731 ------------------------------------
@@ -87,20 +87,12 b' FLAGS_COMMAND_RESPONSE = {'
87 b'eos': FLAG_COMMAND_RESPONSE_EOS,
87 b'eos': FLAG_COMMAND_RESPONSE_EOS,
88 }
88 }
89
89
90 FLAG_ERROR_RESPONSE_PROTOCOL = 0x01
91 FLAG_ERROR_RESPONSE_APPLICATION = 0x02
92
93 FLAGS_ERROR_RESPONSE = {
94 b'protocol': FLAG_ERROR_RESPONSE_PROTOCOL,
95 b'application': FLAG_ERROR_RESPONSE_APPLICATION,
96 }
97
98 # Maps frame types to their available flags.
90 # Maps frame types to their available flags.
99 FRAME_TYPE_FLAGS = {
91 FRAME_TYPE_FLAGS = {
100 FRAME_TYPE_COMMAND_REQUEST: FLAGS_COMMAND_REQUEST,
92 FRAME_TYPE_COMMAND_REQUEST: FLAGS_COMMAND_REQUEST,
101 FRAME_TYPE_COMMAND_DATA: FLAGS_COMMAND_DATA,
93 FRAME_TYPE_COMMAND_DATA: FLAGS_COMMAND_DATA,
102 FRAME_TYPE_COMMAND_RESPONSE: FLAGS_COMMAND_RESPONSE,
94 FRAME_TYPE_COMMAND_RESPONSE: FLAGS_COMMAND_RESPONSE,
103 FRAME_TYPE_ERROR_RESPONSE: FLAGS_ERROR_RESPONSE,
95 FRAME_TYPE_ERROR_RESPONSE: {},
104 FRAME_TYPE_TEXT_OUTPUT: {},
96 FRAME_TYPE_TEXT_OUTPUT: {},
105 FRAME_TYPE_PROGRESS: {},
97 FRAME_TYPE_PROGRESS: {},
106 FRAME_TYPE_STREAM_SETTINGS: {},
98 FRAME_TYPE_STREAM_SETTINGS: {},
@@ -394,20 +386,19 b' def createcommandresponseframesfrombytes'
394 if done:
386 if done:
395 break
387 break
396
388
397 def createerrorframe(stream, requestid, msg, protocol=False, application=False):
389 def createerrorframe(stream, requestid, msg, errtype):
398 # TODO properly handle frame size limits.
390 # TODO properly handle frame size limits.
399 assert len(msg) <= DEFAULT_MAX_FRAME_SIZE
391 assert len(msg) <= DEFAULT_MAX_FRAME_SIZE
400
392
401 flags = 0
393 payload = cbor.dumps({
402 if protocol:
394 b'type': errtype,
403 flags |= FLAG_ERROR_RESPONSE_PROTOCOL
395 b'message': [{b'msg': msg}],
404 if application:
396 }, canonical=True)
405 flags |= FLAG_ERROR_RESPONSE_APPLICATION
406
397
407 yield stream.makeframe(requestid=requestid,
398 yield stream.makeframe(requestid=requestid,
408 typeid=FRAME_TYPE_ERROR_RESPONSE,
399 typeid=FRAME_TYPE_ERROR_RESPONSE,
409 flags=flags,
400 flags=0,
410 payload=msg)
401 payload=payload)
411
402
412 def createtextoutputframe(stream, requestid, atoms,
403 def createtextoutputframe(stream, requestid, atoms,
413 maxframesize=DEFAULT_MAX_FRAME_SIZE):
404 maxframesize=DEFAULT_MAX_FRAME_SIZE):
@@ -664,12 +655,12 b' class serverreactor(object):'
664 'framegen': makegen(),
655 'framegen': makegen(),
665 }
656 }
666
657
667 def onapplicationerror(self, stream, requestid, msg):
658 def onservererror(self, stream, requestid, msg):
668 ensureserverstream(stream)
659 ensureserverstream(stream)
669
660
670 return 'sendframes', {
661 return 'sendframes', {
671 'framegen': createerrorframe(stream, requestid, msg,
662 'framegen': createerrorframe(stream, requestid, msg,
672 application=True),
663 errtype='server'),
673 }
664 }
674
665
675 def makeoutputstream(self):
666 def makeoutputstream(self):
@@ -1051,6 +1042,7 b' class clientreactor(object):'
1051
1042
1052 handlers = {
1043 handlers = {
1053 FRAME_TYPE_COMMAND_RESPONSE: self._oncommandresponseframe,
1044 FRAME_TYPE_COMMAND_RESPONSE: self._oncommandresponseframe,
1045 FRAME_TYPE_ERROR_RESPONSE: self._onerrorresponseframe,
1054 }
1046 }
1055
1047
1056 meth = handlers.get(frame.typeid)
1048 meth = handlers.get(frame.typeid)
@@ -1071,3 +1063,16 b' class clientreactor(object):'
1071 'eos': frame.flags & FLAG_COMMAND_RESPONSE_EOS,
1063 'eos': frame.flags & FLAG_COMMAND_RESPONSE_EOS,
1072 'data': frame.payload,
1064 'data': frame.payload,
1073 }
1065 }
1066
1067 def _onerrorresponseframe(self, request, frame):
1068 request.state = 'errored'
1069 del self._activerequests[request.requestid]
1070
1071 # The payload should be a CBOR map.
1072 m = cbor.loads(frame.payload)
1073
1074 return 'error', {
1075 'request': request,
1076 'type': m['type'],
1077 'message': m['message'],
1078 }
@@ -311,7 +311,7 b' def _httpv2runcommand(ui, repo, req, res'
311 command['requestid'],
311 command['requestid'],
312 encoded)
312 encoded)
313 else:
313 else:
314 action, meta = reactor.onapplicationerror(
314 action, meta = reactor.onservererror(
315 _('unhandled response type from wire proto command'))
315 _('unhandled response type from wire proto command'))
316
316
317 if action == 'sendframes':
317 if action == 'sendframes':
@@ -373,16 +373,18 b' class ServerReactorTests(unittest.TestCa'
373 b'1 2 0 command-response eos %s' % second,
373 b'1 2 0 command-response eos %s' % second,
374 ])
374 ])
375
375
376 def testapplicationerror(self):
376 def testservererror(self):
377 reactor = makereactor()
377 reactor = makereactor()
378 instream = framing.stream(1)
378 instream = framing.stream(1)
379 list(sendcommandframes(reactor, instream, 1, b'mycommand', {}))
379 list(sendcommandframes(reactor, instream, 1, b'mycommand', {}))
380
380
381 outstream = reactor.makeoutputstream()
381 outstream = reactor.makeoutputstream()
382 result = reactor.onapplicationerror(outstream, 1, b'some message')
382 result = reactor.onservererror(outstream, 1, b'some message')
383 self.assertaction(result, b'sendframes')
383 self.assertaction(result, b'sendframes')
384 self.assertframesequal(result[1][b'framegen'], [
384 self.assertframesequal(result[1][b'framegen'], [
385 b'1 2 stream-begin error-response application some message',
385 b"1 2 stream-begin error-response 0 "
386 b"cbor:{b'type': b'server', "
387 b"b'message': [{b'msg': b'some message'}]}",
386 ])
388 ])
387
389
388 def test1commanddeferresponse(self):
390 def test1commanddeferresponse(self):
General Comments 0
You need to be logged in to leave comments. Login now