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