Commit be5b14bd authored by Hanno Schlichting's avatar Hanno Schlichting

Remove `Connection` and `Transfer-Encoding` headers from WSGI responses.

parent 4f0f50c6
......@@ -11,6 +11,9 @@ https://zope.readthedocs.io/en/2.13/CHANGES.html
Bugs Fixed
++++++++++
- Remove `Connection` and `Transfer-Encoding` headers from WSGI responses.
According to PEP 333 WSGI applications must not emit hop-by-hop headers.
- Removed docstrings from some methods to avoid publishing them. From
Products.PloneHotfix20160419. [maurits]
......
......@@ -34,28 +34,24 @@ from ZPublisher.Publish import missing_name
from ZPublisher.pubevents import PubStart, PubBeforeCommit, PubAfterTraversal
from ZPublisher.Iterators import IUnboundStreamIterator, IStreamIterator
_NOW = None # overwrite for testing
_NOW = None # overwrite for testing
def _now():
if _NOW is not None:
return _NOW
return time.time()
class WSGIResponse(HTTPResponse):
"""A response object for WSGI
This Response object knows nothing about ZServer, but tries to be
compatible with the ZServerHTTPResponse.
Most significantly, streaming is not (yet) supported.
"""
_streaming = _chunking = 0
_streaming = 0
_http_version = None
_server_version = None
_http_connection = None
# Set this value to 1 if streaming output in
# HTTP/1.1 should use chunked encoding
http_chunk = 0
# Append any "cleanup" functions to this list.
after_list = ()
......@@ -68,8 +64,8 @@ class WSGIResponse(HTTPResponse):
# set 204 (no content) status if 200 and response is empty
# and not streaming
if ('content-type' not in headers and
'content-length' not in headers and
not self._streaming and self.status == 200):
'content-length' not in headers and
not self._streaming and self.status == 200):
self.setStatus('nocontent')
# add content length if not streaming
......@@ -78,25 +74,6 @@ class WSGIResponse(HTTPResponse):
if content_length is None and not self._streaming:
self.setHeader('content-length', len(body))
if self._http_version == '1.0':
if (self._http_connection == 'keep-alive' and
'content-length' in self.headers):
self.setHeader('Connection', 'Keep-Alive')
else:
self.setHeader('Connection', 'close')
# Close the connection if we have been asked to.
# Use chunking if streaming output.
if self._http_version == '1.1':
if self._http_connection == 'close':
self.setHeader('Connection', 'close')
elif not self.headers.has_key('content-length'):
if self.http_chunk and self._streaming:
self.setHeader('Transfer-Encoding', 'chunked')
self._chunking = 1
else:
self.setHeader('Connection','close')
return '%s %s' % (self.status, self.errmsg), self.listHeaders()
def listHeaders(self):
......@@ -114,7 +91,7 @@ class WSGIResponse(HTTPResponse):
if realm:
self.setHeader('WWW-Authenticate', 'basic realm="%s"' % realm, 1)
def write(self,data):
def write(self, data):
""" Add data to our output stream.
HTML data may be returned using a stream-oriented interface.
......@@ -122,9 +99,7 @@ class WSGIResponse(HTTPResponse):
computation of a response to proceed.
"""
if not self._streaming:
notify(PubBeforeStreaming(self))
self._streaming = 1
self.stdout.flush()
......@@ -148,14 +123,6 @@ class WSGIResponse(HTTPResponse):
HTTPResponse.setBody(self, body, title, is_error)
def __str__(self):
# XXX Consider how we are to handle the cases this logic was trying
# to cover
#if self._wrote:
# if self._chunking:
# return '0\r\n\r\n'
# else:
# return ''
raise NotImplementedError
......@@ -256,7 +223,6 @@ def publish_module(environ, start_response,
stderr = StringIO()
response = _response_factory(stdout=stdout, stderr=stderr)
response._http_version = environ['SERVER_PROTOCOL'].split('/')[1]
response._http_connection = environ.get('CONNECTION_TYPE', 'close')
response._server_version = environ.get('SERVER_SOFTWARE')
request = _request_factory(environ['wsgi.input'], environ, response)
......
......@@ -55,61 +55,6 @@ class WSGIResponseTests(unittest.TestCase):
response.finalize()
self.assertFalse(response.getHeader('Content-Length'))
def test_finalize_HTTP_1_0_keep_alive_w_content_length(self):
response = self._makeOne()
response._http_version = '1.0'
response._http_connection = 'keep-alive'
response.setBody('TESTING')
response.finalize()
self.assertEqual(response.getHeader('Connection'), 'Keep-Alive')
def test_finalize_HTTP_1_0_keep_alive_wo_content_length_streaming(self):
response = self._makeOne()
response._http_version = '1.0'
response._http_connection = 'keep-alive'
response._streaming = True
response.finalize()
self.assertEqual(response.getHeader('Connection'), 'close')
def test_finalize_HTTP_1_0_not_keep_alive_w_content_length(self):
response = self._makeOne()
response._http_version = '1.0'
response.setBody('TESTING')
response.finalize()
self.assertEqual(response.getHeader('Connection'), 'close')
def test_finalize_HTTP_1_1_connection_close(self):
response = self._makeOne()
response._http_version = '1.1'
response._http_connection = 'close'
response.finalize()
self.assertEqual(response.getHeader('Connection'), 'close')
def test_finalize_HTTP_1_1_wo_content_length_streaming_wo_http_chunk(self):
response = self._makeOne()
response._http_version = '1.1'
response._streaming = True
response.http_chunk = 0
response.finalize()
self.assertEqual(response.getHeader('Connection'), 'close')
self.assertEqual(response.getHeader('Transfer-Encoding'), None)
self.assertFalse(response._chunking)
def test_finalize_HTTP_1_1_wo_content_length_streaming_w_http_chunk(self):
response = self._makeOne()
response._http_version = '1.1'
response._streaming = True
response.http_chunk = 1
response.finalize()
self.assertEqual(response.getHeader('Connection'), None)
def test_finalize_HTTP_1_1_w_content_length_wo_chunk_wo_streaming(self):
response = self._makeOne()
response._http_version = '1.1'
response.setBody('TESTING')
response.finalize()
self.assertEqual(response.getHeader('Connection'), None)
def test_listHeaders_skips_Server_header_wo_server_version_set(self):
response = self._makeOne()
response.setBody('TESTING')
......@@ -187,18 +132,6 @@ class WSGIResponseTests(unittest.TestCase):
self.assertEqual(response.getHeader('Content-Length'),
'%d' % len(test_streamiterator.data))
#def test___str__already_wrote_not_chunking(self):
# response = self._makeOne()
# response._wrote = True
# response._chunking = False
# self.assertEqual(str(response), '')
#def test___str__already_wrote_w_chunking(self):
# response = self._makeOne()
# response._wrote = True
# response._chunking = True
# self.assertEqual(str(response), '0\r\n\r\n')
def test___str___raises(self):
response = self._makeOne()
response.setBody('TESTING')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment