Created
February 1, 2024 09:15
-
-
Save wfrisch/63d1163645fa01e3ab1296e752769359 to your computer and use it in GitHub Desktop.
Deliberately broken HTTP server that responds with either a) false Content-Length or b) broken chunked encoding
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Deliberately broken HTTP server that responds with either | |
- false Content-Length | |
- broken chunked encoding | |
both triggering ChunkedEncodingError in clients using `python-requests`: | |
- ChunkedEncodingError: Connection broken: IncompleteRead | |
- ChunkedEncodingError: Connection broken: InvalidChunkLength | |
""" | |
from http.server import BaseHTTPRequestHandler, HTTPServer | |
class BrokenHandler(BaseHTTPRequestHandler): | |
def do_GET(self): | |
routes = { | |
"/invalid-chunk-length": self.respond_invalid_chunk_length, | |
"/invalid-content-length": self.respond_invalid_content_length | |
} | |
if self.path in routes: | |
routes[self.path]() | |
else: | |
self.send_error(404, "Path not found.") | |
def respond_invalid_content_length(self): | |
content = "Hello, World!" | |
content_length = len(content) + 10 # error | |
self.send_response(200) | |
self.send_header('Content-Type', 'text/plain') | |
self.send_header('Content-Length', str(content_length)) | |
self.end_headers() | |
self.wfile.write(content.encode()) | |
def respond_invalid_chunk_length(self): | |
content = "Hello, World!" | |
self.send_response(200) | |
self.send_header('Content-type', 'text/plain') | |
self.send_header('Transfer-Encoding', 'chunked') | |
self.end_headers() | |
self.wfile.write(f"{len(content):X}\r\n".encode()) | |
self.wfile.write(f"{content}\r\n".encode()) | |
# erroneously omit the terminator chunk | |
# self.wfile.write(b"0\r\n\r\n") | |
def run(server_class=HTTPServer, handler_class=BrokenHandler, | |
port=8080): | |
server_address = ('', port) | |
httpd = server_class(server_address, handler_class) | |
print(f"Starting faulty HTTP server on port {port}...") | |
try: | |
httpd.serve_forever() | |
except KeyboardInterrupt: | |
pass | |
httpd.server_close() | |
if __name__ == '__main__': | |
run() | |
# vim:set expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment