mirror of https://github.com/python/cpython
Fix issue3709 - BaseHTTPRequestHandler will buffer the headers and write only on end_headers call.
This commit is contained in:
parent
a73dc9d5e8
commit
e4dad4f8e2
|
@ -182,22 +182,29 @@ of which this module provides three different variants:
|
|||
|
||||
.. method:: send_header(keyword, value)
|
||||
|
||||
Writes a specific HTTP header to the output stream. *keyword* should
|
||||
specify the header keyword, with *value* specifying its value.
|
||||
Stores the HTTP header to an internal buffer which will be written to the
|
||||
output stream when :meth:`end_headers` method is invoked.
|
||||
*keyword* should specify the header keyword, with *value*
|
||||
specifying its value.
|
||||
|
||||
.. versionchanged:: 3.2 Storing the headers in an internal buffer
|
||||
|
||||
|
||||
.. method:: send_response_only(code, message=None)
|
||||
|
||||
Sends the reponse header only, used for the purposes when ``100
|
||||
Continue`` response is sent by the server to the client. If the *message*
|
||||
is not specified, the HTTP message corresponding the response *code* is
|
||||
sent.
|
||||
Continue`` response is sent by the server to the client. The headers not
|
||||
buffered and sent directly the output stream.If the *message* is not
|
||||
specified, the HTTP message corresponding the response *code* is sent.
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
.. method:: end_headers()
|
||||
|
||||
Sends a blank line, indicating the end of the HTTP headers in the
|
||||
response.
|
||||
Write the buffered HTTP headers to the output stream and send a blank
|
||||
line, indicating the end of the HTTP headers in the response.
|
||||
|
||||
.. versionchanged:: 3.2 Writing the buffered headers to the output stream.
|
||||
|
||||
.. method:: log_request(code='-', size='-')
|
||||
|
||||
|
|
|
@ -443,7 +443,10 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
|||
def send_header(self, keyword, value):
|
||||
"""Send a MIME header."""
|
||||
if self.request_version != 'HTTP/0.9':
|
||||
self.wfile.write(("%s: %s\r\n" % (keyword, value)).encode('ASCII', 'strict'))
|
||||
if not hasattr(self, '_headers_buffer'):
|
||||
self._headers_buffer = []
|
||||
self._headers_buffer.append(
|
||||
("%s: %s\r\n" % (keyword, value)).encode('ASCII', 'strict'))
|
||||
|
||||
if keyword.lower() == 'connection':
|
||||
if value.lower() == 'close':
|
||||
|
@ -454,7 +457,9 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
|||
def end_headers(self):
|
||||
"""Send the blank line ending the MIME headers."""
|
||||
if self.request_version != 'HTTP/0.9':
|
||||
self.wfile.write(b"\r\n")
|
||||
self._headers_buffer.append(b"\r\n")
|
||||
self.wfile.write(b"".join(self._headers_buffer))
|
||||
self._headers_buffer = []
|
||||
|
||||
def log_request(self, code='-', size='-'):
|
||||
"""Log an accepted request.
|
||||
|
|
|
@ -511,6 +511,49 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase):
|
|||
self.verify_get_called()
|
||||
self.assertEqual(result[-1], b'<html><body>Data</body></html>\r\n')
|
||||
|
||||
def test_header_buffering(self):
|
||||
|
||||
def _readAndReseek(f):
|
||||
pos = f.tell()
|
||||
f.seek(0)
|
||||
data = f.read()
|
||||
f.seek(pos)
|
||||
return data
|
||||
|
||||
input = BytesIO(b'GET / HTTP/1.1\r\n\r\n')
|
||||
output = BytesIO()
|
||||
self.handler.rfile = input
|
||||
self.handler.wfile = output
|
||||
self.handler.request_version = 'HTTP/1.1'
|
||||
|
||||
self.handler.send_header('Foo', 'foo')
|
||||
self.handler.send_header('bar', 'bar')
|
||||
self.assertEqual(_readAndReseek(output), b'')
|
||||
self.handler.end_headers()
|
||||
self.assertEqual(_readAndReseek(output),
|
||||
b'Foo: foo\r\nbar: bar\r\n\r\n')
|
||||
|
||||
def test_header_unbuffered_when_continue(self):
|
||||
|
||||
def _readAndReseek(f):
|
||||
pos = f.tell()
|
||||
f.seek(0)
|
||||
data = f.read()
|
||||
f.seek(pos)
|
||||
return data
|
||||
|
||||
input = BytesIO(b'GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n')
|
||||
output = BytesIO()
|
||||
self.handler.rfile = input
|
||||
self.handler.wfile = output
|
||||
self.handler.request_version = 'HTTP/1.1'
|
||||
|
||||
self.handler.handle_one_request()
|
||||
self.assertNotEqual(_readAndReseek(output), b'')
|
||||
result = _readAndReseek(output).split(b'\r\n')
|
||||
self.assertEqual(result[0], b'HTTP/1.1 100 Continue')
|
||||
self.assertEqual(result[1], b'HTTP/1.1 200 OK')
|
||||
|
||||
def test_with_continue_rejected(self):
|
||||
usual_handler = self.handler # Save to avoid breaking any subsequent tests.
|
||||
self.handler = RejectingSocketlessRequestHandler()
|
||||
|
|
|
@ -32,6 +32,10 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #3709: BaseHTTPRequestHandler will buffer the headers and write to
|
||||
output stream only when end_headers is invoked. This is a speedup and an
|
||||
internal optimization. Patch by endian.
|
||||
|
||||
- Issue #10220: Added inspect.getgeneratorstate. Initial patch by
|
||||
Rodolpho Eckhardt.
|
||||
|
||||
|
|
Loading…
Reference in New Issue