Géry <gery.o...@gmail.com> 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 <rep...@bugs.python.org> <https://bugs.python.org/issue43474> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com