|
1 | 1 | # -*- coding: utf-8 -*-
|
| 2 | +import h2.settings |
| 3 | + |
2 | 4 | from h2.frame_buffer import FrameBuffer
|
3 | 5 | from hyperframe.frame import (
|
4 | 6 | Frame, DataFrame, RstStreamFrame, SettingsFrame, PushPromiseFrame,
|
@@ -583,6 +585,60 @@ def test_closing_incomplete_stream(self, frame_buffer):
|
583 | 585 | assert isinstance(f, RstStreamFrame)
|
584 | 586 | assert 1 not in c.streams
|
585 | 587 |
|
| 588 | + def test_incrementing_window_after_close(self): |
| 589 | + """ |
| 590 | + Hyper does not attempt to increment the flow control window once the |
| 591 | + stream is closed. |
| 592 | + """ |
| 593 | + # For this test, we want to send a response that has three frames at |
| 594 | + # the default max frame size (16,384 bytes). That will, on the third |
| 595 | + # frame, trigger the processing to increment the flow control window, |
| 596 | + # which should then not happen. |
| 597 | + f = SettingsFrame(0, settings={h2.settings.INITIAL_WINDOW_SIZE: 100}) |
| 598 | + |
| 599 | + c = HTTP20Connection('www.google.com') |
| 600 | + c._sock = DummySocket() |
| 601 | + c._sock.buffer = BytesIO(f.serialize()) |
| 602 | + |
| 603 | + # Open stream 1. |
| 604 | + c.request('GET', '/') |
| 605 | + |
| 606 | + # Check what data we've sent right now. |
| 607 | + originally_sent_data = c._sock.queue[:] |
| 608 | + |
| 609 | + # Swap out the buffer to get a GoAway frame. |
| 610 | + length = 16384 |
| 611 | + total_length = (3 * 16384) + len(b'some more data') |
| 612 | + e = Encoder() |
| 613 | + h1 = HeadersFrame(1) |
| 614 | + h1.data = e.encode( |
| 615 | + [(':status', 200), ('content-length', '%d' % total_length)] |
| 616 | + ) |
| 617 | + h1.flags |= set(['END_HEADERS']) |
| 618 | + |
| 619 | + d1 = DataFrame(1) |
| 620 | + d1.data = b'\x00' * length |
| 621 | + d2 = d1 |
| 622 | + d3 = d1 |
| 623 | + d4 = DataFrame(1) |
| 624 | + d4.data = b'some more data' |
| 625 | + d4.flags |= set(['END_STREAM']) |
| 626 | + |
| 627 | + buffer = BytesIO( |
| 628 | + b''.join(f.serialize() for f in [h1, d1, d2, d3, d4]) |
| 629 | + ) |
| 630 | + c._sock.buffer = buffer |
| 631 | + |
| 632 | + # Read the response |
| 633 | + resp = c.get_response(stream_id=1) |
| 634 | + assert resp.status == 200 |
| 635 | + assert resp.read() == b''.join( |
| 636 | + [b'\x00' * (3 * length), b'some more data'] |
| 637 | + ) |
| 638 | + |
| 639 | + # We should have sent only one extra frame |
| 640 | + assert len(originally_sent_data) + 1 == len(c._sock.queue) |
| 641 | + |
586 | 642 |
|
587 | 643 | class TestServerPush(object):
|
588 | 644 | def setup_method(self, method):
|
@@ -1184,6 +1240,7 @@ def test_resetting_streams_after_close(self):
|
1184 | 1240 | c._single_read()
|
1185 | 1241 |
|
1186 | 1242 |
|
| 1243 | + |
1187 | 1244 | # Some utility classes for the tests.
|
1188 | 1245 | class NullEncoder(object):
|
1189 | 1246 | @staticmethod
|
|
0 commit comments