Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SimpleHTTPRequestHandler close connection before returning from do_POST method

Tags:

python

I'm writing a simple webserver in python. here follows a simplified version of my code:

class StreamerHandler(SimpleHTTPRequestHandler):
    def do_POST(self):
        try:
            length = int(self.headers.getheader('content-length'))
            data = self.rfile.read(length)
            self.send_response(200, "OK")
            #process_data(data, self.client_address)
        except Exception as inst:
            logging.error(type(self).__name__ + "/"  + type(inst).__name__ + " (" + inst.__str__() + ")")

class Streamer(TCPServer):
    def __init__(self, overlay):
        self.allow_reuse_address = True
        TCPServer.__init__(self, ("", port), StreamerHandler)

What I would like to do is to send the response close the TCP connection and then run the process_data method which may take a long time to complete.

Is there way to achieve this? The only solution I can think is to use a dedicated thread to handle the processing.

like image 229
Roberto Avatar asked Jul 06 '11 09:07

Roberto


2 Answers

I tried it out, you actually need both commands (in order) to close it: self.finish() self.connection.close()

like image 88
pomelole Avatar answered Sep 21 '22 23:09

pomelole


So, SimpleHTTPRequestHandler inherits from BaseHTTPServer.BaseHTTPRequestHandler, which in turn inherits from SocketServer.StreamRequestHandler.

In SocketServer.StreamRequestHandler, the rfile and wfile pseudo files get created in the setup() method from the socket object (known as self.connection):

def setup(self):
    self.connection = self.request
    if self.timeout is not None:
        self.connection.settimeout(self.timeout)
    if self.disable_nagle_algorithm:
        self.connection.setsockopt(socket.IPPROTO_TCP,
                                   socket.TCP_NODELAY, True)
    self.rfile = self.connection.makefile('rb', self.rbufsize)
    self.wfile = self.connection.makefile('wb', self.wbufsize)

The socket self.connection is still available to you, so you could call self.connection.close() to close it. However, the wfile pseudo-file might have buffered data inside it which could be lost, so you could/should instead call self.finish(), also defined in SocketServer.StreamRequestHandler:

def finish(self):
    if not self.wfile.closed:
        self.wfile.flush()
    self.wfile.close()
    self.rfile.close()

So, I think the following should work (untested):

class StreamerHandler(SimpleHTTPRequestHandler):
    def do_POST(self):
        try:
            length = int(self.headers.getheader('content-length'))
            data = self.rfile.read(length)
            self.send_response(200, "OK")
            self.finish()
            process_data(data, self.client_address)
        except Exception as exc:
            logging.error(
                "{0}/{1}({2})".format(
                    type(self).__name__, type(exc).__name__, str(exc)))
like image 28
Matt Anderson Avatar answered Sep 21 '22 23:09

Matt Anderson