@@ -83,19 +83,37 @@ def __init__(self, stream_id, flags=()):
8383 )
8484
8585 def __repr__ (self ):
86- flags = ", " .join (self .flags ) or "None"
87- body = binascii .hexlify (self .serialize_body ()).decode ('ascii' )
88- if len (body ) > 20 :
89- body = body [:20 ] + "..."
9086 return (
91- "{type}(Stream : {stream }; Flags : {flags }): {body }"
87+ "{}(stream_id : {}; flags : {}): {}"
9288 ).format (
93- type = type (self ).__name__ ,
94- stream = self .stream_id ,
95- flags = flags ,
96- body = body ,
89+ type (self ).__name__ ,
90+ self .stream_id ,
91+ ", " . join ( sorted ( self . flags )) or "None" ,
92+ self . _body_repr () ,
9793 )
9894
95+ def _body_repr (self ):
96+ # More specific implementation may be provided by subclasses of Frame.
97+ # This fallback shows the serialized (and truncated) body content.
98+ return _raw_data_repr (self .serialize_body ())
99+
100+ @staticmethod
101+ def explain (data ):
102+ """
103+ Takes a bytestring and tries to parse a single frame and print it.
104+
105+ This function is only provided for debugging purposes.
106+
107+ :param data: A memoryview object containing the raw data of at least
108+ one complete frame (header and body).
109+
110+ .. versionadded:: 6.0.0
111+ """
112+ frame , length = Frame .parse_frame_header (data [:9 ])
113+ frame .parse_body (data [9 :9 + length ])
114+ print (frame )
115+ return frame , length
116+
99117 @staticmethod
100118 def parse_frame_header (header , strict = False ):
101119 """
@@ -331,6 +349,13 @@ class PriorityFrame(Priority, Frame):
331349
332350 stream_association = _STREAM_ASSOC_HAS_STREAM
333351
352+ def _body_repr (self ):
353+ return "exclusive: {}, depends_on: {}, stream_weight: {}" .format (
354+ self .exclusive ,
355+ self .depends_on ,
356+ self .stream_weight
357+ )
358+
334359 def serialize_body (self ):
335360 return self .serialize_priority_data ()
336361
@@ -368,6 +393,11 @@ def __init__(self, stream_id, error_code=0, **kwargs):
368393 #: The error code used when resetting the stream.
369394 self .error_code = error_code
370395
396+ def _body_repr (self ):
397+ return "error_code: {}" .format (
398+ self .error_code ,
399+ )
400+
371401 def serialize_body (self ):
372402 return _STRUCT_L .pack (self .error_code )
373403
@@ -434,6 +464,11 @@ def __init__(self, stream_id=0, settings=None, **kwargs):
434464 #: A dictionary of the setting type byte to the value of the setting.
435465 self .settings = settings or {}
436466
467+ def _body_repr (self ):
468+ return "settings: {}" .format (
469+ self .settings ,
470+ )
471+
437472 def serialize_body (self ):
438473 return b'' .join ([_STRUCT_HL .pack (setting & 0xFF , value )
439474 for setting , value in self .settings .items ()])
@@ -484,6 +519,12 @@ def __init__(self, stream_id, promised_stream_id=0, data=b'', **kwargs):
484519 #: stream.
485520 self .data = data
486521
522+ def _body_repr (self ):
523+ return "promised_stream_id: {}, data: {}" .format (
524+ self .promised_stream_id ,
525+ _raw_data_repr (self .data ),
526+ )
527+
487528 def serialize_body (self ):
488529 padding_data = self .serialize_padding_data ()
489530 padding = b'\0 ' * self .pad_length
@@ -535,6 +576,11 @@ def __init__(self, stream_id=0, opaque_data=b'', **kwargs):
535576 #: The opaque data sent in this PING frame, as a bytestring.
536577 self .opaque_data = opaque_data
537578
579+ def _body_repr (self ):
580+ return "opaque_data: {}" .format (
581+ self .opaque_data ,
582+ )
583+
538584 def serialize_body (self ):
539585 if len (self .opaque_data ) > 8 :
540586 raise InvalidFrameError (
@@ -588,6 +634,13 @@ def __init__(self,
588634 #: Any additional data sent in the GOAWAY.
589635 self .additional_data = additional_data
590636
637+ def _body_repr (self ):
638+ return "last_stream_id: {}, error_code: {}, additional_data: {}" .format (
639+ self .last_stream_id ,
640+ self .error_code ,
641+ self .additional_data ,
642+ )
643+
591644 def serialize_body (self ):
592645 data = _STRUCT_LL .pack (
593646 self .last_stream_id & 0x7FFFFFFF ,
@@ -638,6 +691,11 @@ def __init__(self, stream_id, window_increment=0, **kwargs):
638691 #: The amount the flow control window is to be incremented.
639692 self .window_increment = window_increment
640693
694+ def _body_repr (self ):
695+ return "window_increment: {}" .format (
696+ self .window_increment ,
697+ )
698+
641699 def serialize_body (self ):
642700 return _STRUCT_L .pack (self .window_increment & 0x7FFFFFFF )
643701
@@ -692,6 +750,14 @@ def __init__(self, stream_id, data=b'', **kwargs):
692750 #: The HPACK-encoded header block.
693751 self .data = data
694752
753+ def _body_repr (self ):
754+ return "exclusive: {}, depends_on: {}, stream_weight: {}, data: {}" .format (
755+ self .exclusive ,
756+ self .depends_on ,
757+ self .stream_weight ,
758+ _raw_data_repr (self .data ),
759+ )
760+
695761 def serialize_body (self ):
696762 padding_data = self .serialize_padding_data ()
697763 padding = b'\0 ' * self .pad_length
@@ -745,6 +811,11 @@ def __init__(self, stream_id, data=b'', **kwargs):
745811 #: The HPACK-encoded header block.
746812 self .data = data
747813
814+ def _body_repr (self ):
815+ return "data: {}" .format (
816+ _raw_data_repr (self .data ),
817+ )
818+
748819 def serialize_body (self ):
749820 return self .data
750821
@@ -782,6 +853,12 @@ def __init__(self, stream_id, origin=b'', field=b'', **kwargs):
782853 self .origin = origin
783854 self .field = field
784855
856+ def _body_repr (self ):
857+ return "origin: {}, field: {}" .format (
858+ self .origin ,
859+ self .field ,
860+ )
861+
785862 def serialize_body (self ):
786863 origin_len = _STRUCT_H .pack (len (self .origin ))
787864 return b'' .join ([origin_len , self .origin , self .field ])
@@ -819,10 +896,18 @@ class ExtensionFrame(Frame):
819896
820897 stream_association = _STREAM_ASSOC_EITHER
821898
822- def __init__ (self , type , stream_id , ** kwargs ):
899+ def __init__ (self , type , stream_id , flag_byte = 0x0 , body = b'' , ** kwargs ):
823900 super ().__init__ (stream_id , ** kwargs )
824901 self .type = type
825- self .flag_byte = None
902+ self .flag_byte = flag_byte
903+ self .body = body
904+
905+ def _body_repr (self ):
906+ return "type: {}, flag_byte: {}, body: {}" .format (
907+ self .type ,
908+ self .flag_byte ,
909+ _raw_data_repr (self .body ),
910+ )
826911
827912 def parse_flags (self , flag_byte ):
828913 """
@@ -856,6 +941,15 @@ def serialize(self):
856941 return header + self .body
857942
858943
944+ def _raw_data_repr (data ):
945+ if not data :
946+ return "None"
947+ r = binascii .hexlify (data ).decode ('ascii' )
948+ if len (r ) > 20 :
949+ r = r [:20 ] + "..."
950+ return r
951+
952+
859953_FRAME_CLASSES = [
860954 DataFrame ,
861955 HeadersFrame ,
0 commit comments