--- Lib/email/ofeedparser.py 2006-03-18 10:41:53.000000000 -0500 +++ Lib/email/feedparser.py 2009-03-29 21:31:18.000000000 -0400 @@ -104,6 +105,10 @@ # data after the final RE. In the case of a NL/CR terminated string, # this is the empty string. self._partial = parts.pop() + #GAN 29Mar09 bugs 1555570, 1721862 Confusion at 8K boundary ending with \r: + # is there a \n to follow later? + if not self._partial and parts and parts[-1].endswith('\r'): + self._partial = parts.pop(-2)+parts.pop() # parts is a list of strings, alternating between the line contents # and the eol character(s). Gather up a list of lines after # re-attaching the newlines. --- Lib/email/test/otest_email.py 2008-01-19 07:32:27.000000000 -0500 +++ Lib/email/test/test_email.py 2009-04-02 15:15:23.000000000 -0400 @@ -2550,6 +2550,39 @@ eq(headers, ['A', 'B', 'CC']) eq(msg.get_payload(), 'body') + def test_pushCR_LF(self): + '''FeedParser BufferedSubFile.push() assumed it received complete + line endings. A CR ending one push() followed by a LF starting + the next push() added an empty line. + ''' + imt = [ + ("a\r \n", 2), + ("b", 0), + ("c\n", 1), + ("", 0), + ("d\r\n", 1), + ("e\r", 0), + ("\nf", 1), + ("\r\n", 1), + ] + from email.FeedParser import BufferedSubFile, NeedMoreData + bsf = BufferedSubFile() + om = [] + nt = 0 + for il, n in imt: + bsf.push(il) + nt += n + n1 = 0 + while True: + ol = bsf.readline() + if ol == NeedMoreData: + break + om.append(ol) + n1 += 1 + self.assertTrue(n == n1) + self.assertTrue(len(om) == nt) + self.assertTrue(''.join([il for il, n in imt]) == ''.join(om)) + class TestBase64(unittest.TestCase):