pvd
pvd

Reputation: 1343

How to drop request in tornado?

In order to test my client, I want to make some of the HTTP request sent by my client doesn't get any response.

For example, I want every request should have cookie topsession, if not, no response.

class EchoHandler(tornado.web.RequestHandler):
    def get(self):
        if not self.get_cookie("topsession"):
            ###TODO
        else:
            self.write("0")

Upvotes: 2

Views: 1193

Answers (2)

kwarunek
kwarunek

Reputation: 12587

The request's underlying connection can be closed explicitly

import tornado.ioloop
import tornado.web
from tornado.gen import coroutine

class MainHandler(tornado.web.RequestHandler):

    @coroutine
    def get(self):
        self.request.connection.close()

if __name__ == "__main__":
    application = tornado.web.Application([
        (r"/", MainHandler),
    ])
    application.listen(8888)
    tornado.ioloop.IOLoop.current().start()

And the test with curl:

curl http://localhost:8888/ -v
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8888 (#0)
> GET / HTTP/1.1
> Host: localhost:8888
> User-Agent: curl/7.47.0
> Accept: */*
> 
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server

The above code closes connection with FIN-flow and leaves the response empty. If you require to drop connection with reset - RST you can force it. Just set SO_LINGER for the connection's socket. You may consider the api as public since there is no _, but... it's kind a internal stuff (implementation dependent) of Tornado.

import socket
import struct
import tornado.ioloop
import tornado.web
from tornado.gen import coroutine

class MainHandler(tornado.web.RequestHandler):

    @coroutine
    def get(self):
        s = self.request.connection.stream.socket
        l_onoff = 1
        l_linger = 0
        s.setsockopt(
            socket.SOL_SOCKET, socket.SO_LINGER,
            struct.pack('ii', l_onoff, l_linger)
        )
        self.request.connection.close()

if __name__ == "__main__":
    application = tornado.web.Application([
        (r"/", MainHandler),
    ])
    application.listen(8888)
    tornado.ioloop.IOLoop.current().start()

Upvotes: 1

A. Jesse Jiryu Davis
A. Jesse Jiryu Davis

Reputation: 24009

Decorate your method with asynchronous and never call finish:

class EchoHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        if not self.get_cookie("topsession"):
            pass
        else:
            self.finish("0")

As the docs for asynchronous say:

If this decorator is given, the response is not finished when the method returns. It is up to the request handler to call self.finish() to finish the HTTP request.

So, if you simply return without calling finish, the client waits forever (or until its client-side socket timeout) for a response without receiving one. If you do this, however, you must call finish in the other branch of the if statement.

On the other hand if by "no response" you mean an error, you could do instead:

class EchoHandler(tornado.web.RequestHandler):
    def get(self):
        if not self.get_cookie("topsession"):
            raise tornado.web.HTTPError(401)  # Unauthorized.
        else:
            self.write("0")

Upvotes: 4

Related Questions