parent
b95fd2c814
commit
bfd8faafef
@ -36,6 +36,7 @@ from qutebrowser.utils import log, usertypes, error, objreg
|
||||
CONNECT_TIMEOUT = 100
|
||||
WRITE_TIMEOUT = 1000
|
||||
READ_TIMEOUT = 5000
|
||||
PROTOCOL_VERSION = 1
|
||||
|
||||
|
||||
def _get_socketname(basedir, user=None):
|
||||
@ -228,6 +229,13 @@ class IPCServer(QObject):
|
||||
# Maybe another connection is waiting.
|
||||
self.handle_connection()
|
||||
|
||||
def _handle_invalid_data(self):
|
||||
"""Handle invalid data we got from a QLocalSocket."""
|
||||
log.ipc.error("Ignoring invalid IPC data.")
|
||||
self.got_invalid_data.emit()
|
||||
self._socket.error.connect(self.on_error)
|
||||
self._socket.disconnectFromServer()
|
||||
|
||||
@pyqtSlot()
|
||||
def on_ready_read(self):
|
||||
"""Read json data from the client."""
|
||||
@ -241,35 +249,44 @@ class IPCServer(QObject):
|
||||
data = bytes(self._socket.readLine())
|
||||
self.got_raw.emit(data)
|
||||
log.ipc.debug("Read from socket: {}".format(data))
|
||||
|
||||
try:
|
||||
decoded = data.decode('utf-8')
|
||||
except UnicodeDecodeError:
|
||||
log.ipc.error("Ignoring invalid IPC data.")
|
||||
log.ipc.debug("invalid data: {}".format(
|
||||
log.ipc.error("invalid utf-8: {}".format(
|
||||
binascii.hexlify(data)))
|
||||
self.got_invalid_data.emit()
|
||||
self._socket.error.connect(self.on_error)
|
||||
self._socket.disconnectFromServer()
|
||||
self._handle_invalid_data()
|
||||
return
|
||||
|
||||
log.ipc.debug("Processing: {}".format(decoded))
|
||||
try:
|
||||
json_data = json.loads(decoded)
|
||||
except ValueError:
|
||||
log.ipc.error("Ignoring invalid IPC data.")
|
||||
log.ipc.debug("invalid json: {}".format(decoded.strip()))
|
||||
self.got_invalid_data.emit()
|
||||
self._socket.error.connect(self.on_error)
|
||||
self._socket.disconnectFromServer()
|
||||
log.ipc.error("invalid json: {}".format(decoded.strip()))
|
||||
self._handle_invalid_data()
|
||||
return
|
||||
|
||||
try:
|
||||
args = json_data['args']
|
||||
except KeyError:
|
||||
log.ipc.error("Ignoring invalid IPC data.")
|
||||
log.ipc.debug("no args: {}".format(decoded.strip()))
|
||||
self.got_invalid_data.emit()
|
||||
self._socket.error.connect(self.on_error)
|
||||
self._socket.disconnectFromServer()
|
||||
log.ipc.error("no args: {}".format(decoded.strip()))
|
||||
self._handle_invalid_data()
|
||||
return
|
||||
|
||||
try:
|
||||
protocol_version = int(json_data['protocol_version'])
|
||||
except (KeyError, ValueError):
|
||||
log.ipc.error("invalid version: {}".format(decoded.strip()))
|
||||
self._handle_invalid_data()
|
||||
return
|
||||
|
||||
if protocol_version != PROTOCOL_VERSION:
|
||||
log.ipc.error("incompatible version: expected {}, "
|
||||
"got {}".format(
|
||||
PROTOCOL_VERSION, protocol_version))
|
||||
self._handle_invalid_data()
|
||||
return
|
||||
|
||||
cwd = json_data.get('cwd', None)
|
||||
self.got_args.emit(args, cwd)
|
||||
|
||||
@ -310,7 +327,8 @@ def send_to_running_instance(socketname, command, *, socket=None):
|
||||
connected = socket.waitForConnected(100)
|
||||
if connected:
|
||||
log.ipc.info("Opening in existing instance")
|
||||
json_data = {'args': command, 'version': qutebrowser.__version__}
|
||||
json_data = {'args': command, 'version': qutebrowser.__version__,
|
||||
'protocol_version': PROTOCOL_VERSION}
|
||||
try:
|
||||
cwd = os.getcwd()
|
||||
except OSError:
|
||||
|
@ -296,7 +296,9 @@ class TestHandleConnection:
|
||||
assert msg in all_msgs
|
||||
|
||||
def test_read_line_immediately(self, qtbot, ipc_server, caplog):
|
||||
socket = FakeSocket(data=b'{"args": ["foo"]}\n')
|
||||
data = '{{"args": ["foo"], "protocol_version": {}}}\n'.format(
|
||||
ipc.PROTOCOL_VERSION)
|
||||
socket = FakeSocket(data=data.encode('utf-8'))
|
||||
|
||||
ipc_server._server = FakeServer(socket)
|
||||
|
||||
@ -333,28 +335,47 @@ def test_partial_line(connected_socket):
|
||||
connected_socket.write(b'foo')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('data', [
|
||||
b'\x80\n', # invalid UTF8
|
||||
b'\n',
|
||||
b'{"is this invalid json?": true\n',
|
||||
b'{"valid json without args": true}\n',
|
||||
OLD_VERSION = str(ipc.PROTOCOL_VERSION - 1).encode('utf-8')
|
||||
NEW_VERSION = str(ipc.PROTOCOL_VERSION + 1).encode('utf-8')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('data, msg', [
|
||||
(b'\x80\n', 'invalid utf-8'),
|
||||
(b'\n', 'invalid json'),
|
||||
(b'{"is this invalid json?": true\n', 'invalid json'),
|
||||
(b'{"valid json without args": true}\n', 'no args'),
|
||||
(b'{"args": [], "protocol_version": ' + OLD_VERSION + b'}\n',
|
||||
'incompatible version'),
|
||||
(b'{"args": [], "protocol_version": ' + NEW_VERSION + b'}\n',
|
||||
'incompatible version'),
|
||||
(b'{"args": [], "protocol_version": "foo"}\n', 'invalid version'),
|
||||
(b'{"args": []}\n', 'invalid version'),
|
||||
])
|
||||
def test_invalid_data(qtbot, ipc_server, connected_socket, caplog, data):
|
||||
def test_invalid_data(qtbot, ipc_server, connected_socket, caplog, data, msg):
|
||||
got_args_spy = QSignalSpy(ipc_server.got_args)
|
||||
|
||||
signals = [ipc_server.got_invalid_data, connected_socket.disconnected]
|
||||
with caplog.atLevel(logging.ERROR):
|
||||
with qtbot.waitSignals(signals, raising=True):
|
||||
connected_socket.write(data)
|
||||
|
||||
messages = [r.message for r in caplog.records()]
|
||||
assert messages[-1] == 'Ignoring invalid IPC data.'
|
||||
assert messages[-2].startswith(msg)
|
||||
assert not got_args_spy
|
||||
|
||||
|
||||
def test_multiline(qtbot, ipc_server, connected_socket):
|
||||
spy = QSignalSpy(ipc_server.got_args)
|
||||
error_spy = QSignalSpy(ipc_server.got_invalid_data)
|
||||
|
||||
data = ('{{"args": ["one"], "protocol_version": {version}}}\n'
|
||||
'{{"args": ["two"], "protocol_version": {version}}}\n'.format(
|
||||
version=ipc.PROTOCOL_VERSION))
|
||||
|
||||
with qtbot.waitSignals([ipc_server.got_args, ipc_server.got_args],
|
||||
raising=True):
|
||||
connected_socket.write(b'{"args": ["one"]}\n{"args": ["two"]}\n')
|
||||
connected_socket.write(data.encode('utf-8'))
|
||||
|
||||
assert len(spy) == 2
|
||||
assert not error_spy
|
||||
@ -396,7 +417,8 @@ class TestSendToRunningInstance:
|
||||
|
||||
assert len(raw_spy) == 1
|
||||
assert len(raw_spy[0]) == 1
|
||||
raw_expected = {'args': ['foo'], 'version': qutebrowser.__version__}
|
||||
raw_expected = {'args': ['foo'], 'version': qutebrowser.__version__,
|
||||
'protocol_version': ipc.PROTOCOL_VERSION}
|
||||
if has_cwd:
|
||||
raw_expected['cwd'] = str(tmpdir)
|
||||
parsed = json.loads(raw_spy[0][0].decode('utf-8'))
|
||||
|
Loading…
Reference in New Issue
Block a user