diff --git a/Lib/cgi.py b/Lib/cgi.py --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -687,29 +687,70 @@ class FieldStorage: self.__write(line) def read_lines_to_outerboundary(self): """Internal: read lines until outerboundary.""" next = "--" + self.outerboundary last = next + "--" delim = "" last_line_lfend = True + last_line = None + next_line = None while 1: - line = self.fp.readline(1<<16) + if next_line: + line = next_line + next_line = None + else: + # NB - we may interrupt \r\n sequences if they span the 2**16 + # byte boundary + line = self.fp.readline(1 << 16) + + # The previous line ended with \r, so we don't know if it was + # really at the end of a line or not until looking at the current + # line + if last_line: + if line[:1] == "\n": + # Oh noes! We actually interrupted a \r\n sequence. Save + # this line for later, and process the previous line again, + # this time with the extra \n added on + next_line = line[1:] + line = last_line + "\n" + else: + # There was much rejoicing! This wasn't an interrupted \r\n + # sequence after all, so we can just process the previous line + # as normal + line = last_line + # Save the current line for processing on the next + # iteration + next_line = line + last_line = None + + # The previous line was normal... + # If the current line ends with \r, it's possible that we've + # interrupted a \r\n sequence due to capping the amount of data + # received by readline() above. + # Save the current line so we can decide after reading the next + # line if we've interrupted a \r\n sequence + elif line[-1] == "\r": + last_line = line + continue + if not line: self.done = -1 break + if line[:2] == "--" and last_line_lfend: strippedline = line.strip() if strippedline == next: break if strippedline == last: self.done = 1 break odelim = delim + if line[-2:] == "\r\n": delim = "\r\n" line = line[:-2] last_line_lfend = True elif line[-1] == "\n": delim = "\n" line = line[:-1] last_line_lfend = True