Message411017
> 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. |
|
Date |
User |
Action |
Args |
2022-01-20 10:36:25 | maggyero | set | recipients:
+ maggyero, endian, andrei.avk, grumblor |
2022-01-20 10:36:25 | maggyero | set | messageid: <1642674985.77.0.976942137333.issue43474@roundup.psfhosted.org> |
2022-01-20 10:36:25 | maggyero | link | issue43474 messages |
2022-01-20 10:36:25 | maggyero | create | |
|