--- a/src/eric7/Debugger/DebuggerInterfacePython.py Fri Feb 02 19:29:29 2024 +0100 +++ b/src/eric7/Debugger/DebuggerInterfacePython.py Wed Feb 07 15:28:08 2024 +0100 @@ -12,6 +12,8 @@ import logging import os import shlex +import struct +import zlib from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, QTimer @@ -53,7 +55,7 @@ self.process = None self.__startedVenv = "" - self.queue = [] + self.__commandQueue = [] self.__mainDebugger = None self.__connections = {} self.__pendingConnections = [] @@ -208,7 +210,7 @@ else str(Preferences.getDebugger("Python3Redirect")) ) noencoding = ( - Preferences.getDebugger("Python3NoEncoding") and "--no-encoding" or "" + "--no-encoding" if Preferences.getDebugger("Python3NoEncoding") else "" ) multiprocessEnabled = ( "--multiprocess" if Preferences.getDebugger("MultiProcessEnabled") else "" @@ -706,10 +708,10 @@ if self.__mainDebugger: # Send commands that were waiting for the connection. conn = self.__connections[self.__mainDebugger] - for cmd in self.queue: - self.__writeJsonCommandToSocket(cmd, conn) + for jsonStr in self.__commandQueue: + self.__writeJsonCommandToSocket(jsonStr, conn) - self.queue = [] + self.__commandQueue.clear() def shutdown(self): """ @@ -732,7 +734,7 @@ self.__shutdownSocket(sock) # reinitialize - self.queue = [] + self.__commandQueue.clear() self.__mainDebugger = None @@ -1401,14 +1403,27 @@ @param sock reference to the socket to read data from @type QTcpSocket """ - while sock and sock.canReadLine(): - qs = sock.readLine() - line = bytes(qs).decode(encoding=Preferences.getSystem("StringEncoding")) + while sock and sock.bytesAvailable(): + header = sock.read(struct.calcsize(b"!II")) + length, datahash = struct.unpack(b"!II", header) + + data = bytearray() + while len(data) < length: + maxSize = length - len(data) + if sock.bytesAvailable() < maxSize: + sock.waitForReadyRead(50) + data += sock.read(maxSize) - logging.debug("<Debug-Server> %s", line) - ##print("Server: ", line) ## debug # __IGNORE_WARNING_M891__ + if zlib.adler32(data) & 0xFFFFFFFF != datahash: + # corrupted data -> discard and continue + continue - self.__handleJsonCommand(line, sock) + jsonStr = data.decode("utf-8", "backslashreplace") + + logging.debug("<Debug-Server> %s", jsonStr) + ##print("Server: ", jsonStr) ## debug # __IGNORE_WARNING_M891__ + + self.__handleJsonCommand(jsonStr, sock) def __handleJsonCommand(self, jsonStr, sock): """ @@ -1646,29 +1661,30 @@ "method": command, "params": params, } - cmd = json.dumps(commandDict) + "\n" + jsonStr = json.dumps(commandDict) if debuggerId and debuggerId in self.__connections: sock = self.__connections[debuggerId] elif sock is None and self.__mainDebugger is not None: sock = self.__connections[self.__mainDebugger] if sock is not None: - self.__writeJsonCommandToSocket(cmd, sock) + self.__writeJsonCommandToSocket(jsonStr, sock) else: - self.queue.append(cmd) + self.__commandQueue.append(jsonStr) - def __writeJsonCommandToSocket(self, cmd, sock): + def __writeJsonCommandToSocket(self, jsonCommand, sock): """ Private method to write a JSON command to the socket. - @param cmd JSON command to be sent + @param jsonCommand JSON encoded command to be sent @type str @param sock reference to the socket to write to @type QTcpSocket """ - data = cmd.encode("utf8", "backslashreplace") - length = "{0:09d}".format(len(data)) - sock.write(length.encode() + data) + data = jsonCommand.encode("utf8", "backslashreplace") + header = struct.pack(b"!II", len(data), zlib.adler32(data) & 0xFFFFFFFF) + sock.write(header) + sock.write(data) sock.flush()