Welcome, guest | Sign In | My Account | Store | Cart

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, 26 lines
 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()

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

2 comments

Jiri Barton 17 years ago  # | flag

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.

Bastian Kleineidam 17 years ago  # | flag

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/.