def socket_handler(listener): sock = listener.accept()[0] receive_preamble(sock) data.append(sock.recv(65535)) send_event.wait(5) h = HeadersFrame(1) h.data = self.get_encoder().encode( [ (':status', 200), ('content-type', 'not/real'), ('content-length', 12), ('server', 'socket-level-server') ] ) h.flags.add('END_HEADERS') sock.send(h.serialize()) d = DataFrame(1) d.data = b'thisisaproxy' d.flags.add('END_STREAM') sock.send(d.serialize()) sock.close()
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(5) sock.close()
def test_data_frame_zero_length_padding_calculates_flow_control_len(self): f = DataFrame(1) f.flags = set(['PADDED']) f.data = b'testdata' f.pad_length = 0 assert f.flow_controlled_length == len(b'testdata') + 1
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 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()) sock.close()
def test_data_frame_serializes_properly(self): f = DataFrame(1) f.flags = set(['END_STREAM']) f.data = b'testdata' s = f.serialize() assert s == self.payload
def test_data_frame_with_padding_calculates_flow_control_len(self): f = DataFrame(1) f.flags = set(['PADDED']) f.data = b'testdata' f.pad_length = 10 assert f.flow_controlled_length == 19
def test_data_frame_serializes_properly(self, data): f = DataFrame(1) f.flags = set(['END_STREAM']) f.data = data s = f.serialize() assert s == self.payload
def socket_handler(listener): sock = listener.accept()[0] e = Encoder() # 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. f = build_headers_frame( [(':status', '200'), ('content-length', '14')], 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([ ('trialing', 'no'), ('trailing', 'sure')], e) f.flags.add('END_STREAM') f.stream_id = 1 sock.send(f.serialize()) # Wait for the message from the main thread. recv_event.set() sock.close()
def test_data_frame_with_no_length_parses(self): # Fixes issue with empty data frames raising InvalidPaddingError. f = DataFrame(1) f.data = b'' data = f.serialize() new_frame = decode_frame(data) assert new_frame.data == b''
def test_data_frame_with_padding_serializes_properly(self): f = DataFrame(1) f.flags = set(['END_STREAM', 'PADDED']) f.data = b'testdata' f.pad_length = 10 s = f.serialize() assert s == self.payload_with_padding
def build_data_frame(self, data, flags=None, stream_id=1): """ Builds a single data frame out of a chunk of data. """ flags = set(flags) if flags is not None else set() f = DataFrame(stream_id) f.data = data f.flags = flags return f
def socket_handler(listener): sock = listener.accept()[0] # 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 a body. f = build_headers_frame([(':status', '200')]) f.stream_id = 1 sock.send(f.serialize()) # Send the first two chunks. f = DataFrame(1) f.data = b'hello' sock.sendall(f.serialize()) f = DataFrame(1) f.data = b'there' sock.sendall(f.serialize()) # Now, delay a bit. We want to wait a half a second before we send # the next frame. wait_event.wait(5) time.sleep(0.5) f = DataFrame(1) f.data = b'world' f.flags.add('END_STREAM') sock.sendall(f.serialize()) # Wait for the message from the main thread. recv_event.set() sock.close()
def test_connection_window_increments_appropriately(self, frame_buffer): 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() frame_buffer.add_data(b''.join(sock.queue)) queue = list(frame_buffer) 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 test_body_length_behaves_correctly(self): f = DataFrame(1) f.data = b'\x01' * 300 # Initially the body length is zero. For now this is incidental, but # I'm going to test it to ensure that the behaviour is codified. We # should change this test if we change that. assert f.body_len == 0 data = f.serialize() assert f.body_len == 300
def test_body_length_behaves_correctly(self): f = DataFrame(1) f.data = b'\x01' * 300 # Initially the body length is zero. For now this is incidental, but # I'm going to test it to ensure that the behaviour is codified. We # should change this test if we change that. assert f.body_len == 0 f.serialize() assert f.body_len == 300
def test_incrementing_window_after_close(self): """ Hyper does not attempt to increment the flow control window once the stream is closed. """ # For this test, we want to send a response that has three frames at # the default max frame size (16,384 bytes). That will, on the third # frame, trigger the processing to increment the flow control window, # which should then not happen. f = SettingsFrame(0, settings={h2.settings.INITIAL_WINDOW_SIZE: 100}) c = HTTP20Connection('www.google.com') c._sock = DummySocket() c._sock.buffer = BytesIO(f.serialize()) # Open stream 1. c.request('GET', '/') # Check what data we've sent right now. originally_sent_data = c._sock.queue[:] # Swap out the buffer to get a GoAway frame. length = 16384 total_length = (3 * 16384) + len(b'some more data') e = Encoder() h1 = HeadersFrame(1) h1.data = e.encode( [(':status', 200), ('content-length', '%d' % total_length)] ) h1.flags |= set(['END_HEADERS']) d1 = DataFrame(1) d1.data = b'\x00' * length d2 = d1 d3 = d1 d4 = DataFrame(1) d4.data = b'some more data' d4.flags |= set(['END_STREAM']) buffer = BytesIO( b''.join(f.serialize() for f in [h1, d1, d2, d3, d4]) ) c._sock.buffer = buffer # Read the response resp = c.get_response(stream_id=1) assert resp.status == 200 assert resp.read() == b''.join( [b'\x00' * (3 * length), b'some more data'] ) # We should have sent only one extra frame assert len(originally_sent_data) + 1 == len(c._sock.queue)
def write_raw_data_frame(self, data, stream_id=None, end_stream=False): """This bypasses state checking and such, and sends a data frame regardless""" if not stream_id: stream_id = self.request.h2_stream_id frame = DataFrame(stream_id, data=data) if end_stream: self.stream_ended = True frame.flags.add('END_STREAM') data = frame.serialize() self.write_raw(data)
def build_data_frame(self, data, flags=None, stream_id=1, padding_len=0): """ Builds a single data frame out of a chunk of data. """ flags = set(flags) if flags is not None else set() f = DataFrame(stream_id) f.data = data f.flags = flags if padding_len: flags.add('PADDED') f.pad_length = padding_len return f
def test_long_data_frame(self): f = DataFrame(1) # Use more than 256 bytes of data to force setting higher bits. f.data = b'\x01' * 300 data = f.serialize() # The top three bytes should be numerically equal to 300. That means # they should read 00 01 2C. # The weird double index trick is to ensure this test behaves equally # on Python 2 and Python 3. assert data[0] == b'\x00'[0] assert data[1] == b'\x01'[0] assert data[2] == b'\x2C'[0]
def end_stream(self): """ End a stream without sending data. """ self.state_machine.process_input(StreamInputs.SEND_END_STREAM) df = DataFrame(self.stream_id) df.flags.add('END_STREAM') return [df]
def send_data(self, data, end_stream=False): """ Prepare some data frames. Optionally end the stream. .. warning:: Does not perform flow control checks. """ self.state_machine.process_input(StreamInputs.SEND_DATA) df = DataFrame(self.stream_id) df.data = data if end_stream: self.state_machine.process_input(StreamInputs.SEND_END_STREAM) df.flags.add('END_STREAM') self.outbound_flow_control_window -= len(data) assert self.outbound_flow_control_window >= 0 return [df]
def create_socket(status_code, data, headers): # test helper method encoder = Encoder() h1 = HeadersFrame(1) h1.data = encoder.encode([(':status', status_code), ('content-length', len(data))] + headers) h1.flags |= set(['END_HEADERS']) d1 = DataFrame(1) d1.data = data d2 = DataFrame(1) d2.flags |= set(['END_STREAM']) content = b''.join(f.serialize() for f in [h1, d1, d2]) buffer = BytesIO(content) return DummySocket(buffer)
def socket_handler(listener): sock = listener.accept()[0] # First read the HTTP/1.1 request data = b'' while not data.endswith(b'\r\n\r\n'): data += sock.recv(65535) # Check it's an upgrade. assert b'upgrade: h2c\r\n' in data # Send back an upgrade message. data = ( b'HTTP/1.1 101 Switching Protocols\r\n' b'Server: some-server\r\n' b'Connection: upgrade\r\n' b'Upgrade: h2c\r\n' b'\r\n' ) sock.sendall(data) # We get a message for connection open, specifically the preamble. receive_preamble(sock) # Now, send the headers for the response. This response has a body. f = build_headers_frame([(':status', '200')]) f.stream_id = 1 sock.sendall(f.serialize()) # Send the first two chunks. f = DataFrame(1) f.data = b'hello' sock.sendall(f.serialize()) f = DataFrame(1) f.data = b'there' sock.sendall(f.serialize()) # Now, delay a bit. We want to wait a half a second before we send # the next frame. wait_event.wait(5) time.sleep(0.5) f = DataFrame(1) f.data = b'world' f.flags.add('END_STREAM') sock.sendall(f.serialize()) # Wait for the message from the main thread. recv_event.set() sock.close()
def socket_handler(listener): sock = listener.accept()[0] e = Encoder() # 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. f = build_headers_frame([(':status', '200'), ('content-length', '14')], 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([('trialing', 'no'), ('trailing', 'sure')], e) f.flags.add('END_STREAM') f.stream_id = 1 sock.send(f.serialize()) # Wait for the message from the main thread. recv_event.set() sock.close()
def send_data(self, data, end_stream=False, pad_length=None): """ Prepare some data frames. Optionally end the stream. .. warning:: Does not perform flow control checks. """ self.state_machine.process_input(StreamInputs.SEND_DATA) df = DataFrame(self.stream_id) df.data = data if end_stream: self.state_machine.process_input(StreamInputs.SEND_END_STREAM) df.flags.add('END_STREAM') if pad_length is not None: df.flags.add('PADDED') df.pad_length = pad_length # Subtract flow_controlled_length to account for possible padding self.outbound_flow_control_window -= df.flow_controlled_length assert self.outbound_flow_control_window >= 0 return [df]
def write_raw_data_frame(self, data, stream_id=None, end_stream=False): """ Ignores the statemachine of the stream and sends a DATA frame regardless. Unlike `write_data`, this does not check to see if a stream is in the correct state to have DATA frames sent through to it. It will build a DATA frame and send it without using the H2 Connection object. It will not perform any flow control checks. :param data: The data to be sent in the frame :param stream_id: Id of stream to send frame on. Will use the request stream ID if None :param end_stream: Set to True to add END_STREAM flag to frame """ if not stream_id: stream_id = self.request.h2_stream_id frame = DataFrame(stream_id, data=data) if end_stream: self.stream_ended = True frame.flags.add('END_STREAM') data = frame.serialize() self.write_raw(data)
def socket_handler(listener): sock = listener.accept()[0] receive_preamble(sock) data.append(sock.recv(65535)) send_event.wait(5) h = HeadersFrame(1) h.data = self.get_encoder().encode([(':status', 200), ('content-type', 'not/real'), ('content-length', 12), ('server', 'socket-level-server')]) h.flags.add('END_HEADERS') sock.send(h.serialize()) d = DataFrame(1) d.data = b'thisisaproxy' d.flags.add('END_STREAM') sock.send(d.serialize()) sock.close()
def test_connection_no_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_data_frame_without_padding_calculates_flow_control_len(self): f = DataFrame(1) f.data = b'testdata' assert f.flow_controlled_length == 8
def socket_handler(listener): sock = listener.accept()[0] # First read the HTTP/1.1 request data = b'' while not data.endswith(b'\r\n\r\n'): data += sock.recv(65535) # Check it's an upgrade. assert b'upgrade: h2c\r\n' in data # Send back an upgrade message. data = (b'HTTP/1.1 101 Switching Protocols\r\n' b'Server: some-server\r\n' b'Connection: upgrade\r\n' b'Upgrade: h2c\r\n' b'\r\n') sock.sendall(data) # We get a message for connection open, specifically the preamble. receive_preamble(sock) # Now, send the headers for the response. This response has a body. f = build_headers_frame([(':status', '200')]) f.stream_id = 1 sock.sendall(f.serialize()) # Send the first two chunks. f = DataFrame(1) f.data = b'hello' sock.sendall(f.serialize()) f = DataFrame(1) f.data = b'there' sock.sendall(f.serialize()) # Now, delay a bit. We want to wait a half a second before we send # the next frame. wait_event.wait(5) time.sleep(0.5) f = DataFrame(1) f.data = b'world' f.flags.add('END_STREAM') sock.sendall(f.serialize()) # Wait for the message from the main thread. recv_event.set() sock.close()
def test_repr(self): f = DataFrame(1, b"testdata") assert repr(f).endswith("<hex:7465737464617461>")
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)
def test_data_frame_comes_on_a_stream(self): with pytest.raises(ValueError): DataFrame(0)
def test_data_frame_comes_on_a_stream(self): with pytest.raises(InvalidDataError): DataFrame(0)
def test_data_frame_has_correct_flags(self): f = DataFrame(1) flags = f.parse_flags(0xFF) assert flags == set(['END_STREAM', 'PADDED'])
def test_data_frame_has_correct_flags(self): f = DataFrame(1) flags = f.parse_flags(0xFF) assert flags == set([ 'END_STREAM', 'PADDED' ])