|
2 | 2 | from hyper.packages.hyperframe.frame import (
|
3 | 3 | Frame, DataFrame, RstStreamFrame, SettingsFrame,
|
4 | 4 | PushPromiseFrame, PingFrame, WindowUpdateFrame, HeadersFrame,
|
5 |
| - ContinuationFrame, BlockedFrame, |
| 5 | + ContinuationFrame, BlockedFrame, GoAwayFrame, |
6 | 6 | )
|
7 | 7 | from hyper.packages.hpack.hpack_compat import Encoder, Decoder
|
8 | 8 | from hyper.http20.connection import HTTP20Connection
|
|
11 | 11 | )
|
12 | 12 | from hyper.http20.response import HTTP20Response, HTTP20Push
|
13 | 13 | from hyper.http20.exceptions import (
|
14 |
| - HPACKDecodingError, HPACKEncodingError, ProtocolError |
| 14 | + HPACKDecodingError, HPACKEncodingError, ProtocolError, ConnectionError, |
15 | 15 | )
|
16 | 16 | from hyper.http20.window import FlowControlManager
|
17 | 17 | from hyper.http20.util import (
|
|
20 | 20 | from hyper.common.headers import HTTPHeaderMap
|
21 | 21 | from hyper.compat import zlib_compressobj
|
22 | 22 | from hyper.contrib import HTTP20Adapter
|
| 23 | +from hyper.http20.error_code_registry import H2_ERROR_CODE_REGISTRY |
23 | 24 | import errno
|
24 | 25 | import os
|
25 | 26 | import pytest
|
@@ -1183,6 +1184,96 @@ def test_stripping_multiple_connection_headers(self):
|
1183 | 1184 |
|
1184 | 1185 | assert h2_safe_headers(headers) == stripped
|
1185 | 1186 |
|
| 1187 | + def test_goaway_frame_PROTOCOL_ERROR(self): |
| 1188 | + f = GoAwayFrame(0) |
| 1189 | + # Set error code to PROTOCOL_ERROR |
| 1190 | + f.error_code = 1; |
| 1191 | + |
| 1192 | + c = HTTP20Connection('www.google.com') |
| 1193 | + c._sock = DummySocket() |
| 1194 | + |
| 1195 | + # 'Receive' the GOAWAY frame. |
| 1196 | + # Validate that the spec error name and description are used to throw |
| 1197 | + # the connection exception. |
| 1198 | + with pytest.raises(ConnectionError) as conn_err: |
| 1199 | + c.receive_frame(f) |
| 1200 | + |
| 1201 | + err_msg = str(conn_err) |
| 1202 | + assert H2_ERROR_CODE_REGISTRY[f.error_code]['Name'] in err_msg |
| 1203 | + assert H2_ERROR_CODE_REGISTRY[f.error_code]['Description'] in err_msg |
| 1204 | + assert hex(f.error_code) in err_msg |
| 1205 | + |
| 1206 | + def test_goaway_frame_HTTP_1_1_REQUIRED(self): |
| 1207 | + f = GoAwayFrame(0) |
| 1208 | + # Set error code to HTTP_1_1_REQUIRED |
| 1209 | + f.error_code = 13; |
| 1210 | + |
| 1211 | + c = HTTP20Connection('www.google.com') |
| 1212 | + c._sock = DummySocket() |
| 1213 | + |
| 1214 | + # 'Receive' the GOAWAY frame. |
| 1215 | + # Validate that the spec error name and description are used to throw |
| 1216 | + # the connection exception. |
| 1217 | + with pytest.raises(ConnectionError) as conn_err: |
| 1218 | + c.receive_frame(f) |
| 1219 | + |
| 1220 | + err_msg = str(conn_err) |
| 1221 | + assert H2_ERROR_CODE_REGISTRY[f.error_code]['Name'] in err_msg |
| 1222 | + assert H2_ERROR_CODE_REGISTRY[f.error_code]['Description'] in err_msg |
| 1223 | + assert hex(f.error_code) in err_msg |
| 1224 | + |
| 1225 | + def test_goaway_frame_NO_ERROR(self): |
| 1226 | + f = GoAwayFrame(0) |
| 1227 | + # Set error code to NO_ERROR |
| 1228 | + f.error_code = 0; |
| 1229 | + |
| 1230 | + c = HTTP20Connection('www.google.com') |
| 1231 | + c._sock = DummySocket() |
| 1232 | + |
| 1233 | + # 'Receive' the GOAWAY frame. |
| 1234 | + # Test makes sure no exception is raised; error code 0 means we are |
| 1235 | + # dealing with a standard and graceful shutdown. |
| 1236 | + c.receive_frame(f) |
| 1237 | + |
| 1238 | + def test_goaway_frame_additional_data(self): |
| 1239 | + f = GoAwayFrame(0) |
| 1240 | + # Set error code to SETTINGS_TIMEOUT |
| 1241 | + f.error_code = 4; |
| 1242 | + f.additional_data = 'special additional data'; |
| 1243 | + |
| 1244 | + c = HTTP20Connection('www.google.com') |
| 1245 | + c._sock = DummySocket() |
| 1246 | + |
| 1247 | + # 'Receive' the GOAWAY frame. |
| 1248 | + # The connection error contains the extra data if it's available and |
| 1249 | + # the description from the spec if it's not available. This test |
| 1250 | + # validates that the additional data replaces the standard description. |
| 1251 | + with pytest.raises(ConnectionError) as conn_err: |
| 1252 | + c.receive_frame(f) |
| 1253 | + |
| 1254 | + err_msg = str(conn_err) |
| 1255 | + assert H2_ERROR_CODE_REGISTRY[f.error_code]['Name'] in err_msg |
| 1256 | + assert 'special additional data' in err_msg |
| 1257 | + assert hex(f.error_code) in err_msg |
| 1258 | + |
| 1259 | + def test_goaway_frame_invalid_error_code(self): |
| 1260 | + f = GoAwayFrame(0) |
| 1261 | + # Set error code to non existing error |
| 1262 | + f.error_code = 100; |
| 1263 | + f.additional_data = 'data about non existing error code'; |
| 1264 | + |
| 1265 | + c = HTTP20Connection('www.google.com') |
| 1266 | + c._sock = DummySocket() |
| 1267 | + |
| 1268 | + # 'Receive' the GOAWAY frame. |
| 1269 | + # If the error code does not exist in the spec then the additional |
| 1270 | + # data is used instead. |
| 1271 | + with pytest.raises(ConnectionError) as conn_err: |
| 1272 | + c.receive_frame(f) |
| 1273 | + |
| 1274 | + err_msg = str(conn_err) |
| 1275 | + assert 'data about non existing error code' in err_msg |
| 1276 | + assert hex(f.error_code) in err_msg |
1186 | 1277 |
|
1187 | 1278 | # Some utility classes for the tests.
|
1188 | 1279 | class NullEncoder(object):
|
|
0 commit comments