harden against DoS crashes and raise concurrency defaults
Security/robustness fixes for running on public networks:
- reject deeply nested JSON with 400 instead of crashing the event loop (json.loads raises RecursionError, a RuntimeError subclass, which was neither ValueError nor ClientError and propagated out of wait())
- close the WebSocket on send-buffer overflow during auto-pong instead of letting OSError escape the loop (ping flood / dead consumer)
- tolerate custom/unknown response status codes via STATUS_CODES.get() instead of raising KeyError
Defaults tuned for public-facing use:
- MAX_WAITING_CLIENTS 5 -> 32 (browsers open ~6 connections each)
- listen backlog 2 -> 8
Docs:
- sync README kwargs defaults with code (keep_alive_timeout 30->15, max_waiting_clients, add request_timeout/file_chunk_size/listen)
- warn about path traversal in respond_file (README + docstring)
- add TODO: distinguish waiting vs active connections in _accept eviction
Add tests/test_dos_hardening.py covering the three crash fixes.