1010import threading
1111import hyper
1212from hyper import HTTP20Connection
13- from hyper .http20 .frame import Frame , SettingsFrame
13+ from hyper .http20 .frame import (
14+ Frame , SettingsFrame , WindowUpdateFrame , DataFrame
15+ )
1416from server import SocketLevelTest
1517
1618# Turn off certificate verification for the tests.
1719hyper .http20 .tls ._context = hyper .http20 .tls ._init_context ()
1820hyper .http20 .tls ._context .verify_mode = ssl .CERT_NONE
1921
22+ def decode_frame (frame_data ):
23+ f , length = Frame .parse_frame_header (frame_data [:8 ])
24+ f .parse_body (frame_data [8 :8 + length ])
25+ assert 8 + length == len (frame_data )
26+ return f
27+
2028class TestHyperIntegration (SocketLevelTest ):
2129 def test_connection_string (self ):
2230 self .set_up ()
@@ -36,6 +44,10 @@ def socket_handler(listener):
3644 data .append (first )
3745 data .append (second )
3846
47+ # We need to send back a SettingsFrame.
48+ f = SettingsFrame (0 )
49+ sock .send (f .serialize ())
50+
3951 send_event .set ()
4052 sock .close ()
4153
@@ -66,6 +78,10 @@ def socket_handler(listener):
6678 data .append (first )
6779 data .append (second )
6880
81+ # We need to send back a SettingsFrame.
82+ f = SettingsFrame (0 )
83+ sock .send (f .serialize ())
84+
6985 send_event .set ()
7086 sock .close ()
7187
@@ -76,11 +92,76 @@ def socket_handler(listener):
7692
7793 # Get the second chunk of data and decode it into a frame.
7894 data = data [1 ]
79- f , length = Frame .parse_frame_header (data [:8 ])
80- f .parse_body (data [8 :])
95+ f = decode_frame (data )
8196
8297 assert isinstance (f , SettingsFrame )
8398 assert f .stream_id == 0
8499 assert f .settings == {SettingsFrame .ENABLE_PUSH : 0 }
85100
86101 self .tear_down ()
102+
103+ def test_stream_level_window_management (self ):
104+ self .set_up ()
105+ data = []
106+ send_event = threading .Event ()
107+
108+ def socket_handler (listener ):
109+ sock = listener .accept ()[0 ]
110+
111+ # Dispose of the first two packets.
112+ sock .recv (65535 )
113+ sock .recv (65535 )
114+
115+ # Send a Settings frame that reduces the flow-control window to
116+ # 64 bytes.
117+ f = SettingsFrame (0 )
118+ f .settings [SettingsFrame .INITIAL_WINDOW_SIZE ] = 64
119+ sock .send (f .serialize ())
120+
121+ # Grab three frames, the settings ACK, the initial headers frame,
122+ # and the first data frame.
123+ for x in range (0 , 3 ):
124+ data .append (sock .recv (65535 ))
125+
126+ # Send a WindowUpdate giving more window room to the stream.
127+ f = WindowUpdateFrame (1 )
128+ f .window_increment = 64
129+ sock .send (f .serialize ())
130+
131+ # Reeive the remaining frame.
132+ data .append (sock .recv (65535 ))
133+ send_event .set ()
134+
135+ # We're done.
136+ sock .close ()
137+
138+ self ._start_server (socket_handler )
139+ conn = HTTP20Connection (self .host , self .port )
140+
141+ conn .putrequest ('GET' , '/' )
142+ conn .endheaders ()
143+
144+ # Send the first data chunk. This is 32 bytes.
145+ sd = b'a' * 32
146+ conn .send (sd )
147+
148+ # Send the second one. This should block until the WindowUpdate comes
149+ # in.
150+ sd = sd * 2
151+ conn .send (sd , final = True )
152+ assert send_event .wait (0.3 )
153+
154+ # Decode the frames.
155+ print (data )
156+ frames = [decode_frame (d ) for d in data ]
157+
158+ # We care about the last two. The first should be a data frame
159+ # containing 32 bytes.
160+ assert isinstance (frames [- 2 ], DataFrame )
161+ assert len (frames [- 2 ].data ) == 32
162+
163+ # The second should be a data frame containing 64 bytes.
164+ assert isinstance (frames [- 1 ], DataFrame )
165+ assert len (frames [- 1 ].data ) == 64
166+
167+ self .tear_down ()
0 commit comments