def send(self, event: HttpEvent) -> layer.CommandGenerator[None]: assert event.stream_id == self.stream_id if isinstance(event, ResponseHeaders): self.response = response = event.response if response.is_http2: response = response.copy() # Convert to an HTTP/1 response. response.http_version = "HTTP/1.1" # not everyone supports empty reason phrases, so we better make up one. response.reason = status_codes.RESPONSES.get( response.status_code, "") # Shall we set a Content-Length header here if there is none? # For now, let's try to modify as little as possible. raw = http1.assemble_response_head(response) yield commands.SendData(self.conn, raw) elif isinstance(event, ResponseData): assert self.response if "chunked" in self.response.headers.get("transfer-encoding", "").lower(): raw = b"%x\r\n%s\r\n" % (len(event.data), event.data) else: raw = event.data if raw: yield commands.SendData(self.conn, raw) elif isinstance(event, ResponseEndOfMessage): assert self.response if "chunked" in self.response.headers.get("transfer-encoding", "").lower(): yield commands.SendData(self.conn, b"0\r\n\r\n") yield from self.mark_done(response=True) elif isinstance(event, ResponseProtocolError): if not self.response and event.code != status_codes.NO_RESPONSE: resp = http.Response.make( event.code, format_error(event.code, event.message), http.Headers( Server=version.MITMPROXY, Connection="close", Content_Type="text/html", )) raw = http1.assemble_response(resp) yield commands.SendData(self.conn, raw) if self.conn.state & ConnectionState.CAN_WRITE: yield commands.CloseConnection(self.conn) else: raise AssertionError(f"Unexpected event: {event}")
def send_response_headers(self, response): raw = http1.assemble_response_head(response) self.client_conn.wfile.write(raw) self.client_conn.wfile.flush()