def send_left_body(self): while self.remote_window_size and not self.request_body_sended: send_size = min(self.remote_window_size, self.request_body_left, self.max_frame_size) f = DataFrame(self.stream_id) data_start = len(self.request_body) - self.request_body_left f.data = self.request_body[data_start:data_start + send_size] self.remote_window_size -= send_size self.request_body_left -= send_size # If the length of the data is less than MAX_CHUNK, we're probably # at the end of the file. If this is the end of the data, mark it # as END_STREAM. if self.request_body_left == 0: f.flags.add('END_STREAM') # Send the frame and decrement the flow control window. self._send_cb(f) # If no more data is to be sent on this stream, transition our state. if self.request_body_left == 0: self.request_body_sended = True self._close_local()
def socket_handler(listener): sock = listener.accept()[0] e = Encoder() e.huffman_coder = HuffmanEncoder(REQUEST_CODES, REQUEST_CODES_LENGTH) # We get two messages for the connection open and then a HEADERS # frame. receive_preamble(sock) sock.recv(65535) # Now, send the headers for the response. This response has no body. f = build_headers_frame([(':status', '200'), ('content-length', '0')], e) f.stream_id = 1 sock.send(f.serialize()) # Also send a data frame. f = DataFrame(1) f.data = b'have some data' sock.send(f.serialize()) # Now, send a headers frame again, containing trailing headers. f = build_headers_frame([('trailing', 'sure'), (':res', 'no')], e) f.flags.add('END_STREAM') f.stream_id = 1 sock.send(f.serialize()) # Wait for the message from the main thread. recv_event.wait() sock.close()
def test_stream_reading_works(self): out_frames = [] in_frames = [] def send_cb(frame, tolerate_peer_gone=False): out_frames.append(frame) def recv_cb(s): def inner(): s.receive_frame(in_frames.pop(0)) return inner s = Stream(1, send_cb, None, None, None, None, FlowControlManager(65535)) s._recv_cb = recv_cb(s) s.state = STATE_HALF_CLOSED_LOCAL # Provide a data frame to read. f = DataFrame(1) f.data = b'hi there!' f.flags.add('END_STREAM') in_frames.append(f) data = s._read() assert data == b'hi there!' assert len(out_frames) == 0
def test_can_read_multiple_frames_from_streams(self): out_frames = [] in_frames = [] def send_cb(frame, tolerate_peer_gone=False): out_frames.append(frame) def recv_cb(s): def inner(): s.receive_frame(in_frames.pop(0)) return inner s = Stream(1, send_cb, None, None, None, None, FlowControlManager(800)) s._recv_cb = recv_cb(s) s.state = STATE_HALF_CLOSED_LOCAL # Provide two data frames to read. f = DataFrame(1) f.data = b'hi there!' in_frames.append(f) f = DataFrame(1) f.data = b'hi there again!' f.flags.add('END_STREAM') in_frames.append(f) data = s._read() assert data == b'hi there!hi there again!' assert len(out_frames) == 1 assert isinstance(out_frames[0], WindowUpdateFrame) assert out_frames[0].window_increment == len(b'hi there!')
def test_flow_control_manager_update_includes_padding(self): out_frames = [] in_frames = [] def send_cb(frame): out_frames.append(frame) def recv_cb(s): def inner(): s.receive_frame(in_frames.pop(0)) return inner start_window = 65535 s = Stream(1, send_cb, None, None, None, None, FlowControlManager(start_window)) s._recv_cb = recv_cb(s) s.state = STATE_HALF_CLOSED_LOCAL # Provide two data frames to read. f = DataFrame(1) f.data = b'hi there!' f.pad_length = 10 f.flags.add('END_STREAM') in_frames.append(f) data = s._read() assert data == b'hi there!' assert s._in_window_manager.window_size == start_window - f.pad_length - len( data) - 1
def socket_handler(listener): sock = listener.accept()[0] # Do the handshake: conn header, settings, send settings, recv ack. receive_preamble(sock) # Now expect some data. One headers frame and one data frame. data.append(sock.recv(65535)) data.append(sock.recv(65535)) # Respond! h = HeadersFrame(1) h.data = self.get_encoder().encode({ ':status': 200, 'Content-Type': 'not/real', 'Content-Length': 20 }) h.flags.add('END_HEADERS') sock.send(h.serialize()) d = DataFrame(1) d.data = b'1234567890' * 2 d.flags.add('END_STREAM') sock.send(d.serialize()) send_event.set() sock.close()
def send_left_body(self): while self.remote_window_size and not self.request_body_sended: send_size = min(self.remote_window_size, self.request_body_left, self.max_frame_size) f = DataFrame(self.stream_id) data_start = len(self.request_body) - self.request_body_left f.data = self.request_body[data_start:data_start+send_size] self.remote_window_size -= send_size self.request_body_left -= send_size # If the length of the data is less than MAX_CHUNK, we're probably # at the end of the file. If this is the end of the data, mark it # as END_STREAM. if self.request_body_left == 0: f.flags.add('END_STREAM') # Send the frame and decrement the flow control window. self._send_cb(f) # If no more data is to be sent on this stream, transition our state. if self.request_body_left == 0: self.request_body_sended = True self._close_local() self.task.set_state("end send left body")
def test_flow_control_manager_update_includes_padding(self): out_frames = [] in_frames = [] def send_cb(frame): out_frames.append(frame) def recv_cb(s): def inner(): s.receive_frame(in_frames.pop(0)) return inner start_window = 65535 s = Stream(1, send_cb, None, None, None, None, FlowControlManager(start_window)) s._recv_cb = recv_cb(s) s.state = STATE_HALF_CLOSED_LOCAL # Provide two data frames to read. f = DataFrame(1) f.data = b'hi there!' f.pad_length = 10 f.flags.add('END_STREAM') in_frames.append(f) data = s._read() assert data == b'hi there!' assert s._in_window_manager.window_size == start_window - f.pad_length - len(data) - 1
def test_window_increments_appropriately(self): e = Encoder() h = HeadersFrame(1) h.data = e.encode({':status': 200, 'content-type': 'foo/bar'}) h.flags = set(['END_HEADERS']) d = DataFrame(1) d.data = b'hi there sir' d2 = DataFrame(1) d2.data = b'hi there sir again' d2.flags = set(['END_STREAM']) sock = DummySocket() sock.buffer = BytesIO(h.serialize() + d.serialize() + d2.serialize()) c = HTTP20Connection('www.google.com') c._sock = sock c.window_manager.window_size = 1000 c.window_manager.initial_window_size = 1000 c.request('GET', '/') resp = c.get_response() resp.read() queue = list(map(decode_frame, map(memoryview, sock.queue))) assert len(queue) == 3 # one headers frame, two window update frames. assert isinstance(queue[1], WindowUpdateFrame) assert queue[1].window_increment == len(b'hi there sir') assert isinstance(queue[2], WindowUpdateFrame) assert queue[2].window_increment == len(b'hi there sir again')
def socket_handler(listener): sock = listener.accept()[0] # Do the handshake: conn header, settings, send settings, recv ack. receive_preamble(sock) # Now expect some data. One headers frame. data.append(sock.recv(65535)) # Respond! h = HeadersFrame(1) h.data = self.get_encoder().encode({':status': 200, 'Content-Type': 'not/real', 'Content-Length': 20}) h.flags.add('END_HEADERS') sock.send(h.serialize()) d = DataFrame(1) d.data = b'1234567890' * 2 d.flags.add('END_STREAM') sock.send(d.serialize()) send_event.wait() sock.close()
def test_can_read_single_frames_from_streams(self): out_frames = [] in_frames = [] def send_cb(frame, tolerate_peer_gone=False): out_frames.append(frame) def recv_cb(s): def inner(): s.receive_frame(in_frames.pop(0)) return inner s = Stream(1, send_cb, None, None, None, None, FlowControlManager(800)) s._recv_cb = recv_cb(s) s.state = STATE_HALF_CLOSED_LOCAL # Provide two data frames to read. f = DataFrame(1) f.data = b'hi there!' in_frames.append(f) f = DataFrame(1) f.data = b'hi there again!' f.flags.add('END_STREAM') in_frames.append(f) data = s._read_one_frame() assert data == b'hi there!' data = s._read_one_frame() assert data == b'hi there again!' data = s._read_one_frame() assert data is None data = s._read() assert data == b''
def socket_handler(listener): sock = listener.accept()[0] receive_preamble(sock) data.append(sock.recv(65535)) send_event.wait() h = HeadersFrame(1) h.data = self.get_encoder().encode({ ':status': 200, 'Content-Type': 'not/real', 'Content-Length': 14, 'Server': 'socket-level-server' }) h.flags.add('END_HEADERS') sock.send(h.serialize()) d = DataFrame(1) d.data = b'nsaislistening' d.flags.add('END_STREAM') sock.send(d.serialize()) sock.close()
def test_partial_reads_from_streams(self): out_frames = [] in_frames = [] def send_cb(frame, tolerate_peer_gone=False): out_frames.append(frame) def recv_cb(s): def inner(): s.receive_frame(in_frames.pop(0)) return inner s = Stream(1, send_cb, None, None, None, None, FlowControlManager(800)) s._recv_cb = recv_cb(s) s.state = STATE_HALF_CLOSED_LOCAL # Provide two data frames to read. f = DataFrame(1) f.data = b'hi there!' in_frames.append(f) f = DataFrame(1) f.data = b'hi there again!' f.flags.add('END_STREAM') in_frames.append(f) # We'll get the entire first frame. data = s._read(4) assert data == b'hi there!' assert len(out_frames) == 1 # Now we'll get the entire of the second frame. data = s._read(4) assert data == b'hi there again!' assert len(out_frames) == 1 assert s.state == STATE_CLOSED
def socket_handler(listener): sock = listener.accept()[0] receive_preamble(sock) data.append(sock.recv(65535)) send_event.wait() h = HeadersFrame(1) h.data = self.get_encoder().encode( {':status': 200, 'Content-Type': 'not/real', 'Content-Length': 14, 'Server': 'socket-level-server'} ) h.flags.add('END_HEADERS') sock.send(h.serialize()) d = DataFrame(1) d.data = b'nsaislistening' d.flags.add('END_STREAM') sock.send(d.serialize()) sock.close()
def test_connection_doesnt_send_window_update_on_zero_length_data_frame( self): # Prepare a socket with a data frame in it that has no length. sock = DummySocket() sock.buffer = BytesIO(DataFrame(1).serialize()) c = HTTP20Connection('www.google.com') c._sock = sock # We open a request here just to allocate a stream, but we throw away # the frames it sends. c.request('GET', '/') sock.queue = [] # Read the frame. c._recv_cb() # No frame should have been sent on the connection. assert len(sock.queue) == 0
def test_reading_trailers_early_reads_all_data(self): in_frames = [] headers = [('a', 'b'), ('c', 'd'), (':status', '200')] trailers = [('e', 'f'), ('g', 'h')] def recv_cb(s): def inner(): s.receive_frame(in_frames.pop(0)) return inner s = Stream(1, None, None, None, None, FixedDecoder(headers), FlowControlManager(65535)) s._recv_cb = recv_cb(s) s.state = STATE_HALF_CLOSED_LOCAL # Provide the first HEADERS frame. f = HeadersFrame(1) f.data = b'hi there!' f.flags.add('END_HEADERS') in_frames.append(f) # Provide some data. f = DataFrame(1) f.data = b'testdata' in_frames.append(f) # Provide the trailers. f = HeadersFrame(1) f.data = b'hi there again!' f.flags.add('END_STREAM') f.flags.add('END_HEADERS') in_frames.append(f) # Begin by reading the first headers. assert s.getheaders() == HTTPHeaderMap(headers) # Now, replace the dummy decoder to ensure we get a new header block. s._decoder = FixedDecoder(trailers) # Ask for the trailers. This should also read the data frames. assert s.gettrailers() == HTTPHeaderMap(trailers) assert s.data == [b'testdata']
def test_receive_unexpected_stream_id(self): frames = [] def data_callback(frame): frames.append(frame) c = HTTP20Connection('www.google.com') c._send_cb = data_callback f = DataFrame(2) data = memoryview(b"hi there sir") c._consume_frame_payload(f, data) # If we receive an unexpected stream id then we cancel the stream # by sending a reset stream that contains the protocol error code (1) f = frames[0] assert len(frames) == 1 assert f.stream_id == 2 assert isinstance(f, RstStreamFrame) assert f.error_code == 1 # PROTOCOL_ERROR
def add_data_frame(self, stream_id, data, end_stream=False): frame = DataFrame(stream_id) frame.data = data if end_stream: frame.flags.add('END_STREAM') self.frames.append(frame)