1# -*- coding: utf-8 -*- 2""" 3hyperframe/frame 4~~~~~~~~~~~~~~~~ 5 6Defines framing logic for HTTP/2. Provides both classes to represent framed 7data and logic for aiding the connection when it comes to reading from the 8socket. 9""" 10import struct 11import binascii 12 13from .exceptions import ( 14 UnknownFrameError, InvalidPaddingError, InvalidFrameError, InvalidDataError 15) 16from .flags import Flag, Flags 17 18 19# The maximum initial length of a frame. Some frames have shorter maximum 20# lengths. 21FRAME_MAX_LEN = (2 ** 14) 22 23# The maximum allowed length of a frame. 24FRAME_MAX_ALLOWED_LEN = (2 ** 24) - 1 25 26# Stream association enumerations. 27_STREAM_ASSOC_HAS_STREAM = "has-stream" 28_STREAM_ASSOC_NO_STREAM = "no-stream" 29_STREAM_ASSOC_EITHER = "either" 30 31# Structs for packing and unpacking 32_STRUCT_HBBBL = struct.Struct(">HBBBL") 33_STRUCT_LL = struct.Struct(">LL") 34_STRUCT_HL = struct.Struct(">HL") 35_STRUCT_LB = struct.Struct(">LB") 36_STRUCT_L = struct.Struct(">L") 37_STRUCT_H = struct.Struct(">H") 38_STRUCT_B = struct.Struct(">B") 39 40 41class Frame: 42 """ 43 The base class for all HTTP/2 frames. 44 """ 45 #: The flags defined on this type of frame. 46 defined_flags = [] 47 48 #: The byte used to define the type of the frame. 49 type = None 50 51 # If 'has-stream', the frame's stream_id must be non-zero. If 'no-stream', 52 # it must be zero. If 'either', it's not checked. 53 stream_association = None 54 55 def __init__(self, stream_id, flags=()): 56 #: The stream identifier for the stream this frame was received on. 57 #: Set to 0 for frames sent on the connection (stream-id 0). 58 self.stream_id = stream_id 59 60 #: The flags set for this frame. 61 self.flags = Flags(self.defined_flags) 62 63 #: The frame length, excluding the nine-byte header. 64 self.body_len = 0 65 66 for flag in flags: 67 self.flags.add(flag) 68 69 if (not self.stream_id and 70 self.stream_association == _STREAM_ASSOC_HAS_STREAM): 71 raise InvalidDataError( 72 'Stream ID must be non-zero for {}'.format( 73 type(self).__name__, 74 ) 75 ) 76 if (self.stream_id and 77 self.stream_association == _STREAM_ASSOC_NO_STREAM): 78 raise InvalidDataError( 79 'Stream ID must be zero for {} with stream_id={}'.format( 80 type(self).__name__, 81 self.stream_id, 82 ) 83 ) 84 85 def __repr__(self): 86 return ( 87 "{}(stream_id={}, flags={}): {}" 88 ).format( 89 type(self).__name__, 90 self.stream_id, 91 repr(self.flags), 92 self._body_repr(), 93 ) 94 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 117 @staticmethod 118 def parse_frame_header(header, strict=False): 119 """ 120 Takes a 9-byte frame header and returns a tuple of the appropriate 121 Frame object and the length that needs to be read from the socket. 122 123 This populates the flags field, and determines how long the body is. 124 125 :param header: A memoryview object containing the 9-byte frame header 126 data of a frame. Must not contain more or less. 127 128 :param strict: Whether to raise an exception when encountering a frame 129 not defined by spec and implemented by hyperframe. 130 131 :raises hyperframe.exceptions.UnknownFrameError: If a frame of unknown 132 type is received. 133 134 .. versionchanged:: 5.0.0 135 Added :param:`strict` to accommodate :class:`ExtensionFrame` 136 """ 137 try: 138 fields = _STRUCT_HBBBL.unpack(header) 139 except struct.error: 140 raise InvalidFrameError("Invalid frame header") 141 142 # First 24 bits are frame length. 143 length = (fields[0] << 8) + fields[1] 144 type = fields[2] 145 flags = fields[3] 146 stream_id = fields[4] & 0x7FFFFFFF 147 148 try: 149 frame = FRAMES[type](stream_id) 150 except KeyError: 151 if strict: 152 raise UnknownFrameError(type, length) 153 frame = ExtensionFrame(type=type, stream_id=stream_id) 154 155 frame.parse_flags(flags) 156 return (frame, length) 157 158 def parse_flags(self, flag_byte): 159 for flag, flag_bit in self.defined_flags: 160 if flag_byte & flag_bit: 161 self.flags.add(flag) 162 163 return self.flags 164 165 def serialize(self): 166 """ 167 Convert a frame into a bytestring, representing the serialized form of 168 the frame. 169 """ 170 body = self.serialize_body() 171 self.body_len = len(body) 172 173 # Build the common frame header. 174 # First, get the flags. 175 flags = 0 176 177 for flag, flag_bit in self.defined_flags: 178 if flag in self.flags: 179 flags |= flag_bit 180 181 header = _STRUCT_HBBBL.pack( 182 (self.body_len >> 8) & 0xFFFF, # Length spread over top 24 bits 183 self.body_len & 0xFF, 184 self.type, 185 flags, 186 self.stream_id & 0x7FFFFFFF # Stream ID is 32 bits. 187 ) 188 189 return header + body 190 191 def serialize_body(self): 192 raise NotImplementedError() 193 194 def parse_body(self, data): 195 """ 196 Given the body of a frame, parses it into frame data. This populates 197 the non-header parts of the frame: that is, it does not populate the 198 stream ID or flags. 199 200 :param data: A memoryview object containing the body data of the frame. 201 Must not contain *more* data than the length returned by 202 :meth:`parse_frame_header 203 <hyperframe.frame.Frame.parse_frame_header>`. 204 """ 205 raise NotImplementedError() 206 207 208class Padding: 209 """ 210 Mixin for frames that contain padding. Defines extra fields that can be 211 used and set by frames that can be padded. 212 """ 213 def __init__(self, stream_id, pad_length=0, **kwargs): 214 super().__init__(stream_id, **kwargs) 215 216 #: The length of the padding to use. 217 self.pad_length = pad_length 218 219 def serialize_padding_data(self): 220 if 'PADDED' in self.flags: 221 return _STRUCT_B.pack(self.pad_length) 222 return b'' 223 224 def parse_padding_data(self, data): 225 if 'PADDED' in self.flags: 226 try: 227 self.pad_length = struct.unpack('!B', data[:1])[0] 228 except struct.error: 229 raise InvalidFrameError("Invalid Padding data") 230 return 1 231 return 0 232 233 #: .. deprecated:: 5.2.1 234 #: Use self.pad_length instead. 235 @property 236 def total_padding(self): # pragma: no cover 237 import warnings 238 warnings.warn( 239 "total_padding contains the same information as pad_length.", 240 DeprecationWarning 241 ) 242 return self.pad_length 243 244 245class Priority: 246 """ 247 Mixin for frames that contain priority data. Defines extra fields that can 248 be used and set by frames that contain priority data. 249 """ 250 def __init__(self, 251 stream_id, 252 depends_on=0x0, 253 stream_weight=0x0, 254 exclusive=False, 255 **kwargs): 256 super().__init__(stream_id, **kwargs) 257 258 #: The stream ID of the stream on which this stream depends. 259 self.depends_on = depends_on 260 261 #: The weight of the stream. This is an integer between 0 and 256. 262 self.stream_weight = stream_weight 263 264 #: Whether the exclusive bit was set. 265 self.exclusive = exclusive 266 267 def serialize_priority_data(self): 268 return _STRUCT_LB.pack( 269 self.depends_on + (0x80000000 if self.exclusive else 0), 270 self.stream_weight 271 ) 272 273 def parse_priority_data(self, data): 274 try: 275 self.depends_on, self.stream_weight = _STRUCT_LB.unpack(data[:5]) 276 except struct.error: 277 raise InvalidFrameError("Invalid Priority data") 278 279 self.exclusive = True if self.depends_on >> 31 else False 280 self.depends_on &= 0x7FFFFFFF 281 return 5 282 283 284class DataFrame(Padding, Frame): 285 """ 286 DATA frames convey arbitrary, variable-length sequences of octets 287 associated with a stream. One or more DATA frames are used, for instance, 288 to carry HTTP request or response payloads. 289 """ 290 #: The flags defined for DATA frames. 291 defined_flags = [ 292 Flag('END_STREAM', 0x01), 293 Flag('PADDED', 0x08), 294 ] 295 296 #: The type byte for data frames. 297 type = 0x0 298 299 stream_association = _STREAM_ASSOC_HAS_STREAM 300 301 def __init__(self, stream_id, data=b'', **kwargs): 302 super().__init__(stream_id, **kwargs) 303 304 #: The data contained on this frame. 305 self.data = data 306 307 def serialize_body(self): 308 padding_data = self.serialize_padding_data() 309 padding = b'\0' * self.pad_length 310 if isinstance(self.data, memoryview): 311 self.data = self.data.tobytes() 312 return b''.join([padding_data, self.data, padding]) 313 314 def parse_body(self, data): 315 padding_data_length = self.parse_padding_data(data) 316 self.data = ( 317 data[padding_data_length:len(data)-self.pad_length].tobytes() 318 ) 319 self.body_len = len(data) 320 321 if self.pad_length and self.pad_length >= self.body_len: 322 raise InvalidPaddingError("Padding is too long.") 323 324 @property 325 def flow_controlled_length(self): 326 """ 327 The length of the frame that needs to be accounted for when considering 328 flow control. 329 """ 330 padding_len = 0 331 if 'PADDED' in self.flags: 332 # Account for extra 1-byte padding length field, which is still 333 # present if possibly zero-valued. 334 padding_len = self.pad_length + 1 335 return len(self.data) + padding_len 336 337 338class PriorityFrame(Priority, Frame): 339 """ 340 The PRIORITY frame specifies the sender-advised priority of a stream. It 341 can be sent at any time for an existing stream. This enables 342 reprioritisation of existing streams. 343 """ 344 #: The flags defined for PRIORITY frames. 345 defined_flags = [] 346 347 #: The type byte defined for PRIORITY frames. 348 type = 0x02 349 350 stream_association = _STREAM_ASSOC_HAS_STREAM 351 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 359 def serialize_body(self): 360 return self.serialize_priority_data() 361 362 def parse_body(self, data): 363 if len(data) > 5: 364 raise InvalidFrameError( 365 "PRIORITY must have 5 byte body: actual length %s." % 366 len(data) 367 ) 368 369 self.parse_priority_data(data) 370 self.body_len = 5 371 372 373class RstStreamFrame(Frame): 374 """ 375 The RST_STREAM frame allows for abnormal termination of a stream. When sent 376 by the initiator of a stream, it indicates that they wish to cancel the 377 stream or that an error condition has occurred. When sent by the receiver 378 of a stream, it indicates that either the receiver is rejecting the stream, 379 requesting that the stream be cancelled or that an error condition has 380 occurred. 381 """ 382 #: The flags defined for RST_STREAM frames. 383 defined_flags = [] 384 385 #: The type byte defined for RST_STREAM frames. 386 type = 0x03 387 388 stream_association = _STREAM_ASSOC_HAS_STREAM 389 390 def __init__(self, stream_id, error_code=0, **kwargs): 391 super().__init__(stream_id, **kwargs) 392 393 #: The error code used when resetting the stream. 394 self.error_code = error_code 395 396 def _body_repr(self): 397 return "error_code={}".format( 398 self.error_code, 399 ) 400 401 def serialize_body(self): 402 return _STRUCT_L.pack(self.error_code) 403 404 def parse_body(self, data): 405 if len(data) != 4: 406 raise InvalidFrameError( 407 "RST_STREAM must have 4 byte body: actual length %s." % 408 len(data) 409 ) 410 411 try: 412 self.error_code = _STRUCT_L.unpack(data)[0] 413 except struct.error: # pragma: no cover 414 raise InvalidFrameError("Invalid RST_STREAM body") 415 416 self.body_len = 4 417 418 419class SettingsFrame(Frame): 420 """ 421 The SETTINGS frame conveys configuration parameters that affect how 422 endpoints communicate. The parameters are either constraints on peer 423 behavior or preferences. 424 425 Settings are not negotiated. Settings describe characteristics of the 426 sending peer, which are used by the receiving peer. Different values for 427 the same setting can be advertised by each peer. For example, a client 428 might set a high initial flow control window, whereas a server might set a 429 lower value to conserve resources. 430 """ 431 #: The flags defined for SETTINGS frames. 432 defined_flags = [Flag('ACK', 0x01)] 433 434 #: The type byte defined for SETTINGS frames. 435 type = 0x04 436 437 stream_association = _STREAM_ASSOC_NO_STREAM 438 439 # We need to define the known settings, they may as well be class 440 # attributes. 441 #: The byte that signals the SETTINGS_HEADER_TABLE_SIZE setting. 442 HEADER_TABLE_SIZE = 0x01 443 #: The byte that signals the SETTINGS_ENABLE_PUSH setting. 444 ENABLE_PUSH = 0x02 445 #: The byte that signals the SETTINGS_MAX_CONCURRENT_STREAMS setting. 446 MAX_CONCURRENT_STREAMS = 0x03 447 #: The byte that signals the SETTINGS_INITIAL_WINDOW_SIZE setting. 448 INITIAL_WINDOW_SIZE = 0x04 449 #: The byte that signals the SETTINGS_MAX_FRAME_SIZE setting. 450 MAX_FRAME_SIZE = 0x05 451 #: The byte that signals the SETTINGS_MAX_HEADER_LIST_SIZE setting. 452 MAX_HEADER_LIST_SIZE = 0x06 453 #: The byte that signals SETTINGS_ENABLE_CONNECT_PROTOCOL setting. 454 ENABLE_CONNECT_PROTOCOL = 0x08 455 456 def __init__(self, stream_id=0, settings=None, **kwargs): 457 super().__init__(stream_id, **kwargs) 458 459 if settings and "ACK" in kwargs.get("flags", ()): 460 raise InvalidDataError( 461 "Settings must be empty if ACK flag is set." 462 ) 463 464 #: A dictionary of the setting type byte to the value of the setting. 465 self.settings = settings or {} 466 467 def _body_repr(self): 468 return "settings={}".format( 469 self.settings, 470 ) 471 472 def serialize_body(self): 473 return b''.join([_STRUCT_HL.pack(setting & 0xFF, value) 474 for setting, value in self.settings.items()]) 475 476 def parse_body(self, data): 477 if 'ACK' in self.flags and len(data) > 0: 478 raise InvalidDataError( 479 "SETTINGS ack frame must not have payload: got %s bytes" % 480 len(data) 481 ) 482 483 body_len = 0 484 for i in range(0, len(data), 6): 485 try: 486 name, value = _STRUCT_HL.unpack(data[i:i+6]) 487 except struct.error: 488 raise InvalidFrameError("Invalid SETTINGS body") 489 490 self.settings[name] = value 491 body_len += 6 492 493 self.body_len = body_len 494 495 496class PushPromiseFrame(Padding, Frame): 497 """ 498 The PUSH_PROMISE frame is used to notify the peer endpoint in advance of 499 streams the sender intends to initiate. 500 """ 501 #: The flags defined for PUSH_PROMISE frames. 502 defined_flags = [ 503 Flag('END_HEADERS', 0x04), 504 Flag('PADDED', 0x08) 505 ] 506 507 #: The type byte defined for PUSH_PROMISE frames. 508 type = 0x05 509 510 stream_association = _STREAM_ASSOC_HAS_STREAM 511 512 def __init__(self, stream_id, promised_stream_id=0, data=b'', **kwargs): 513 super().__init__(stream_id, **kwargs) 514 515 #: The stream ID that is promised by this frame. 516 self.promised_stream_id = promised_stream_id 517 518 #: The HPACK-encoded header block for the simulated request on the new 519 #: stream. 520 self.data = data 521 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 528 def serialize_body(self): 529 padding_data = self.serialize_padding_data() 530 padding = b'\0' * self.pad_length 531 data = _STRUCT_L.pack(self.promised_stream_id) 532 return b''.join([padding_data, data, self.data, padding]) 533 534 def parse_body(self, data): 535 padding_data_length = self.parse_padding_data(data) 536 537 try: 538 self.promised_stream_id = _STRUCT_L.unpack( 539 data[padding_data_length:padding_data_length + 4] 540 )[0] 541 except struct.error: 542 raise InvalidFrameError("Invalid PUSH_PROMISE body") 543 544 self.data = ( 545 data[padding_data_length + 4:len(data)-self.pad_length].tobytes() 546 ) 547 self.body_len = len(data) 548 549 if self.promised_stream_id == 0 or self.promised_stream_id % 2 != 0: 550 raise InvalidDataError( 551 "Invalid PUSH_PROMISE promised stream id: %s" % 552 self.promised_stream_id 553 ) 554 555 if self.pad_length and self.pad_length >= self.body_len: 556 raise InvalidPaddingError("Padding is too long.") 557 558 559class PingFrame(Frame): 560 """ 561 The PING frame is a mechanism for measuring a minimal round-trip time from 562 the sender, as well as determining whether an idle connection is still 563 functional. PING frames can be sent from any endpoint. 564 """ 565 #: The flags defined for PING frames. 566 defined_flags = [Flag('ACK', 0x01)] 567 568 #: The type byte defined for PING frames. 569 type = 0x06 570 571 stream_association = _STREAM_ASSOC_NO_STREAM 572 573 def __init__(self, stream_id=0, opaque_data=b'', **kwargs): 574 super().__init__(stream_id, **kwargs) 575 576 #: The opaque data sent in this PING frame, as a bytestring. 577 self.opaque_data = opaque_data 578 579 def _body_repr(self): 580 return "opaque_data={}".format( 581 self.opaque_data, 582 ) 583 584 def serialize_body(self): 585 if len(self.opaque_data) > 8: 586 raise InvalidFrameError( 587 "PING frame may not have more than 8 bytes of data, got %s" % 588 self.opaque_data 589 ) 590 591 data = self.opaque_data 592 data += b'\x00' * (8 - len(self.opaque_data)) 593 return data 594 595 def parse_body(self, data): 596 if len(data) != 8: 597 raise InvalidFrameError( 598 "PING frame must have 8 byte length: got %s" % len(data) 599 ) 600 601 self.opaque_data = data.tobytes() 602 self.body_len = 8 603 604 605class GoAwayFrame(Frame): 606 """ 607 The GOAWAY frame informs the remote peer to stop creating streams on this 608 connection. It can be sent from the client or the server. Once sent, the 609 sender will ignore frames sent on new streams for the remainder of the 610 connection. 611 """ 612 #: The flags defined for GOAWAY frames. 613 defined_flags = [] 614 615 #: The type byte defined for GOAWAY frames. 616 type = 0x07 617 618 stream_association = _STREAM_ASSOC_NO_STREAM 619 620 def __init__(self, 621 stream_id=0, 622 last_stream_id=0, 623 error_code=0, 624 additional_data=b'', 625 **kwargs): 626 super().__init__(stream_id, **kwargs) 627 628 #: The last stream ID definitely seen by the remote peer. 629 self.last_stream_id = last_stream_id 630 631 #: The error code for connection teardown. 632 self.error_code = error_code 633 634 #: Any additional data sent in the GOAWAY. 635 self.additional_data = additional_data 636 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 644 def serialize_body(self): 645 data = _STRUCT_LL.pack( 646 self.last_stream_id & 0x7FFFFFFF, 647 self.error_code 648 ) 649 data += self.additional_data 650 651 return data 652 653 def parse_body(self, data): 654 try: 655 self.last_stream_id, self.error_code = _STRUCT_LL.unpack( 656 data[:8] 657 ) 658 except struct.error: 659 raise InvalidFrameError("Invalid GOAWAY body.") 660 661 self.body_len = len(data) 662 663 if len(data) > 8: 664 self.additional_data = data[8:].tobytes() 665 666 667class WindowUpdateFrame(Frame): 668 """ 669 The WINDOW_UPDATE frame is used to implement flow control. 670 671 Flow control operates at two levels: on each individual stream and on the 672 entire connection. 673 674 Both types of flow control are hop by hop; that is, only between the two 675 endpoints. Intermediaries do not forward WINDOW_UPDATE frames between 676 dependent connections. However, throttling of data transfer by any receiver 677 can indirectly cause the propagation of flow control information toward the 678 original sender. 679 """ 680 #: The flags defined for WINDOW_UPDATE frames. 681 defined_flags = [] 682 683 #: The type byte defined for WINDOW_UPDATE frames. 684 type = 0x08 685 686 stream_association = _STREAM_ASSOC_EITHER 687 688 def __init__(self, stream_id, window_increment=0, **kwargs): 689 super().__init__(stream_id, **kwargs) 690 691 #: The amount the flow control window is to be incremented. 692 self.window_increment = window_increment 693 694 def _body_repr(self): 695 return "window_increment={}".format( 696 self.window_increment, 697 ) 698 699 def serialize_body(self): 700 return _STRUCT_L.pack(self.window_increment & 0x7FFFFFFF) 701 702 def parse_body(self, data): 703 if len(data) > 4: 704 raise InvalidFrameError( 705 "WINDOW_UPDATE frame must have 4 byte length: got %s" % 706 len(data) 707 ) 708 709 try: 710 self.window_increment = _STRUCT_L.unpack(data)[0] 711 except struct.error: 712 raise InvalidFrameError("Invalid WINDOW_UPDATE body") 713 714 if not 1 <= self.window_increment <= 2**31-1: 715 raise InvalidDataError( 716 "WINDOW_UPDATE increment must be between 1 to 2^31-1" 717 ) 718 719 self.body_len = 4 720 721 722class HeadersFrame(Padding, Priority, Frame): 723 """ 724 The HEADERS frame carries name-value pairs. It is used to open a stream. 725 HEADERS frames can be sent on a stream in the "open" or "half closed 726 (remote)" states. 727 728 The HeadersFrame class is actually basically a data frame in this 729 implementation, because of the requirement to control the sizes of frames. 730 A header block fragment that doesn't fit in an entire HEADERS frame needs 731 to be followed with CONTINUATION frames. From the perspective of the frame 732 building code the header block is an opaque data segment. 733 """ 734 #: The flags defined for HEADERS frames. 735 defined_flags = [ 736 Flag('END_STREAM', 0x01), 737 Flag('END_HEADERS', 0x04), 738 Flag('PADDED', 0x08), 739 Flag('PRIORITY', 0x20), 740 ] 741 742 #: The type byte defined for HEADERS frames. 743 type = 0x01 744 745 stream_association = _STREAM_ASSOC_HAS_STREAM 746 747 def __init__(self, stream_id, data=b'', **kwargs): 748 super().__init__(stream_id, **kwargs) 749 750 #: The HPACK-encoded header block. 751 self.data = data 752 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 761 def serialize_body(self): 762 padding_data = self.serialize_padding_data() 763 padding = b'\0' * self.pad_length 764 765 if 'PRIORITY' in self.flags: 766 priority_data = self.serialize_priority_data() 767 else: 768 priority_data = b'' 769 770 return b''.join([padding_data, priority_data, self.data, padding]) 771 772 def parse_body(self, data): 773 padding_data_length = self.parse_padding_data(data) 774 data = data[padding_data_length:] 775 776 if 'PRIORITY' in self.flags: 777 priority_data_length = self.parse_priority_data(data) 778 else: 779 priority_data_length = 0 780 781 self.body_len = len(data) 782 self.data = ( 783 data[priority_data_length:len(data)-self.pad_length].tobytes() 784 ) 785 786 if self.pad_length and self.pad_length >= self.body_len: 787 raise InvalidPaddingError("Padding is too long.") 788 789 790class ContinuationFrame(Frame): 791 """ 792 The CONTINUATION frame is used to continue a sequence of header block 793 fragments. Any number of CONTINUATION frames can be sent on an existing 794 stream, as long as the preceding frame on the same stream is one of 795 HEADERS, PUSH_PROMISE or CONTINUATION without the END_HEADERS flag set. 796 797 Much like the HEADERS frame, hyper treats this as an opaque data frame with 798 different flags and a different type. 799 """ 800 #: The flags defined for CONTINUATION frames. 801 defined_flags = [Flag('END_HEADERS', 0x04)] 802 803 #: The type byte defined for CONTINUATION frames. 804 type = 0x09 805 806 stream_association = _STREAM_ASSOC_HAS_STREAM 807 808 def __init__(self, stream_id, data=b'', **kwargs): 809 super().__init__(stream_id, **kwargs) 810 811 #: The HPACK-encoded header block. 812 self.data = data 813 814 def _body_repr(self): 815 return "data={}".format( 816 _raw_data_repr(self.data), 817 ) 818 819 def serialize_body(self): 820 return self.data 821 822 def parse_body(self, data): 823 self.data = data.tobytes() 824 self.body_len = len(data) 825 826 827class AltSvcFrame(Frame): 828 """ 829 The ALTSVC frame is used to advertise alternate services that the current 830 host, or a different one, can understand. This frame is standardised as 831 part of RFC 7838. 832 833 This frame does no work to validate that the ALTSVC field parameter is 834 acceptable per the rules of RFC 7838. 835 836 .. note:: If the ``stream_id`` of this frame is nonzero, the origin field 837 must have zero length. Conversely, if the ``stream_id`` of this 838 frame is zero, the origin field must have nonzero length. Put 839 another way, a valid ALTSVC frame has ``stream_id != 0`` XOR 840 ``len(origin) != 0``. 841 """ 842 type = 0xA 843 844 stream_association = _STREAM_ASSOC_EITHER 845 846 def __init__(self, stream_id, origin=b'', field=b'', **kwargs): 847 super().__init__(stream_id, **kwargs) 848 849 if not isinstance(origin, bytes): 850 raise InvalidDataError("AltSvc origin must be bytestring.") 851 if not isinstance(field, bytes): 852 raise InvalidDataError("AltSvc field must be a bytestring.") 853 self.origin = origin 854 self.field = field 855 856 def _body_repr(self): 857 return "origin={}, field={}".format( 858 self.origin, 859 self.field, 860 ) 861 862 def serialize_body(self): 863 origin_len = _STRUCT_H.pack(len(self.origin)) 864 return b''.join([origin_len, self.origin, self.field]) 865 866 def parse_body(self, data): 867 try: 868 origin_len = _STRUCT_H.unpack(data[0:2])[0] 869 self.origin = data[2:2+origin_len].tobytes() 870 871 if len(self.origin) != origin_len: 872 raise InvalidFrameError("Invalid ALTSVC frame body.") 873 874 self.field = data[2+origin_len:].tobytes() 875 except (struct.error, ValueError): 876 raise InvalidFrameError("Invalid ALTSVC frame body.") 877 878 self.body_len = len(data) 879 880 881class ExtensionFrame(Frame): 882 """ 883 ExtensionFrame is used to wrap frames which are not natively interpretable 884 by hyperframe. 885 886 Although certain byte prefixes are ordained by specification to have 887 certain contextual meanings, frames with other prefixes are not prohibited, 888 and may be used to communicate arbitrary meaning between HTTP/2 peers. 889 890 Thus, hyperframe, rather than raising an exception when such a frame is 891 encountered, wraps it in a generic frame to be properly acted upon by 892 upstream consumers which might have additional context on how to use it. 893 894 .. versionadded:: 5.0.0 895 """ 896 897 stream_association = _STREAM_ASSOC_EITHER 898 899 def __init__(self, type, stream_id, flag_byte=0x0, body=b'', **kwargs): 900 super().__init__(stream_id, **kwargs) 901 self.type = type 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 ) 911 912 def parse_flags(self, flag_byte): 913 """ 914 For extension frames, we parse the flags by just storing a flag byte. 915 """ 916 self.flag_byte = flag_byte 917 918 def parse_body(self, data): 919 self.body = data.tobytes() 920 self.body_len = len(data) 921 922 def serialize(self): 923 """ 924 A broad override of the serialize method that ensures that the data 925 comes back out exactly as it came in. This should not be used in most 926 user code: it exists only as a helper method if frames need to be 927 reconstituted. 928 """ 929 # Build the frame header. 930 # First, get the flags. 931 flags = self.flag_byte 932 933 header = _STRUCT_HBBBL.pack( 934 (self.body_len >> 8) & 0xFFFF, # Length spread over top 24 bits 935 self.body_len & 0xFF, 936 self.type, 937 flags, 938 self.stream_id & 0x7FFFFFFF # Stream ID is 32 bits. 939 ) 940 941 return header + self.body 942 943 944def _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 "<hex:" + r + ">" 951 952 953_FRAME_CLASSES = [ 954 DataFrame, 955 HeadersFrame, 956 PriorityFrame, 957 RstStreamFrame, 958 SettingsFrame, 959 PushPromiseFrame, 960 PingFrame, 961 GoAwayFrame, 962 WindowUpdateFrame, 963 ContinuationFrame, 964 AltSvcFrame, 965] 966#: FRAMES maps the type byte for each frame to the class used to represent that 967#: frame. 968FRAMES = {cls.type: cls for cls in _FRAME_CLASSES} 969