diff -r 0e7c4203bd79 Lib/httplib.py --- a/Lib/httplib.py Wed Dec 18 11:25:26 2013 -0800 +++ b/Lib/httplib.py Wed Dec 18 21:13:22 2013 +0000 @@ -307,6 +307,11 @@ hlist.append(line) self.addheader(headerseen, line[len(headerseen)+1:].strip()) continue + elif headerseen is not None: + # An empty header name. These aren't allowed in HTTP, but it's + # probably a benign mistake. Don't add the header, just keep + # going. + continue else: # It's not a header line; throw it back and stop here. if not self.dict: diff -r 0e7c4203bd79 Lib/rfc822.py --- a/Lib/rfc822.py Wed Dec 18 11:25:26 2013 -0800 +++ b/Lib/rfc822.py Wed Dec 18 21:13:22 2013 +0000 @@ -179,6 +179,11 @@ lst.append(line) self.dict[headerseen] = line[len(headerseen)+1:].strip() continue + elif headerseen is not None: + # An empty header name. These aren't allowed in HTTP, but it's + # probably a benign mistake. Don't add the header, just keep + # going. + continue else: # It's not a header line; throw it back and stop here. if not self.dict: @@ -202,7 +207,7 @@ data in RFC 2822-like formats with special header formats. """ i = line.find(':') - if i > 0: + if i > -1: return line[:i].lower() return None diff -r 0e7c4203bd79 Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py Wed Dec 18 11:25:26 2013 -0800 +++ b/Lib/test/test_httplib.py Wed Dec 18 21:13:22 2013 +0000 @@ -144,6 +144,17 @@ conn.request('GET', '/foo') self.assertTrue(sock.data.startswith(expected)) + def test_malformed_headers_coped_with(self): + # Issue 19996 + body = "HTTP/1.1 200 OK\r\nFirst: val\r\n: nval\r\nSecond: val\r\n\r\n" + sock = FakeSocket(body) + resp = httplib.HTTPResponse(sock) + resp.begin() + + self.assertEqual(resp.getheader('First'), 'val') + self.assertEqual(resp.getheader('Second'), 'val') + + class BasicTest(TestCase): def test_status_lines(self): diff -r 0e7c4203bd79 Lib/test/test_rfc822.py --- a/Lib/test/test_rfc822.py Wed Dec 18 11:25:26 2013 -0800 +++ b/Lib/test/test_rfc822.py Wed Dec 18 21:13:22 2013 +0000 @@ -248,6 +248,12 @@ eq(rfc822.quote('foo\\wacky"name'), 'foo\\\\wacky\\"name') eq(rfc822.unquote('"foo\\\\wacky\\"name"'), 'foo\\wacky"name') + def test_invalid_headers(self): + eq = self.assertEqual + msg = self.create_message("First: val\n: otherval\nSecond: val2\n") + eq(msg.getheader('First'), 'val') + eq(msg.getheader('Second'), 'val2') + def test_main(): test_support.run_unittest(MessageTestCase)