2013年7月31日星期三

测试 IRC 网址机器人代码

最近在优化 IRC 链接机器人。这是一种在 IRC 频道中自动识别用户发出的网址并获取对应页面的标题或对应图片的尺寸等信息的机器人。
有一个要求很重要,就是发一些奇怪的网址也能正确识别,并且能妥善处理超时等问题。
下面列出一段代码,使用 Tornado 技术:
#!/usr/bin/env python

import time

import tornado.gen
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web


tornado.options.define('port', default=10489,
                       help='run on the given port', type=int)


class CountHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    @tornado.gen.coroutine
    def get(self):
        for i in range(1, 101):
            yield tornado.gen.Task(
                tornado.ioloop.IOLoop.instance().add_timeout, time.time()+1
            )
            self.write(('%s\n') % i)
            self.flush()
        self.finish()


class BombHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header('Content-Encoding', 'gzip')
        self.set_header('Content-Type', 'text/html')
        self.set_header('Content-Length', '2147483647')
        with open('bomb.gz', 'rb') as f:
            self.write(f.read())


def main():
    tornado.options.parse_command_line()
    application = tornado.web.Application([
        ('/count', CountHandler),
        ('/bomb', BombHandler),
    ])
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(tornado.options.options.port)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == '__main__':
    main()
然后我们还需要生成 bomb.gz。使用如下命令:
dd if=/dev/zero bs=4M count=1k | gzip -9 >bomb.gz
这将一个 4 GiB 大小的空文件压缩成 gzip 格式,生成文件大小约 4 MiB。
我们将测试 http://localhost:10489/count 和 http://localhost:10489/bomb 两个链接。

某些机器人有超时设定,而 /count 测试会分批传输数据,某些具有 bug 的机器人会一直等待下去。此时如果发送很多这个链接,在机器人等待的时候中断服务器的 Tornado 程序,可能会导致机器人不断高速发送错误信息而被踢出。
由于某些站点,如哔哩哔哩,会不顾浏览器发送的 Accept-Encoding 请求而始终返回 gzip 压缩的数据。导致有的机器人需要解压返回的数据。/bomb 就是测试机器人是否能够控制解压的数据量而不占用过多内存。
最后,提醒一下:如果你打算测试某个机器人,最好征得其主人同意哦。