fix: suppress error log for unsupported HTTP methods (HEAD, POST, etc.)#1727
fix: suppress error log for unsupported HTTP methods (HEAD, POST, etc.)#1727lennney wants to merge 2 commits into
Conversation
Change the unsupported-method exception in http11.py from ValueError to InvalidHandshake to better describe the error. In the asyncio and sync server handshake methods, suppress the re-raise when the parse failure was caused by an unsupported HTTP method — the connection is already being closed cleanly by send_eof() and logging an ERROR is noisy but not actionable. Closes python-websockets#1677
|
Earlier commit (3a6ee61) suppressed the error log but still just closed the connection — the client never got an HTTP response. This adds one. gorilla/websocket returns StatusMethodNotAllowed and ws returns 405 abortHandshake for the same case. Putting the check in ServerProtocol.parse() after the InvalidHandshake exception matches that pattern: parse() is the single entry point, same place gorilla's Upgrade() and ws's handleUpgrade() do their method check. Reuses the existing reject() / send_response() helpers, so the change is 4 lines of new logic in server.py.
|
Follow-up to 3a6ee61 — the earlier commit suppressed the error log but I looked at how gorilla/websocket and ws handle this — both return 405 The check goes after the existing InvalidHandshake exception handler so |
|
Look, I'm not interested in talking with an AI over GitHub comments; if I want to use Claude Code, I'll use it directly. |
Closes #1677.
Problem
When a non-GET HTTP request (HEAD, POST, OPTIONS, etc.) hits a websockets
server, it causes a noisy
ERROR opening handshake failedlog with fulltraceback. The connection is already being closed cleanly, so the error log
is misleading but not actionable.
What #1684 got right and wrong
PR #1684 correctly identified the fix but was rejected for calling
reject()from the low-level parser — a layering violation as noted by@aaugustin. The problem is real and affects production servers that get
hit by bots and health checkers.
This fix
http11.py: Change the unsupported-method exception from genericValueErrortoInvalidHandshake— semantically accurate since anunsupported method IS an invalid handshake.
asyncio/server.py+sync/server.py: Inhandshake(), suppressthe re-raise when
handshake_excis anInvalidMessagecaused by anInvalidHandshake. The connection is already being closed cleanly bysend_eof()— re-raising only causes anERRORlog that's noise.Test update:
test_parse_unsupported_methodnow expectsInvalidHandshakeinstead ofValueError.What's NOT changed
HELO) still producesInvalidMessagewithoutInvalidHandshakeas cause → still logged as ERROR (security-relevant)400 BAD_REQUESTfor all handshake failurescleanly, same as before — just no ERROR log)
Testing
tests/test_http11.py: 98 passedtests/test_server.py: all handshake tests passedtests/asyncio/test_server.py:test_junk_handshakestill logs ERROR(junk data), HEAD/OPTIONS logged at DEBUG