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