426 """Create an empty payload frame representing command end-of-stream.""" |
427 """Create an empty payload frame representing command end-of-stream.""" |
427 return stream.makeframe(requestid=requestid, |
428 return stream.makeframe(requestid=requestid, |
428 typeid=FRAME_TYPE_COMMAND_RESPONSE, |
429 typeid=FRAME_TYPE_COMMAND_RESPONSE, |
429 flags=FLAG_COMMAND_RESPONSE_EOS, |
430 flags=FLAG_COMMAND_RESPONSE_EOS, |
430 payload=b'') |
431 payload=b'') |
|
432 |
|
433 def createalternatelocationresponseframe(stream, requestid, location): |
|
434 data = { |
|
435 b'status': b'redirect', |
|
436 b'location': { |
|
437 b'url': location.url, |
|
438 b'mediatype': location.mediatype, |
|
439 } |
|
440 } |
|
441 |
|
442 for a in (r'size', r'fullhashes', r'fullhashseed', r'serverdercerts', |
|
443 r'servercadercerts'): |
|
444 value = getattr(location, a) |
|
445 if value is not None: |
|
446 data[b'location'][pycompat.bytestr(a)] = value |
|
447 |
|
448 return stream.makeframe(requestid=requestid, |
|
449 typeid=FRAME_TYPE_COMMAND_RESPONSE, |
|
450 flags=FLAG_COMMAND_RESPONSE_CONTINUATION, |
|
451 payload=b''.join(cborutil.streamencode(data))) |
431 |
452 |
432 def createcommanderrorresponse(stream, requestid, message, args=None): |
453 def createcommanderrorresponse(stream, requestid, message, args=None): |
433 # TODO should this be using a list of {'msg': ..., 'args': {}} so atom |
454 # TODO should this be using a list of {'msg': ..., 'args': {}} so atom |
434 # formatting works consistently? |
455 # formatting works consistently? |
435 m = { |
456 m = { |
811 # In all cases, when the function finishes, the request is fully |
832 # In all cases, when the function finishes, the request is fully |
812 # handled and no new frames for it should be seen. |
833 # handled and no new frames for it should be seen. |
813 |
834 |
814 def sendframes(): |
835 def sendframes(): |
815 emitted = False |
836 emitted = False |
|
837 alternatelocationsent = False |
816 emitter = bufferingcommandresponseemitter(stream, requestid) |
838 emitter = bufferingcommandresponseemitter(stream, requestid) |
817 while True: |
839 while True: |
818 try: |
840 try: |
819 o = next(objs) |
841 o = next(objs) |
820 except StopIteration: |
842 except StopIteration: |
839 yield frame |
861 yield frame |
840 |
862 |
841 break |
863 break |
842 |
864 |
843 try: |
865 try: |
|
866 # Alternate location responses can only be the first and |
|
867 # only object in the output stream. |
|
868 if isinstance(o, wireprototypes.alternatelocationresponse): |
|
869 if emitted: |
|
870 raise error.ProgrammingError( |
|
871 'alternatelocationresponse seen after initial ' |
|
872 'output object') |
|
873 |
|
874 yield createalternatelocationresponseframe( |
|
875 stream, requestid, o) |
|
876 |
|
877 alternatelocationsent = True |
|
878 emitted = True |
|
879 continue |
|
880 |
|
881 if alternatelocationsent: |
|
882 raise error.ProgrammingError( |
|
883 'object follows alternatelocationresponse') |
|
884 |
844 if not emitted: |
885 if not emitted: |
845 yield createcommandresponseokframe(stream, requestid) |
886 yield createcommandresponseokframe(stream, requestid) |
846 emitted = True |
887 emitted = True |
847 |
888 |
848 # Objects emitted by command functions can be serializable |
889 # Objects emitted by command functions can be serializable |
975 |
1016 |
976 return 'runcommand', { |
1017 return 'runcommand', { |
977 'requestid': requestid, |
1018 'requestid': requestid, |
978 'command': request[b'name'], |
1019 'command': request[b'name'], |
979 'args': request[b'args'], |
1020 'args': request[b'args'], |
|
1021 'redirect': request.get(b'redirect'), |
980 'data': entry['data'].getvalue() if entry['data'] else None, |
1022 'data': entry['data'].getvalue() if entry['data'] else None, |
981 } |
1023 } |
982 |
1024 |
983 def _makewantframeresult(self): |
1025 def _makewantframeresult(self): |
984 return 'wantframe', { |
1026 return 'wantframe', { |