Géry <[email protected]> added the comment:
> http.server.BaseHTTPRequestHandler end_headers() can reference _header_buffer
> array before it is assigned.
@grumblor I was about to open the same bug after reading the implementation of
http.server this morning and noticing that the attribute _headers_buffer of
BaseHTTPRequestHandler is used in 4 methods:
- send_response_only;
- send_header;
- end_headers;
- flush_headers
but its existence is not checked only in end_headers.
> It seems like sending zero headers is not supported
@andrei.avk It is actually supported by the syntax of HTTP/1.1 messages, cf.
RFC 7230, § 3:
HTTP-message = start-line
*( header-field CRLF )
CRLF
[ message-body ]
For instance the method handle_expect_100 does not send any header:
def handle_expect_100(self):
self.send_response_only(HTTPStatus.CONTINUE)
self.end_headers()
return True
It only writes a start line (which includes \r\n) followed by an empty line
(\r\n) as a response:
HTTP/1.1 100 Continue\r\n\r\n
But self.end_headers() does not raise an AttributeError here like one might
expect from its implementation:
def end_headers(self):
if self.request_version != 'HTTP/0.9':
self._headers_buffer.append(b"\r\n")
self.flush_headers()
because, contrary to what its name suggests, self._headers_buffer does not only
include the response headers but also the response start line, which is
appended to the buffer before by self.send_response_only(HTTPStatus.CONTINUE):
def send_response_only(self, code, message=None):
"""Send the response header only."""
if self.request_version != 'HTTP/0.9':
if message is None:
if code in self.responses:
message = self.responses[code][0]
else:
message = ''
if not hasattr(self, '_headers_buffer'):
self._headers_buffer = []
self._headers_buffer.append(("%s %d %s\r\n" %
(self.protocol_version, code, message)).encode(
'latin-1', 'strict'))
So I am not sure it is a bug if we consider that send_response_only (which
appends a start line to the buffer) is a precondition to end_headers (which
appends an empty line to the buffer and flushes it). But then flush_headers
should also have this precondition instead of preventing the AttributeError
like this:
def flush_headers(self):
if hasattr(self, '_headers_buffer'):
self.wfile.write(b"".join(self._headers_buffer))
self._headers_buffer = []
Let’s ask Andrew Schaaf (@endian) who introduced flush_headers in Python 3.3
(cf. https://bugs.python.org/issue3709) why he implemented end_headers by
contract and flush_headers defensively.
----------
nosy: +endian, maggyero
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue43474>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com