Log message for revision 73723: Collector #2300: delimit *all* headers with CRLF; accumulated_headers and appendHeader use \n for delimeters and never get corrected on output
Changed: U Zope/trunk/lib/python/ZServer/HTTPResponse.py U Zope/trunk/lib/python/ZServer/tests/test_responses.py -=- Modified: Zope/trunk/lib/python/ZServer/HTTPResponse.py =================================================================== --- Zope/trunk/lib/python/ZServer/HTTPResponse.py 2007-03-27 12:44:11 UTC (rev 73722) +++ Zope/trunk/lib/python/ZServer/HTTPResponse.py 2007-03-27 12:44:27 UTC (rev 73723) @@ -113,8 +113,15 @@ self._chunking=1 else: self.setHeader('Connection','close') + + headers = headers.items() + for line in self.accumulated_headers.splitlines(): + if line[0] == '\t': + headers[-1][1] += '\n' + line + continue + headers.append(line.split(': ', 1)) - for key, val in headers.items(): + for key, val in headers: if key.lower()==key: # only change non-literal header names key="%s%s" % (key[:1].upper(), key[1:]) @@ -124,10 +131,13 @@ key="%s-%s%s" % (key[:l],key[l+1:l+2].upper(),key[l+2:]) start=l+1 l=key.find('-',start) + val = val.replace('\n\t', '\r\n\t') append("%s: %s" % (key, val)) if self.cookies: - headersl=headersl+self._cookie_list() - headersl[len(headersl):]=[self.accumulated_headers, body] + headersl.extend(self._cookie_list()) + + append('') + append(body) return "\r\n".join(headersl) _tempfile=None @@ -150,6 +160,7 @@ """ + if type(data) != type(''): raise TypeError('Value must be a string') Modified: Zope/trunk/lib/python/ZServer/tests/test_responses.py =================================================================== --- Zope/trunk/lib/python/ZServer/tests/test_responses.py 2007-03-27 12:44:11 UTC (rev 73722) +++ Zope/trunk/lib/python/ZServer/tests/test_responses.py 2007-03-27 12:44:27 UTC (rev 73723) @@ -56,7 +56,7 @@ one = ZServerHTTPResponse(stdout=DummyChannel()) self.assertRaises(AssertionError, one.setBody, test_streamiterator()) - + class DummyChannel: def __init__(self): self.out = StringIO() @@ -92,8 +92,46 @@ return self.data raise StopIteration +class ZServerHTTPResponseTestCase(unittest.TestCase): + """Test ZServer HTTPResponse object""" + + def _makeOne(self): + return ZServerHTTPResponse() + + def testToString(self): + response = self._makeOne() + response.headers = { + 'content-type': 'text/plain', + 'all-lower-case': 'foo', + 'Title-Cased': 'bar', + 'mixed-CasED': 'spam', + 'multilined': 'eggs\n\tham'} + response.accumulated_headers = 'foo-bar: bar\n\tbaz\nFoo-bar: monty\n' + response.cookies = dict(foo=dict(value='bar')) + response.body = 'A body\nwith multiple lines\n' + + result = str(response) + headers, body = result.rsplit('\r\n\r\n') + + self.assertEqual(body, response.body) + + self.assertTrue(headers.startswith('HTTP/1.0 200 OK\r\n')) + + # 15 header lines all delimited by \r\n + self.assertEqual( + ['\n' in line for line in headers.split('\r\n')], + 15 * [False]) + + self.assertTrue('Multilined: eggs\r\n\tham\r\n' in headers) + self.assertTrue('Foo-Bar: bar\r\n\tbaz\r\n' in headers) + def test_suite(): - return unittest.makeSuite(ZServerResponseTestCase) + suite = unittest.TestSuite() + suite.addTests(( + unittest.makeSuite(ZServerResponseTestCase), + unittest.makeSuite(ZServerHTTPResponseTestCase) + )) + return suite if __name__ == "__main__": unittest.main(defaultTest="test_suite") _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org http://mail.zope.org/mailman/listinfo/zope-checkins