Reputation: 101
I have a Python (2.7.13) HTTP Server running in Debian, I want to stop any GET request that takes longer than 10 seconds, but can't find a solution anywhere.
I already tried all the snippets posted in the following question: How to implement Timeout in BaseHTTPServer.BaseHTTPRequestHandler Python
#!/usr/bin/env python
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os
class handlr(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text-html')
self.end_headers()
self.wfile.write(os.popen('sleep 20 & echo "this took 20 seconds"').read())
def run():
server_address = ('127.0.0.1', 8080)
httpd = HTTPServer(server_address, handlr)
httpd.serve_forever()
if __name__ == '__main__':
run()
As a test, I'm running a shell command that takes 20 seconds to execute, so I need the server stop before that.
Upvotes: 3
Views: 3392
Reputation: 1661
Put your operation on a background thread, and then wait for your background thread to finish. There isn't a general-purpose safe way to abort threads, so this implementation unfortunately leaves the function running in the background even though it had already given up.
If you can, you might consider putting a proxy server (like say nginx
) in front of your server and let it handle timeouts for you, or perhaps use a more robust HTTP server implementation that allows this as a configuration option. But the answer below should basically cover it.
#!/usr/bin/env python
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os
import threading
class handlr(BaseHTTPRequestHandler):
def do_GET(self):
result, succeeded = run_with_timeout(lambda: os.popen('sleep 20 & echo "this took 20 seconds"').read(), timeout=3)
if succeeded:
self.send_response(200)
self.send_header('Content-type','text-html')
self.end_headers()
self.wfile.write(os.popen('sleep 20 & echo "this took 20 seconds"').read())
else:
self.send_response(500)
self.send_header('Content-type','text-html')
self.end_headers()
self.wfile.write('<html><head></head><body>Sad panda</body></html>')
self.wfile.close()
def run():
server_address = ('127.0.0.1', 8080)
httpd = HTTPServer(server_address, handlr)
httpd.serve_forever()
def run_with_timeout(fn, timeout):
lock = threading.Lock()
result = [None, False]
def run_callback():
r = fn()
with lock:
result[0] = r
result[1] = True
t = threading.Thread(target=run_callback)
t.daemon = True
t.start()
t.join(timeout)
with lock:
return tuple(result)
if __name__ == '__main__':
run()
Upvotes: 1