Save old socket for IPC
At least on Windows with Qt 5.8, we get readyRead notifications *after* disconnect...
This commit is contained in:
parent
57223b78f3
commit
a55d1b1ee8
@ -27,7 +27,7 @@ import getpass
|
|||||||
import binascii
|
import binascii
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, Qt, QTimer
|
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, Qt
|
||||||
from PyQt5.QtNetwork import QLocalSocket, QLocalServer, QAbstractSocket
|
from PyQt5.QtNetwork import QLocalSocket, QLocalServer, QAbstractSocket
|
||||||
|
|
||||||
import qutebrowser
|
import qutebrowser
|
||||||
@ -182,6 +182,7 @@ class IPCServer(QObject):
|
|||||||
self._server.newConnection.connect(self.handle_connection)
|
self._server.newConnection.connect(self.handle_connection)
|
||||||
|
|
||||||
self._socket = None
|
self._socket = None
|
||||||
|
self._old_socket = None
|
||||||
self._socketopts_ok = os.name == 'nt'
|
self._socketopts_ok = os.name == 'nt'
|
||||||
if self._socketopts_ok: # pragma: no cover
|
if self._socketopts_ok: # pragma: no cover
|
||||||
# If we use setSocketOptions on Unix with Qt < 5.4, we get a
|
# If we use setSocketOptions on Unix with Qt < 5.4, we get a
|
||||||
@ -278,15 +279,8 @@ class IPCServer(QObject):
|
|||||||
log.ipc.debug("Client disconnected from socket 0x{:x}.".format(
|
log.ipc.debug("Client disconnected from socket 0x{:x}.".format(
|
||||||
id(self._socket)))
|
id(self._socket)))
|
||||||
self._timer.stop()
|
self._timer.stop()
|
||||||
if self._socket is None:
|
self._old_socket = self._socket
|
||||||
log.ipc.debug("In on_disconnected with None socket!")
|
self._socket = None
|
||||||
else:
|
|
||||||
# For some reason Qt can still get delayed canReadNotifications
|
|
||||||
# internally, so if we call deleteLater() right away and then call
|
|
||||||
# QApplication::processEvents() somewhere in the code, we can get a
|
|
||||||
# segfault.
|
|
||||||
QTimer.singleShot(500, self._socket.deleteLater)
|
|
||||||
self._socket = None
|
|
||||||
# Maybe another connection is waiting.
|
# Maybe another connection is waiting.
|
||||||
self.handle_connection()
|
self.handle_connection()
|
||||||
|
|
||||||
@ -349,17 +343,23 @@ class IPCServer(QObject):
|
|||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def on_ready_read(self):
|
def on_ready_read(self):
|
||||||
"""Read json data from the client."""
|
"""Read json data from the client."""
|
||||||
if self._socket is None:
|
if self._socket is None: # pragma: no cover
|
||||||
# This happens when doing a connection while another one is already
|
# This happens when doing a connection while another one is already
|
||||||
# active for some reason.
|
# active for some reason.
|
||||||
log.ipc.warning("In on_ready_read with None socket!")
|
if self._old_socket is None:
|
||||||
return
|
log.ipc.warning("In on_ready_read with None socket and "
|
||||||
|
"old_socket!")
|
||||||
|
return
|
||||||
|
log.ipc.debug("In on_ready_read with None socket!")
|
||||||
|
socket = self._old_socket
|
||||||
|
else:
|
||||||
|
socket = self._socket
|
||||||
self._timer.stop()
|
self._timer.stop()
|
||||||
while self._socket is not None and self._socket.canReadLine():
|
while socket is not None and socket.canReadLine():
|
||||||
data = bytes(self._socket.readLine())
|
data = bytes(socket.readLine())
|
||||||
self.got_raw.emit(data)
|
self.got_raw.emit(data)
|
||||||
log.ipc.debug("Read from socket 0x{:x}: {!r}".format(
|
log.ipc.debug("Read from socket 0x{:x}: {!r}".format(
|
||||||
id(self._socket), data))
|
id(socket), data))
|
||||||
self._handle_data(data)
|
self._handle_data(data)
|
||||||
self._timer.start()
|
self._timer.start()
|
||||||
|
|
||||||
|
@ -587,22 +587,20 @@ def test_timeout(qtbot, caplog, qlocalsocket, ipc_server):
|
|||||||
assert caplog.records[-1].message.startswith("IPC connection timed out")
|
assert caplog.records[-1].message.startswith("IPC connection timed out")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('method, args, is_warning', [
|
def test_ipcserver_socket_none_readyread(ipc_server, caplog):
|
||||||
pytest.mark.posix(('on_error', [0], False)),
|
|
||||||
('on_disconnected', [], False),
|
|
||||||
('on_ready_read', [], True),
|
|
||||||
])
|
|
||||||
def test_ipcserver_socket_none(ipc_server, caplog, method, args, is_warning):
|
|
||||||
func = getattr(ipc_server, method)
|
|
||||||
assert ipc_server._socket is None
|
assert ipc_server._socket is None
|
||||||
|
assert ipc_server._old_socket is None
|
||||||
|
with caplog.at_level(logging.WARNING):
|
||||||
|
ipc_server.on_ready_read()
|
||||||
|
msg = "In on_ready_read with None socket and old_socket!"
|
||||||
|
assert msg in [r.message for r in caplog.records]
|
||||||
|
|
||||||
if is_warning:
|
|
||||||
with caplog.at_level(logging.WARNING):
|
|
||||||
func(*args)
|
|
||||||
else:
|
|
||||||
func(*args)
|
|
||||||
|
|
||||||
msg = "In {} with None socket!".format(method)
|
@pytest.mark.posix
|
||||||
|
def test_ipcserver_socket_none_error(ipc_server, caplog):
|
||||||
|
assert ipc_server._socket is None
|
||||||
|
ipc_server.on_error(0)
|
||||||
|
msg = "In on_error with None socket!"
|
||||||
assert msg in [r.message for r in caplog.records]
|
assert msg in [r.message for r in caplog.records]
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user