10
10
import threading
11
11
import hyper
12
12
from hyper import HTTP20Connection
13
- from hyper .http20 .frame import Frame , SettingsFrame
13
+ from hyper .http20 .frame import (
14
+ Frame , SettingsFrame , WindowUpdateFrame , DataFrame
15
+ )
14
16
from server import SocketLevelTest
15
17
16
18
# Turn off certificate verification for the tests.
17
19
hyper .http20 .tls ._context = hyper .http20 .tls ._init_context ()
18
20
hyper .http20 .tls ._context .verify_mode = ssl .CERT_NONE
19
21
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
+
20
28
class TestHyperIntegration (SocketLevelTest ):
21
29
def test_connection_string (self ):
22
30
self .set_up ()
@@ -36,6 +44,10 @@ def socket_handler(listener):
36
44
data .append (first )
37
45
data .append (second )
38
46
47
+ # We need to send back a SettingsFrame.
48
+ f = SettingsFrame (0 )
49
+ sock .send (f .serialize ())
50
+
39
51
send_event .set ()
40
52
sock .close ()
41
53
@@ -66,6 +78,10 @@ def socket_handler(listener):
66
78
data .append (first )
67
79
data .append (second )
68
80
81
+ # We need to send back a SettingsFrame.
82
+ f = SettingsFrame (0 )
83
+ sock .send (f .serialize ())
84
+
69
85
send_event .set ()
70
86
sock .close ()
71
87
@@ -76,11 +92,76 @@ def socket_handler(listener):
76
92
77
93
# Get the second chunk of data and decode it into a frame.
78
94
data = data [1 ]
79
- f , length = Frame .parse_frame_header (data [:8 ])
80
- f .parse_body (data [8 :])
95
+ f = decode_frame (data )
81
96
82
97
assert isinstance (f , SettingsFrame )
83
98
assert f .stream_id == 0
84
99
assert f .settings == {SettingsFrame .ENABLE_PUSH : 0 }
85
100
86
101
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