12
12
from ..packages .hyperframe .frame import (
13
13
FRAMES , DataFrame , HeadersFrame , PushPromiseFrame , RstStreamFrame ,
14
14
SettingsFrame , Frame , WindowUpdateFrame , GoAwayFrame , PingFrame ,
15
- BlockedFrame
15
+ BlockedFrame , FRAME_MAX_LEN
16
16
)
17
17
from ..packages .hpack .hpack_compat import Encoder , Decoder
18
18
from .stream import Stream
@@ -123,6 +123,7 @@ def __init_state(self):
123
123
# Values for the settings used on an HTTP/2 connection.
124
124
self ._settings = {
125
125
SettingsFrame .INITIAL_WINDOW_SIZE : 65535 ,
126
+ SettingsFrame .SETTINGS_MAX_FRAME_SIZE : FRAME_MAX_LEN ,
126
127
}
127
128
128
129
# The socket used to send data.
@@ -469,12 +470,7 @@ def _close_stream(self, stream_id, error_code=None):
469
470
"""
470
471
Called by a stream when it would like to be 'closed'.
471
472
"""
472
- if error_code is not None :
473
- f = RstStreamFrame (stream_id )
474
- f .error_code = error_code
475
- self ._send_cb (f )
476
-
477
- del self .streams [stream_id ]
473
+ self ._send_rst_frame (stream_id , error_code )
478
474
479
475
def _send_cb (self , frame , tolerate_peer_gone = False ):
480
476
"""
@@ -535,6 +531,16 @@ def _consume_single_frame(self):
535
531
# Parse the header. We can use the returned memoryview directly here.
536
532
frame , length = Frame .parse_frame_header (header )
537
533
534
+ frame_size = self ._settings [SettingsFrame .SETTINGS_MAX_FRAME_SIZE ]
535
+ if (length > frame_size ):
536
+ self ._send_rst_frame (frame .stream_id , 6 ) # 6 = FRAME_SIZE_ERROR
537
+ log .warning (
538
+ "Frame size exceeded on stream %d (received: %d, max: %d)" ,
539
+ frame .stream_id ,
540
+ length ,
541
+ frame_size
542
+ )
543
+
538
544
# Read the remaining data from the socket.
539
545
data = self ._recv_payload (length )
540
546
self ._consume_frame_payload (frame , data )
@@ -595,9 +601,7 @@ def _consume_frame_payload(self, frame, data):
595
601
# the ENABLE_PUSH setting is 0, but the spec leaves the client
596
602
# action undefined when they do it anyway. So we just refuse
597
603
# the stream and go about our business.
598
- f = RstStreamFrame (frame .promised_stream_id )
599
- f .error_code = 7 # REFUSED_STREAM
600
- self ._send_cb (f )
604
+ self ._send_rst_frame (frame .promised_stream_id , 7 )
601
605
602
606
# Work out to whom this frame should go.
603
607
if frame .stream_id != 0 :
@@ -606,9 +610,7 @@ def _consume_frame_payload(self, frame, data):
606
610
except KeyError :
607
611
# If we receive an unexpected stream identifier then we
608
612
# cancel the stream with an error of type PROTOCOL_ERROR
609
- f = RstStreamFrame (frame .stream_id )
610
- f .error_code = 1 # PROTOCOL_ERROR
611
- self ._send_cb (f )
613
+ self ._send_rst_frame (frame .stream_id , 1 )
612
614
log .warning (
613
615
"Unexpected stream identifier %d" % (frame .stream_id )
614
616
)
@@ -637,6 +639,21 @@ def _recv_cb(self):
637
639
except ConnectionResetError :
638
640
break
639
641
642
+ def _send_rst_frame (self , stream_id , error_code ):
643
+ """
644
+ Send reset stream frame with error code and remove stream from map.
645
+ """
646
+ if error_code is not None :
647
+ f = RstStreamFrame (stream_id )
648
+ f .error_code = error_code
649
+ self ._send_cb (f )
650
+
651
+ try :
652
+ del self .streams [stream_id ]
653
+ except KeyError as e : # pragma: no cover
654
+ log .warn (
655
+ "Stream with id %d does not exist: %s" ,
656
+ stream_id , e )
640
657
641
658
# The following two methods are the implementation of the context manager
642
659
# protocol.
0 commit comments