resolved RESOLVED PASS · 38 tool calls · 294 s · encode/httpx
Server connection handling. * Add `HTTPParser.keep_alive`. * Server... always read request to completion on keep alives. * `HTTPParser.complete` -> `.reset` * Close streams on server exit. * Don't raise `KeyboardException` on server exit.
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "grep -rn \"HTTPParser\" src/httpx/_parsers.py src/httpx/_server.py"
} | {"status": "ok", "stdout": "src/httpx/_parsers.py:5:__all__ = ['HTTPParser', 'Mode', 'ProtocolError']\nsrc/httpx/_parsers.py:72:class HTTPParser:\nsrc/httpx/_pafull{"status": "ok", "stdout": "src/httpx/_parsers.py:5:__all__ = ['HTTPParser', 'Mode', 'ProtocolError']\nsrc/httpx/_parsers.py:72:class HTTPParser:\nsrc/httpx/_parsers.py:76: client = HTTPParser(writer, reader)\nsrc/httpx/_parsers.py:426: return f'<HTTPParser [{detail}]>'\nsrc/httpx/_server.py:6:from ._parsers import HTTPParser\nsrc/httpx/_server.py:27: self._parser = HTTPParser(stream, mode='SERVER')\n", "stderr": "", "exit_code": 0} |
| 2 | run_command | {
"command": "sed -n '72,150p' src/httpx/_parsers.py"
} | {"status": "ok", "stdout": "class HTTPParser:\n \"\"\"\n Usage...\n\n client = HTTPParser(writer, reader)\n client.send_method_line()\n client.send_headers()\n full{"status": "ok", "stdout": "class HTTPParser:\n \"\"\"\n Usage...\n\n client = HTTPParser(writer, reader)\n client.send_method_line()\n client.send_headers()\n client.send_body()\n client.recv_status_line()\n client.recv_headers()\n client.recv_body()\n client.complete()\n client.close()\n \"\"\"\n def __init__(self, stream: Stream, mode: str) -> None:\n self.stream = stream\n self.parser = ReadAheadParser(stream)\n self.mode = {'CLIENT': Mode.CLIENT, 'SERVER': Mode.SERVER}[mode]\n\n # Track state...\n if self.mode == Mode.CLIENT:\n self.send_state: State = State.SEND_METHOD_LINE\n self.recv_state: State = State.WAIT\n else:\n self.recv_state = State.RECV_METHOD_LINE\n self.send_state = State.WAIT\n\n # Track message framing...\n self.send_content_length: int | None = 0\n self.recv_content_length: int | None = 0\n self.send_seen_length = 0\n self.recv_seen_length = 0\n\n # Track connection keep alive...\n self.send_keep_alive = True\n self.recv_keep_alive = True\n\n # Special states...\n self.processing_1xx = False\n\n def send_method_line(self, method: bytes, target: bytes, protocol: bytes) -> None:\n \"\"\"\n Send the initial request line:\n\n >>> p.send_method_line(b'GET', b'/', b'HTTP/1.1')\n\n Sending state will switch to SEND_HEADERS state.\n \"\"\"\n if self.send_state != State.SEND_METHOD_LINE:\n msg = f\"Called 'send_method_line' in invalid state {self.send_state}\"\n raise ProtocolError(msg)\n\n # Send initial request line, eg. \"GET / HTTP/1.1\"\n if protocol != b'HTTP/1.1':\n raise ProtocolError(\"Sent unsupported protocol version\")\n data = b\" \".join([method, target, protocol]) + b\"\\r\\n\"\n self.stream.write(data)\n\n self.send_state = State.SEN |
| 3 | run_command | {
"command": "grep -n \"def complete\" src/httpx/_parsers.py"
} | {"status": "ok", "stdout": "378: def complete(self):\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "378: def complete(self):\n", "stderr": "", "exit_code": 0} |
| 4 | run_command | {
"command": "sed -n '378,385p' src/httpx/_parsers.py"
} | {"status": "ok", "stdout": " def complete(self):\n is_fully_complete = self.send_state == State.DONE and self.recv_state == State.DONE\n is_keepalive = self.senfull{"status": "ok", "stdout": " def complete(self):\n is_fully_complete = self.send_state == State.DONE and self.recv_state == State.DONE\n is_keepalive = self.send_keep_alive and self.recv_keep_alive\n\n if not (is_fully_complete and is_keepalive):\n self.close()\n return\n\n", "stderr": "", "exit_code": 0} |
| 5 | run_command | {
"command": "sed -n '378,400p' src/httpx/_parsers.py"
} | {"status": "ok", "stdout": " def complete(self):\n is_fully_complete = self.send_state == State.DONE and self.recv_state == State.DONE\n is_keepalive = self.senfull{"status": "ok", "stdout": " def complete(self):\n is_fully_complete = self.send_state == State.DONE and self.recv_state == State.DONE\n is_keepalive = self.send_keep_alive and self.recv_keep_alive\n\n if not (is_fully_complete and is_keepalive):\n self.close()\n return\n\n if self.mode == Mode.CLIENT:\n self.send_state = State.SEND_METHOD_LINE\n self.recv_state = State.WAIT\n else:\n self.recv_state = State.RECV_METHOD_LINE\n self.send_state = State.WAIT\n\n self.send_content_length = 0\n self.recv_content_length = 0\n self.send_seen_length = 0\n self.recv_seen_length = 0\n self.send_keep_alive = True\n self.recv_keep_alive = True\n self.processing_1xx = False\n\n", "stderr": "", "exit_code": 0} |
| 6 | run_command | {
"command": "sed -n '27,100p' src/httpx/_server.py"
} | {"status": "ok", "stdout": " self._parser = HTTPParser(stream, mode='SERVER')\n self._keepalive_duration = 5.0\n self._idle_expiry = time.monotonic() + self._kefull{"status": "ok", "stdout": " self._parser = HTTPParser(stream, mode='SERVER')\n self._keepalive_duration = 5.0\n self._idle_expiry = time.monotonic() + self._keepalive_duration\n\n # API entry points...\n def handle_requests(self):\n try:\n while not self._parser.is_closed():\n method, url, headers = self._recv_head()\n stream = HTTPStream(self._recv_body, self._complete)\n # TODO: Handle endpoint exceptions\n with Request(method, url, headers=headers, content=stream) as request:\n try:\n response = self._endpoint(request)\n status_line = f\"{request.method} {request.url.target} [{response.status_code} {response.reason_phrase}]\"\n logger.info(status_line)\n except Exception:\n logger.error(\"Internal Server Error\", exc_info=True)\n content = Text(\"Internal Server Error\")\n err = Response(code=500, content=content)\n self._send_head(err)\n self._send_body(err)\n else:\n self._send_head(response)\n self._send_body(response)\n except Exception:\n logger.error(\"Internal Server Error\", exc_info=True)\n\n def close(self):\n self._parser.close()\n\n # Receive the request...\n def _recv_head(self) -> tuple[str, str, list[tuple[str, str]]]:\n method, target, _ = self._parser.recv_method_line()\n m = method.decode('ascii')\n t = target.decode('ascii')\n headers = self._parser.recv_headers()\n h = [\n (k.decode('latin-1'), v.decode('latin-1'))\n for k, v in headers\n ]\n return m, t, h\n\n def _recv_body(self):\n return self._parser.recv_body()\n\n # Return the response. |
| 7 | run_command | {
"command": "sed -n '101,150p' src/httpx/_server.py"
} | {"status": "ok", "stdout": " while(True):\n sleep(1)\n\n\n@contextlib.contextmanager\ndef serve_http(endpoint):\n def handler(stream):\n connection = HTTPConnecfull{"status": "ok", "stdout": " while(True):\n sleep(1)\n\n\n@contextlib.contextmanager\ndef serve_http(endpoint):\n def handler(stream):\n connection = HTTPConnection(stream, endpoint)\n connection.handle_requests()\n\n logging.basicConfig(\n format=\"%(levelname)s [%(asctime)s] %(name)s - %(message)s\",\n datefmt=\"%Y-%m-%d %H:%M:%S\",\n level=logging.DEBUG\n )\n\n backend = NetworkBackend()\n with backend.serve(\"127.0.0.1\", 8080, handler) as server:\n server = HTTPServer(server.host, server.port)\n logger.info(f\"Serving on {server.url} (Press CTRL+C to quit)\")\n yield server\n\n\ndef run(app):\n with serve_http(app) as server:\n server.wait()\n", "stderr": "", "exit_code": 0} |
| 8 | run_command | {
"command": "grep -n \"KeyboardInterrupt\" src/httpx/_server.py"
} | {"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 9 | run_command | {
"command": "grep -rn \"KeyboardInterrupt\" src/httpx/"
} | {"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 10 | run_command | {
"command": "grep -rn \"KeyboardException\" src/httpx/"
} | {"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 11 | run_command | {
"command": "grep -rn \"Keyboard\" src/httpx/"
} | {"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 12 | run_command | {
"command": "grep -rn \"Keyboard\" src/ahttpx/"
} | {"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 13 | run_command | {
"command": "grep -rn \"Keyboard\" src/"
} | {"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 14 | run_command | {
"command": "grep -n \"def _complete\" src/httpx/_server.py"
} | {"status": "ok", "stdout": "91: def _complete(self):\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "91: def _complete(self):\n", "stderr": "", "exit_code": 0} |
| 15 | run_command | {
"command": "sed -n '91,93p' src/httpx/_server.py"
} | {"status": "ok", "stdout": " def _complete(self):\n self._parser.complete\n self._idle_expiry = time.monotonic() + self._keepalive_duration\n", "stderr": "", "efull{"status": "ok", "stdout": " def _complete(self):\n self._parser.complete\n self._idle_expiry = time.monotonic() + self._keepalive_duration\n", "stderr": "", "exit_code": 0} |
| 16 | run_command | {
"command": "grep -n \"def reset\" src/httpx/_parsers.py"
} | {"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 17 | run_command | {
"command": "grep -n \"def __init__\" src/httpx/_parsers.py"
} | {"status": "ok", "stdout": "86: def __init__(self, stream: Stream, mode: str) -> None:\n433: def __init__(self, stream: Stream) -> None:\n", "stderr": "", "exitfull{"status": "ok", "stdout": "86: def __init__(self, stream: Stream, mode: str) -> None:\n433: def __init__(self, stream: Stream) -> None:\n", "stderr": "", "exit_code": 0} |
| 18 | run_command | {
"command": "sed -n '72,100p' src/httpx/_parsers.py"
} | {"status": "ok", "stdout": "class HTTPParser:\n \"\"\"\n Usage...\n\n client = HTTPParser(writer, reader)\n client.send_method_line()\n client.send_headers()\n full{"status": "ok", "stdout": "class HTTPParser:\n \"\"\"\n Usage...\n\n client = HTTPParser(writer, reader)\n client.send_method_line()\n client.send_headers()\n client.send_body()\n client.recv_status_line()\n client.recv_headers()\n client.recv_body()\n client.complete()\n client.close()\n \"\"\"\n def __init__(self, stream: Stream, mode: str) -> None:\n self.stream = stream\n self.parser = ReadAheadParser(stream)\n self.mode = {'CLIENT': Mode.CLIENT, 'SERVER': Mode.SERVER}[mode]\n\n # Track state...\n if self.mode == Mode.CLIENT:\n self.send_state: State = State.SEND_METHOD_LINE\n self.recv_state: State = State.WAIT\n else:\n self.recv_state = State.RECV_METHOD_LINE\n self.send_state = State.WAIT\n\n # Track message framing...\n self.send_content_length: int | None = 0\n", "stderr": "", "exit_code": 0} |
| 19 | run_command | {
"command": "sed -n '378,400p' src/httpx/_parsers.py"
} | {"status": "ok", "stdout": " def complete(self):\n is_fully_complete = self.send_state == State.DONE and self.recv_state == State.DONE\n is_keepalive = self.senfull{"status": "ok", "stdout": " def complete(self):\n is_fully_complete = self.send_state == State.DONE and self.recv_state == State.DONE\n is_keepalive = self.send_keep_alive and self.recv_keep_alive\n\n if not (is_fully_complete and is_keepalive):\n self.close()\n return\n\n if self.mode == Mode.CLIENT:\n self.send_state = State.SEND_METHOD_LINE\n self.recv_state = State.WAIT\n else:\n self.recv_state = State.RECV_METHOD_LINE\n self.send_state = State.WAIT\n\n self.send_content_length = 0\n self.recv_content_length = 0\n self.send_seen_length = 0\n self.recv_seen_length = 0\n self.send_keep_alive = True\n self.recv_keep_alive = True\n self.processing_1xx = False\n\n", "stderr": "", "exit_code": 0} |
| 20 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"src/httpx/_parsers.py\")\ns = p.read_text()\nold = \"\"\" def complete(self):\"\"\"\nnew = \"\"\" def reset(self):\"\"\"\nt = s.replace(old, new)\np.write_text(t)\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 21 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"src/httpx/_server.py\")\ns = p.read_text()\nold = \"\"\" self._parser.complete\"\"\"\nnew = \"\"\" self._parser.reset()\"\"\"\nt = s.replace(old, new)\np.write_text(t)\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 22 | run_command | {
"command": "sed -n '30,60p' src/httpx/_server.py"
} | {"status": "ok", "stdout": "\n # API entry points...\n def handle_requests(self):\n try:\n while not self._parser.is_closed():\n method, url, headers = self._refull{"status": "ok", "stdout": "\n # API entry points...\n def handle_requests(self):\n try:\n while not self._parser.is_closed():\n method, url, headers = self._recv_head()\n stream = HTTPStream(self._recv_body, self._complete)\n # TODO: Handle endpoint exceptions\n with Request(method, url, headers=headers, content=stream) as request:\n try:\n response = self._endpoint(request)\n status_line = f\"{request.method} {request.url.target} [{response.status_code} {response.reason_phrase}]\"\n logger.info(status_line)\n except Exception:\n logger.error(\"Internal Server Error\", exc_info=True)\n content = Text(\"Internal Server Error\")\n err = Response(code=500, content=content)\n self._send_head(err)\n self._send_body(err)\n else:\n self._send_head(response)\n self._send_body(response)\n except Exception:\n logger.error(\"Internal Server Error\", exc_info=True)\n\n def close(self):\n self._parser.close()\n\n # Receive the request...\n def _recv_head(self) -> tuple[str, str, list[tuple[str, str]]]:\n method, target, _ = self._parser.recv_method_line()\n", "stderr": "", "exit_code": 0} |
| 23 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"src/httpx/_server.py\")\ns = p.read_text()\nold = \"\"\" except Exception:\"\"\"\nnew = \"\"\" except (Exception, KeyboardInterrupt):\"\"\"\nt = s.replace(old, new)\np.write_text(t)\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 24 | run_command | {
"command": "sed -n '101,130p' src/httpx/_server.py"
} | {"status": "ok", "stdout": " while(True):\n sleep(1)\n\n\n@contextlib.contextmanager\ndef serve_http(endpoint):\n def handler(stream):\n connection = HTTPConnecfull{"status": "ok", "stdout": " while(True):\n sleep(1)\n\n\n@contextlib.contextmanager\ndef serve_http(endpoint):\n def handler(stream):\n connection = HTTPConnection(stream, endpoint)\n connection.handle_requests()\n\n logging.basicConfig(\n format=\"%(levelname)s [%(asctime)s] %(name)s - %(message)s\",\n datefmt=\"%Y-%m-%d %H:%M:%S\",\n level=logging.DEBUG\n )\n\n backend = NetworkBackend()\n with backend.serve(\"127.0.0.1\", 8080, handler) as server:\n server = HTTPServer(server.host, server.port)\n logger.info(f\"Serving on {server.url} (Press CTRL+C to quit)\")\n yield server\n\n\ndef run(app):\n with serve_http(app) as server:\n server.wait()\n", "stderr": "", "exit_code": 0} |
| 25 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"src/httpx/_server.py\")\ns = p.read_text()\nold = \"\"\" with backend.serve(\"127.0.0.1\", 8080, handler) as server:\"\"\"\nnew = \"\"\" with backend.serve(\"127.0.0.1\", 8080, handler) as server:\n try:\"\"\"\n# This is not quite right, I need to wrap the yield.\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 26 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"src/httpx/_server.py\")\ns = p.read_text()\nold = \"\"\" with backend.serve(\"127.0.0.1\", 8080, handler) as server:\n server = HTTPServer(server.host, server.port)\n logger.info(f\"Serving on {server.url} (Press CTRL+C to quit)\")\n yield server\"\"\"\nnew = \"\"\" with backend.serve(\"127.0.0.1\", 8080, handler) as server:\n server = HTTPServer(server.host, server.port)\n logger.info(f\"Serving on {server.url} (Press CTRL+C to quit)\")\n try:\n yield server\n finally:\n server.close()\"\"\"\nt = s.replace(old, new)\np.write_text(t)\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 27 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"src/httpx/_parsers.py\")\ns = p.read_text()\n# Add keep_alive property to HTTPParser\n# It should return whether the connection should be kept alive.\n# Based on the problem statement \"Add HTTPParser.keep_alive\".\n# Looking at the code, it has send_keep_alive and recv_keep_alive.\n\n# Let's see where to add it.\n# Maybe after __init__?\n\n# I'll add a property keep_alive that returns send_keep_alive and recv_keep_alive.\n# Wait, usually keep_alive on a parser means \"is this connection still alive/should it be\".\n\n# Let's check if there is any other place where keep_alive is used.\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 28 | run_command | {
"command": "grep -rn \"keep_alive\" src/httpx/_parsers.py"
} | {"status": "ok", "stdout": "src/httpx/_parsers.py:106: self.send_keep_alive = True\nsrc/httpx/_parsers.py:107: self.recv_keep_alive = True\nsrc/httpx/_parsers.pfull{"status": "ok", "stdout": "src/httpx/_parsers.py:106: self.send_keep_alive = True\nsrc/httpx/_parsers.py:107: self.recv_keep_alive = True\nsrc/httpx/_parsers.py:179: self.send_keep_alive = False\nsrc/httpx/_parsers.py:316: self.recv_keep_alive = False\nsrc/httpx/_parsers.py:380: is_keepalive = self.send_keep_alive and self.recv_keep_alive\nsrc/httpx/_parsers.py:397: self.send_keep_alive = True\nsrc/httpx/_parsers.py:398: self.recv_keep_alive = True\n", "stderr": "", "exit_code": 0} |
| 29 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"src/httpx/_parsers.py\")\ns = p.read_text()\n# Find a good place to insert the property. After __init__.\n# __init__ ends around line 110.\n\n# Let's find the end of __init__\nimport re\nmatch = re.search(r'def __init__\\(self, stream: Stream, mode: str\\) -> None:.*?(\\n\\s*\\n)', s, re.DOTALL)\n# That's not reliable.\n\n# Let's just insert it before send_method_line.\n# send_method_line starts at line 113.\n\n# I'll use a simpler replacement.\nold = \"\"\" def send_method_line(self, method: bytes, target: bytes, protocol: bytes) -> None:\"\"\"\nnew = \"\"\" @property\n def keep_alive(self) -> bool:\n return self.send_keep_alive and self.recv_keep_alive\n\n def send_method_line(self, method: bytes, target: bytes, protocol: bytes) -> None:\"\"\"\nt = s.replace(old, new)\np.write_text(t)\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 30 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"src/httpx/_server.py\")\ns = p.read_text()\n# \"Server... always read request to completion on keep alives.\"\n# This means in handle_requests, we should ensure the body is read even if we don't use it.\n\n# Current handle_requests:\n# while not self._parser.is_closed():\n# method, url, headers = self._recv_head()\n# stream = HTTPStream(self._recv_body, self._complete)\n# with Request(method, url, headers=headers, content=stream) as request:\n# ...\n\n# The Request context manager should handle reading the body to completion if it's not already read.\n# But let's check Request implementation.\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 31 | run_command | {
"command": "grep -rn \"class Request\" src/httpx/"
} | {"status": "ok", "stdout": "src/httpx/_request.py:12:class Request:\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "src/httpx/_request.py:12:class Request:\n", "stderr": "", "exit_code": 0} |
| 32 | run_command | {
"command": "sed -n '12,60p' src/httpx/_request.py"
} | {"status": "ok", "stdout": "class Request:\n def __init__(\n self,\n method: str,\n url: URL | str,\n headers: Headers | typing.Mapping[str, str] | None = None,full{"status": "ok", "stdout": "class Request:\n def __init__(\n self,\n method: str,\n url: URL | str,\n headers: Headers | typing.Mapping[str, str] | None = None,\n content: Content | Stream | bytes | None = None,\n ):\n self.method = method\n self.url = URL(url)\n self.headers = Headers(headers)\n self.stream: Stream = ByteStream(b\"\")\n\n # https://datatracker.ietf.org/doc/html/rfc2616#section-14.23\n #\u00a0RFC 2616, Section 14.23, Host.\n #\n # A client MUST include a Host header field in all HTTP/1.1 request messages.\n if \"Host\" not in self.headers:\n self.headers = self.headers.copy_set(\"Host\", self.url.netloc)\n\n if content is not None:\n if isinstance(content, bytes):\n self.stream = ByteStream(content)\n elif isinstance(content, Stream):\n self.stream = content\n elif isinstance(content, Content):\n ct = content.content_type()\n self.stream = content.encode()\n self.headers = self.headers.copy_set(\"Content-Type\", ct)\n else:\n raise TypeError(f'Expected `Content | Stream | bytes | None` got {type(content)}')\n\n # https://datatracker.ietf.org/doc/html/rfc2616#section-4.3\n #\u00a0RFC 2616, Section 4.3, Message Body.\n #\n # The presence of a message-body in a request is signaled by the\n # inclusion of a Content-Length or Transfer-Encoding header field in\n # the request's message-headers.\n content_length: int | None = self.stream.size\n if content_length is None:\n self.headers = self.headers.copy_set(\"Transfer-Encoding\", \"chunked\")\n elif content_length > 0:\n self.headers = self.headers.copy_set(\"Content-Length\", str(content_length))\n\n elif method in (\" |
| 33 | run_command | {
"command": "sed -n '61,100p' src/httpx/_request.py"
} | {"status": "ok", "stdout": " # Transfer-Encoding is sent and the request method defines a meaning for\n # an enclosed payload body. For example, a Content-Lengtfull{"status": "ok", "stdout": " # Transfer-Encoding is sent and the request method defines a meaning for\n # an enclosed payload body. For example, a Content-Length header field is\n # normally sent in a POST request even when the value is 0.\n # (indicating an empty payload body).\n self.headers = self.headers.copy_set(\"Content-Length\", \"0\")\n\n @property\n def body(self) -> bytes:\n if not hasattr(self, '_body'):\n raise RuntimeError(\"'.body' cannot be accessed without calling '.read()'\")\n return self._body\n\n def read(self) -> bytes:\n if not hasattr(self, '_body'):\n self._body = self.stream.read()\n self.stream = ByteStream(self._body)\n return self._body\n\n def close(self) -> None:\n self.stream.close()\n\n def __enter__(self):\n return self\n\n def __exit__(self,\n exc_type: type[BaseException] | None = None,\n exc_value: BaseException | None = None,\n traceback: types.TracebackType | None = None\n ):\n self.close()\n\n def __repr__(self):\n return f\"<Request [{self.method} {str(self.url)!r}]>\"\n", "stderr": "", "exit_code": 0} |
| 34 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"src/httpx/_request.py\")\ns = p.read_text()\nold = \"\"\" def close(self) -> None:\n self.stream.close()\"\"\"\nnew = \"\"\" def close(self) -> None:\n try:\n self.stream.read()\n except Exception:\n pass\n self.stream.close()\"\"\"\n# Wait, if it's already read, read() might return empty bytes.\n# But if it's a Stream, we should read it to completion.\n# Let's check if self.stream.read() reads everything.\n# In src/httpx/_streams.py, Stream.read() probably reads everything if no size is given.\nt = s.replace(old, new)\np.write_text(t)\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 35 | run_command | {
"command": "sed -n '1,50p' src/httpx/_streams.py"
} | {"status": "ok", "stdout": "import io\nimport typing\nimport types\nimport os\n\n\nclass Stream:\n def read(self, size: int=-1) -> bytes:\n raise NotImplementedfull{"status": "ok", "stdout": "import io\nimport typing\nimport types\nimport os\n\n\nclass Stream:\n def read(self, size: int=-1) -> bytes:\n raise NotImplementedError()\n\n def write(self, data: bytes) -> None:\n raise NotImplementedError()\n\n def close(self) -> None:\n raise NotImplementedError()\n\n @property\n def size(self) -> int | None:\n return None\n\n def __enter__(self):\n return self\n\n def __exit__(\n self,\n exc_type: type[BaseException] | None = None,\n exc_value: BaseException | None = None,\n traceback: types.TracebackType | None = None\n ):\n self.close()\n\n\nclass ByteStream(Stream):\n def __init__(self, data: bytes = b''):\n self._buffer = io.BytesIO(data)\n self._size = len(data)\n\n def read(self, size: int=-1) -> bytes:\n return self._buffer.read(size)\n\n def close(self) -> None:\n self._buffer.close()\n\n @property\n def size(self) -> int | None:\n return self._size\n\n\nclass DuplexStream(Stream):\n \"\"\"\n", "stderr": "", "exit_code": 0} |
| 36 | run_command | {
"command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"src/httpx/_request.py\")\ns = p.read_text()\nold = \"\"\" def close(self) -> None:\n try:\n self.stream.read()\n except Exception:\n pass\n self.stream.close()\"\"\"\nnew = \"\"\" def close(self) -> None:\n try:\n while self.stream.read(64 * 1024):\n pass\n except Exception:\n pass\n self.stream.close()\"\"\"\n# Actually, if it's a ByteStream, read() without size reads everything.\n# But if it's a custom Stream (like the one in HTTPConnection), it might be different.\n# Let's use a loop to be safe.\nt = s.replace(old, new)\np.write_text(t)\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 37 | run_command | {
"command": "git diff"
} | {"status": "ok", "stdout": "diff --git a/src/httpx/_parsers.py b/src/httpx/_parsers.py\nindex 830fccd..4069551 100644\n--- a/src/httpx/_parsers.py\n+++ b/src/htfull{"status": "ok", "stdout": "diff --git a/src/httpx/_parsers.py b/src/httpx/_parsers.py\nindex 830fccd..4069551 100644\n--- a/src/httpx/_parsers.py\n+++ b/src/httpx/_parsers.py\n@@ -109,6 +109,10 @@ class HTTPParser:\n # Special states...\n self.processing_1xx = False\n \n+ @property\n+ def keep_alive(self) -> bool:\n+ return self.send_keep_alive and self.recv_keep_alive\n+\n def send_method_line(self, method: bytes, target: bytes, protocol: bytes) -> None:\n \"\"\"\n Send the initial request line:\n@@ -375,7 +379,7 @@ class HTTPParser:\n self.recv_state = State.DONE\n return body\n \n- def complete(self):\n+ def reset(self):\n is_fully_complete = self.send_state == State.DONE and self.recv_state == State.DONE\n is_keepalive = self.send_keep_alive and self.recv_keep_alive\n \ndiff --git a/src/httpx/_request.py b/src/httpx/_request.py\nindex 1b739b1..fa4b2fa 100644\n--- a/src/httpx/_request.py\n+++ b/src/httpx/_request.py\n@@ -77,6 +77,11 @@ class Request:\n return self._body\n \n def close(self) -> None:\n+ try:\n+ while self.stream.read(64 * 1024):\n+ pass\n+ except Exception:\n+ pass\n self.stream.close()\n \n def __enter__(self):\ndiff --git a/src/httpx/_server.py b/src/httpx/_server.py\nindex 95226d9..4edf648 100644\n--- a/src/httpx/_server.py\n+++ b/src/httpx/_server.py\n@@ -40,7 +40,7 @@ class HTTPConnection:\n response = self._endpoint(request)\n status_line = f\"{request.method} {request.url.target} [{response.status_code} {response.reason_phrase}]\"\n logger.info(status_line)\n- except Exception:\n+ except (Exception, KeyboardInterrupt):\n logger.error(\"Internal Server Error\", exc_info=True)\n content = Text(\"Internal Server Error\")\n |
| 38 | run_command | {
"command": "submit_patch"
} | {"status": "error", "error_type": "CommandError", "error_message": "/bin/bash: submit_patch: command not found\n", "details": {"stdout": "", "stderr": "/bin/basfull{"status": "error", "error_type": "CommandError", "error_message": "/bin/bash: submit_patch: command not found\n", "details": {"stdout": "", "stderr": "/bin/bash: submit_patch: command not found\n", "exit_code": 127}} |
| 39 | submit_patch | {} | {"status": "ok", "patch_size": 2914, "files_changed": 3}full{"status": "ok", "patch_size": 2914, "files_changed": 3} |
diff --git a/src/httpx/_parsers.py b/src/httpx/_parsers.py
index 830fccd..4069551 100644
--- a/src/httpx/_parsers.py
+++ b/src/httpx/_parsers.py
@@ -109,6 +109,10 @@ class HTTPParser:
# Special states...
self.processing_1xx = False
+ @property
+ def keep_alive(self) -> bool:
+ return self.send_keep_alive and self.recv_keep_alive
+
def send_method_line(self, method: bytes, target: bytes, protocol: bytes) -> None:
"""
Send the initial request line:
@@ -375,7 +379,7 @@ class HTTPParser:
self.recv_state = State.DONE
return body
- def complete(self):
+ def reset(self):
is_fully_complete = self.send_state == State.DONE and self.recv_state == State.DONE
is_keepalive = self.send_keep_alive and self.recv_keep_alive
diff --git a/src/httpx/_request.py b/src/httpx/_request.py
index 1b739b1..fa4b2fa 100644
--- a/src/httpx/_request.py
+++ b/src/httpx/_request.py
@@ -77,6 +77,11 @@ class Request:
return self._body
def close(self) -> None:
+ try:
+ while self.stream.read(64 * 1024):
+ pass
+ except Exception:
+ pass
self.stream.close()
def __enter__(self):
diff --git a/src/httpx/_server.py b/src/httpx/_server.py
index 95226d9..4edf648 100644
--- a/src/httpx/_server.py
+++ b/src/httpx/_server.py
@@ -40,7 +40,7 @@ class HTTPConnection:
response = self._endpoint(request)
status_line = f"{request.method} {request.url.target} [{response.status_code} {response.reason_phrase}]"
logger.info(status_line)
- except Exception:
+ except (Exception, KeyboardInterrupt):
logger.error("Internal Server Error", exc_info=True)
content = Text("Internal Server Error")
err = Response(code=500, content=content)
@@ -49,7 +49,7 @@ class HTTPConnection:
else:
self._send_head(response)
self._send_body(response)
- except Exception:
+ except (Exception, KeyboardInterrupt):
logger.error("Internal Server Error", exc_info=True)
def close(self):
@@ -89,7 +89,7 @@ class HTTPConnection:
# Start it all over again...
def _complete(self):
- self._parser.complete
+ self._parser.reset()
self._idle_expiry = time.monotonic() + self._keepalive_duration
@@ -118,7 +118,10 @@ def serve_http(endpoint):
with backend.serve("127.0.0.1", 8080, handler) as server:
server = HTTPServer(server.host, server.port)
logger.info(f"Serving on {server.url} (Press CTRL+C to quit)")
- yield server
+ try:
+ yield server
+ finally:
+ server.close()
def run(app):
........................ [100%] 24 passed in 0.05s