def __init__(self, logger, ip_manager, config, ssl_sock, close_cb, retry_task_cb, idle_cb): super(Http2Worker, self).__init__(logger, ip_manager, config, ssl_sock, close_cb, retry_task_cb, idle_cb) self.network_buffer_size = 128 * 1024 # Google http/2 time out is 4 mins. self.ssl_sock.settimeout(240) self._sock = BufferedSocket(ssl_sock, self.network_buffer_size) self.next_stream_id = 1 self.streams = {} self.last_ping_time = time.time() self.last_active_time = self.ssl_sock.create_time - 1 self.continue_timeout = 0 # count ping not ACK # increase when send ping # decrease when recv ping ack # if this in not 0, don't accept request. self.ping_on_way = 0 self.accept_task = False # request_lock self.request_lock = threading.Lock() # all send frame must put to this queue # then send by send_loop # every frame put to this queue must allowed by stream window and connection window # any data frame blocked by connection window should put to self.blocked_send_frames self.send_queue = Queue.Queue() # keep blocked data frame in this buffer # which is allowed by stream window but blocked by connection window. # They will be sent when connection window open self.blocked_send_frames = [] # Values for the settings used on an HTTP/2 connection. # will send to remote using Setting Frame self.local_settings = { SettingsFrame.INITIAL_WINDOW_SIZE: 16 * 1024 * 1024, SettingsFrame.SETTINGS_MAX_FRAME_SIZE: 256 * 1024 } self.local_connection_initial_windows = 32 * 1024 * 1024 self.local_window_manager = FlowControlManager(self.local_connection_initial_windows) # changed by server, with SettingFrame self.remote_settings = { SettingsFrame.INITIAL_WINDOW_SIZE: DEFAULT_WINDOW_SIZE, SettingsFrame.SETTINGS_MAX_FRAME_SIZE: DEFAULT_MAX_FRAME, SettingsFrame.MAX_CONCURRENT_STREAMS: 100 } #self.remote_window_size = DEFAULT_WINDOW_SIZE self.remote_window_size = 32 * 1024 * 1024 # send Setting frame before accept task. self._send_preamble() threading.Thread(target=self.send_loop).start() threading.Thread(target=self.recv_loop).start()
def test_socket_error_on_readline(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) with pytest.raises(ConnectionResetError): b.readline()
def test_can_create_buffered_sockets(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) assert b is not None assert b._buffer_size == 1000
def test_can_send_on_buffered_socket(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) b.send(b'test data') assert len(s.outbound_packets) == 1 assert s.outbound_packets[0] == b'test data'
def test_receive_single_packet(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) s.inbound_packets.append(b'test data') d = b.recv(100).tobytes() assert d == b'test data'
def test_oversized_read(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) s.inbound_packets.append(b'a' * 600) d = b.recv(1200).tobytes() assert d == b'a' * 600
def test_socket_fill_resizes_if_needed(self): s = DummySocket() b = BufferedSocket(s) s.inbound_packets = [b'Here'] b._index = 1000 assert not len(b.buffer) b.fill() assert len(b.buffer) == 4 assert b._index == 0
def test_socket_readline_too_long(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) b._buffer_view[0:b._buffer_size] = b'0' * b._buffer_size b._bytes_in_buffer = b._buffer_size with pytest.raises(LineTooLongError): b.readline()
def test_advancing_sockets(self): s = DummySocket() b = BufferedSocket(s) b._buffer_view[0:5] = b'abcde' b._bytes_in_buffer += 5 assert len(b.buffer) == 5 b.advance_buffer(3) assert len(b.buffer) == 2 assert b.buffer.tobytes() == b'de'
def test_receive_small_packets(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) s.inbound_packets = [b'Here', b'begins', b'the', b'test', b'data'] d = b'' for _ in range(5): d += b.recv(100).tobytes() assert d == b'Herebeginsthetestdata'
def test_filling_the_buffer(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) s.inbound_packets = [ b'a' * 1000, b'a' * 800, ] d = b'' for _ in range(2): d += b.recv(900).tobytes() assert d == (b'a' * 1800)
def test_receive_multiple_packets_at_once(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) s.inbound_packets = [ b'Here', b'begins', b'the', b'test', b'data', b'!' ] s.read_count = 3 d = b'' for _ in range(22): d += b.recv(1).tobytes() assert d == b'Herebeginsthetestdata!'
def test_socket_fill_basic(self): s = DummySocket() b = BufferedSocket(s) s.inbound_packets = [b'Here', b'begins', b'the'] assert not len(b.buffer) b.fill() assert len(b.buffer) == 4 b.fill() assert len(b.buffer) == 10 b.fill() assert len(b.buffer) == 13
def test_readline_from_buffer(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) one = b'hi there\r\n' two = b'this is another line\r\n' three = b'\r\n' combined = b''.join([one, two, three]) b._buffer_view[0:len(combined)] = combined b._bytes_in_buffer += len(combined) assert b.readline().tobytes() == one assert b.readline().tobytes() == two assert b.readline().tobytes() == three
def test_readline_from_socket(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) one = b'hi there\r\n' two = b'this is another line\r\n' three = b'\r\n' combined = b''.join([one, two, three]) for i in range(0, len(combined), 5): s.inbound_packets.append(combined[i:i + 5]) assert b.readline().tobytes() == one assert b.readline().tobytes() == two assert b.readline().tobytes() == three
def connect(self): """ Connect to the server specified when the object was created. This is a no-op if we're already connected. Concurrency ----------- This method is thread-safe. It may be called from multiple threads, and is a noop for all threads apart from the first. :returns: Nothing. """ #print("connecting to ATS") with self._lock: if self._sock is not None: return sni = self.host if not self.proxy_host: host = self.host port = self.port else: host = self.proxy_host port = self.proxy_port sock = socket.create_connection((host, port)) if self.secure: #assert not self.proxy_host, "Proxy with HTTPS not supported." sock, proto = wrap_socket(sock, sni, self.ssl_context, force_proto=self.force_proto) else: proto = H2C_PROTOCOL log.debug("Selected NPN protocol: %s", proto) assert proto in H2_NPN_PROTOCOLS or proto == H2C_PROTOCOL self._sock = BufferedSocket(sock, self.network_buffer_size) self._send_preamble()
def test_readline_both(self, monkeypatch): monkeypatch.setattr(hyper.common.bufsocket.select, 'select', dummy_select) s = DummySocket() b = BufferedSocket(s) one = b'hi there\r\n' two = b'this is another line\r\n' three = b'\r\n' combined = b''.join([one, two, three]) split_index = int(len(combined) / 2) b._buffer_view[0:split_index] = combined[0:split_index] b._bytes_in_buffer += split_index for i in range(split_index, len(combined), 5): s.inbound_packets.append(combined[i:i + 5]) assert b.readline().tobytes() == one assert b.readline().tobytes() == two assert b.readline().tobytes() == three
def test_socket_fill_raises_connection_errors(self): s = DummySocket() b = BufferedSocket(s) with pytest.raises(ConnectionResetError): b.fill()