HTTP server hangs while accepting packets

http, python

Solution

I completely rewrote my solution in order to fix two disadvantages:

- It can treat timeout even if client has opened only a connection but did not start communicate.

- If the client opens a connection, a new server process is forked. A slow client can not block other.

It is based on your code as most as possible. It is now a complete independent demo. If you open a browser on http://localhost:8000/ and write 'simulate error' to form and press submit, it simulates runtime error.

from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ForkingMixIn
from urllib.parse import parse_qs


class MyHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        ctype, pdict = self.headers.get_params(header='content-type')[0]
        postvars = {}
        try:
            if ctype == 'application/x-www-form-urlencoded':
                length = int(self.headers['content-length'])
                postvars = parse_qs(self.rfile.read(length), keep_blank_values=1
                                    encoding='utf-8')
                assert postvars.get('foo', '') != ['bar']  # can simulate error
            body = 'Something\n'.encode('ascii')
            self.send_response(200)
            self.send_header("Content-type", "text")
            self.send_header("Content-length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)
        except Exception:
            self.send_error(500)
            raise

    def do_GET(self):
        # demo for testing POST by web browser - without valid html
        body = ('Something\n<form method="post" action="http://%s:%d/">\n'
                '<input name="foo" type="text"><input type="submit"></form>\n'
                % self.server.server_address).encode('ascii')
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.send_header("Content-length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)


class ForkingHTTPServer(ForkingMixIn, HTTPServer):
    def finish_request(self, request, client_address):
        request.settimeout(30)
        # "super" can not be used because BaseServer is not created from object
        HTTPServer.finish_request(self, request, client_address)


def httpd(handler_class=MyHandler, server_address=('localhost', 8000)):
    try:
        print("Server started")
        srvr = ForkingHTTPServer(server_address, handler_class)
        srvr.serve_forever()  # serve_forever
    except KeyboardInterrupt:
        srvr.socket.close()


if __name__ == "__main__":
    httpd()

Forking can be disabled for e.g. debugging purposes by removing class `SocketServer.ForkingMixIn` from code.

EDIT Updated for Python 3, but a warning from Python 3 docs should be noted:

Warning: http.server is not recommended for production. It only implements basic security checks.

Problem

I have written a simple http server to handle POST requests: ``` class MyHandler( BaseHTTPServer.BaseHTTPRequestHandler): def do_POST( self ): ctype, pdict = cgi.parse_header(self.headers.getheader('content-type')) postvars = {} try: if ctype == 'application/x-www-form-urlencoded': length = int(self.headers.getheader('content-length')) postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1) self.send_response( 200 ) self.send_header( "Content-type", "text") self.send_header( "Content-length", str(len(body)) ) self.end_headers() self.wfile.write(body) except: print "Error" def httpd(handler_class=MyHandler, server_address = ('2.3.4.5', 80)): try: print "Server started" srvr = BaseHTTPServer.HTTPServer(server_address, handler_class) srvr.serve_forever() # serve_forever except KeyboardInterrupt: server.socket.close() if __name__ == "__main__": httpd( ) ``` The server runs fine but sometimes it just hangs. When I press CTRL+C it gives the following error and then continues receiving data: ``` Exception happened during processing of request from ('1.1.1.2', 50928) Traceback (most recent call last): File "/usr/lib/python2.6/SocketServer.py", line 281, in _handle_request_noblock self.process_request(request, client_address) File "/usr/lib/python2.6/SocketServer.py", line 307, in process_request self.finish_request(request, client_address) File "/usr/lib/python2.6/SocketServer.py", line 320, in finish_request self.RequestHandlerClass(request, client_address, self) File "/usr/lib/python2.6/SocketServer.py", line 615, in __init__ self.handle() File "/usr/lib/python2.6/BaseHTTPServer.py", line 329, in handle self.handle_one_request() File "/usr/lib/python2.6/BaseHTTPServer.py", line 312, in handle_one_request self.raw_requestline = self.rfile.readline() File "/usr/lib/python2.6/socket.py", line 406, in readline data = self._sock.recv(self._rbufsize) KeyboardInterrupt ``` Can someone tell me how to correct this? I can't make sense of the errors.

Original source