http.server: HTTP/1.1 requests without Host, with two Host fields or with an invalid Host value are accepted

未關閉
#161,675 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 1 天內回覆

還沒有人認領這個 Issue。

評估

難度
3/5
預估耗時
1-2 天
新手友好度
35/100
Issue 類型
缺陷
描述清晰度
描述清楚
活躍度
停滯
技術堆疊
python

研究方向

Start with BaseHTTPRequestHandler.parse_request and trace how it handles HTTP/1.1 headers. The report’s three examples define the cases to check: missing Host, duplicate Host fields, and an invalid Host value. Done means each case receives a 400 Bad Request; note that the issue body references linked PR gh-161696.

由索引模型根據 Issue 內容生成。

描述

stdlib type-bug
Bug report

BaseHTTPRequestHandler.parse_request does not look at the Host field. RFC 9112 section 3.2 states: "A server MUST respond with a 400 (Bad Request) status code to any HTTP/1.1 request message that lacks a Host header field and to any request message that contains more than one Host header field line or a Host header field with an invalid field value."

All three kinds of request below get status 200 and reach the handler. The 400 for a missing Host is from RFC 2616 section 14.23; the 400 for duplicate or invalid Host values was added in RFC 7230 section 5.4 (2014).

import http.server, socket, threading

class Handler(http.server.BaseHTTPRequestHandler):
    protocol_version = "HTTP/1.1"
    def do_GET(self):
        body = ("Host: %r\n" % self.headers.get_all("Host")).encode()
        self.send_response(200)
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)
    def log_message(self, *args): pass

server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), Handler)
threading.Thread(target=server.serve_forever, daemon=True).start()

for request in [b"GET / HTTP/1.1\r\n\r\n",
                b"GET / HTTP/1.1\r\nHost: a.example\r\nHost: b.example\r\n\r\n",
                b"GET / HTTP/1.1\r\nHost: a b\r\n\r\n"]:
    with socket.create_connection(server.server_address, timeout=2) as s:
        s.sendall(request)
        s.shutdown(socket.SHUT_WR)
        lines = s.makefile("rb").read().split(b"\r\n")
    print(request, "->", lines[0], lines[-1])
server.shutdown()

Output:

b'GET / HTTP/1.1\r\n\r\n' -> b'HTTP/1.1 200 OK' b'Host: None\n'
b'GET / HTTP/1.1\r\nHost: a.example\r\nHost: b.example\r\n\r\n' -> b'HTTP/1.1 200 OK' b"Host: ['a.example', 'b.example']\n"
b'GET / HTTP/1.1\r\nHost: a b\r\n\r\n' -> b'HTTP/1.1 200 OK' b"Host: ['a b']\n"

Expected: HTTP/1.1 400 Bad Request for all three requests.

CPython versions tested on:

3.14

Operating systems tested on:

Linux

Linked PRs
  • gh-161696
主要語言
Python
星號
78.2k
分支
36.6k
平均合併
19 小時 57 分鐘
30 天內合併 PR
630

環境準備

在 Codespaces 中開啟

在瀏覽器裡用你自己的 GitHub 帳號啟動這個專案的開發容器。

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

python/cpython 的其他 Issue

查看 python/cpython 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。