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 |
|
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: |
|
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, |
|
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= |
|
400 | flags=0, | |
410 |
payload= |
|
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 on |
|
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 |
|
|
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.on |
|
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 test |
|
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.on |
|
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 |
|
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