Ticket #3050: linereceiver_depth.3.diff

File linereceiver_depth.3.diff, 4.9 KB (added by Graham Batty, 9 years ago)

Updated version of the previous patch that accommodates calling setLineMode from outside a rawDataReceived method.

  • twisted/protocols/basic.py

     
    534534    """
    535535    line_mode = 1
    536536    __buffer = b''
     537    __busy_receiving = False
    537538    delimiter = b'\r\n'
    538539    MAX_LENGTH = 16384
    539540
     
    555556        Translates bytes into lines, and calls lineReceived (or
    556557        rawDataReceived, depending on mode.)
    557558        """
    558         self.__buffer = self.__buffer+data
    559         while self.line_mode and not self.paused:
    560             try:
    561                 line, self.__buffer = self.__buffer.split(self.delimiter, 1)
    562             except ValueError:
    563                 if len(self.__buffer) > self.MAX_LENGTH:
    564                     line, self.__buffer = self.__buffer, b''
    565                     return self.lineLengthExceeded(line)
    566                 break
    567             else:
    568                 linelength = len(line)
    569                 if linelength > self.MAX_LENGTH:
    570                     exceeded = line + self.__buffer
    571                     self.__buffer = b''
    572                     return self.lineLengthExceeded(exceeded)
    573                 why = self.lineReceived(line)
    574                 if why or self.transport and self.transport.disconnecting:
    575                     return why
    576         else:
    577             if not self.paused:
    578                 data=self.__buffer
    579                 self.__buffer = b''
    580                 if data:
    581                     return self.rawDataReceived(data)
     559        if self.__busy_receiving:
     560            self.__buffer += data
     561            return
    582562
     563        try:
     564            self.__busy_receiving = True
     565            self.__buffer += data
     566            while self.__buffer and not self.paused:
     567                if self.line_mode:
     568                    try:
     569                        line, self.__buffer = self.__buffer.split(self.delimiter, 1)
     570                    except ValueError:
     571                        if len(self.__buffer) > self.MAX_LENGTH:
     572                            line, self.__buffer = self.__buffer, ''
     573                            return self.lineLengthExceeded(line)
     574                        return
     575                    else:
     576                        linelength = len(line)
     577                        if linelength > self.MAX_LENGTH:
     578                            exceeded = line + self.__buffer
     579                            self.__buffer = ''
     580                            return self.lineLengthExceeded(exceeded)
     581                        why = self.lineReceived(line)
     582                        if why or self.transport and self.transport.disconnecting:
     583                            return why
     584                else:
     585                    data = self.__buffer
     586                    self.__buffer = ''
     587                    why = self.rawDataReceived(data)
     588                    if why:
     589                        return why
     590        finally:
     591            self.__busy_receiving = False
    583592
    584593    def setLineMode(self, extra=b''):
    585594        """
  • twisted/protocols/test/test_basic.py

     
    77
    88from __future__ import division, absolute_import
    99
     10import sys
    1011import struct
    1112
    1213from twisted.python.compat import _PY3, iterbytes
     
    1718
    1819_PY3NEWSTYLESKIP = "All classes are new style on Python 3."
    1920
     21class FlippingLineTester(basic.LineReceiver):
     22    """
     23    A line receiver that flips between line and raw data modes after one byte.
     24    """
    2025
     26    delimiter = '\n'
     27
     28    def lineReceived(self, line):
     29        """
     30        Set the mode to raw.
     31        """
     32        self.setRawMode()
     33
     34    def rawDataReceived(self, data):
     35        """
     36        Set the mode back to line.
     37        """
     38        self.setLineMode(data[1:])
     39
     40
    2141class LineTester(basic.LineReceiver):
    2242    """
    2343    A line receiver that parses data received and make actions on some tokens.
     
    256276        self.assertEqual(protocol.rest, b'')
    257277
    258278
     279    def test_stackRecursion(self):
     280        """
     281        Test switching modes many times on the same data.
     282        """
     283        a = FlippingLineTester()
     284        t = proto_helpers.StringIOWithoutClosing()
     285        a.makeConnection(protocol.FileWrapper(t))
     286        a.dataReceived('x\nx' * sys.getrecursionlimit())
    259287
    260288class LineOnlyReceiverTestCase(unittest.SynchronousTestCase):
    261289    """
  • twisted/topfiles/3050.bugfix

     
     1twisted.protocols.basic.LineReceiver now does not hit the maximum stack recursion depth when the line and data mode is switched many times.
     2twisted.protocols.basic.LineReceiver now does not hit the maximum stack recursion depth when the line and data mode is switched many times.