ActiveState Powered by ActiveState

Recipe 336012: Stoppable HTTP server


Starting a SimpleHTTPServer instance in a separate thread makes it run forever. To solve this problem the server is augmented with a QUIT command. If sent it makes the server stop serving requests.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import SimpleHTTPServer, BaseHTTPServer, httplib

class StoppableHttpRequestHandler (SimpleHTTPServer.SimpleHTTPRequestHandler):
    """http request handler with QUIT stopping the server"""

    def do_QUIT (self):
        """send 200 OK response, and set server.stop to True"""
        self.send_response(200)
        self.end_headers()
        self.server.stop = True


class StoppableHttpServer (BaseHTTPServer.HTTPServer):
    """http server that reacts to self.stop flag"""

    def serve_forever (self):
        """Handle one request at a time until stopped."""
        self.stop = False
        while not self.stop:
            self.handle_request()

def stop_server (port):
    """send QUIT request to http server running on localhost:<port>"""
    conn = httplib.HTTPConnection("localhost:%d" % port)
    conn.request("QUIT", "/")
    conn.getresponse()

Discussion

I use this in a functional test suite to start and stop HTTP servers in separate threads in the background. Then the test routines can access and run tests with the HTTP server. For a complete example see http://cvs.sourceforge.net/viewcvs.py/linkchecker/linkchecker/linkcheck/ftests/httptest.py?view=markup

Comments

  1. 1. At 12:46 a.m. on 19 nov 2004, Jiri Barton said:

    Anonymous port. I have several questions and/or suggestions.

    I have been wondering about the way you use this server in httptest.start_server().

    For test suites, I'd like to be able to run the server that can bind to the port that OS will assign. I mean using the fixed port number in the test suites is not safe. So, I will need to pass the port 0 (that does the trick). However, then I need to know which port the OS has given to the server in order to stop it: I need to access the server instance.

    Given the fact I had the server instance, I could use another technique to prevent the server from getting stuck. I could wait for a fixed amount of time (e.g. 10secs) and then kill it with server_instance.socket.close().

    Or, this might be a completely different use case, please comment.

  2. 2. At 3:42 a.m. on 23 nov 2004, Bastian Kleineidam said:

    Re: port and stop questions. Yes, the HTTP port in this example is fixed. I think finding a free port and using it is a different problem and is subject for other recipes ;) For unit test suites the port number could also be given as a command line parameter.

    As to your stop suggestion: accessing the server instance outside of the HTTP server thread needs thread locking which I wanted to avoid. But yes it would be possible.

    Another problem in the example is how to tell if the HTTP server is started. I just wait for a couple of seconds and assume it is there. A clean approach would be using the waitfor module at http://www.hennessynet.com/waitfor/.

Sign in to comment