File: simple_httpclient.py

package info (click to toggle)
python-tornado 1.0.1-1%2Bdeb6u1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze-lts
  • size: 776 kB
  • ctags: 1,093
  • sloc: python: 6,168; ansic: 64; xml: 26; sql: 25; makefile: 2
file content (68 lines) | stat: -rw-r--r-- 2,520 bytes parent folder | download | duplicates (2)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from cStringIO import StringIO
from tornado.httpclient import HTTPRequest, HTTPResponse, HTTPError
from tornado.httputil import HTTPHeaders
from tornado.ioloop import IOLoop
from tornado.iostream import IOStream
from tornado import stack_context

import functools
import logging
import re
import socket
import urlparse

class SimpleAsyncHTTPClient(object):
    # TODO: singleton magic?
    def __init__(self, io_loop=None):
        self.io_loop = io_loop or IOLoop.instance()

    def close(self):
        pass

    def fetch(self, request, callback, **kwargs):
        if not isinstance(request, HTTPRequest):
            request = HTTPRequest(url=request, **kwargs)
        callback = stack_context.wrap(callback)

        parsed = urlparse.urlsplit(request.url)
        sock = socket.socket()
        #sock.setblocking(False) # TODO non-blocking connect
        sock.connect((parsed.netloc, 80))  # TODO: other ports, https
        stream = IOStream(sock, io_loop=self.io_loop)
        # TODO: query parameters
        logging.warning("%s %s HTTP/1.0\r\n\r\n" % (request.method, parsed.path or '/'))
        stream.write("%s %s HTTP/1.0\r\n\r\n" % (request.method, parsed.path or '/'))
        stream.read_until("\r\n\r\n", functools.partial(self._on_headers,
                                                        request, callback, stream))

    def _on_headers(self, request, callback, stream, data):
        logging.warning(data)
        first_line, _, header_data = data.partition("\r\n")
        match = re.match("HTTP/1.[01] ([0-9]+) .*", first_line)
        assert match
        code = int(match.group(1))
        headers = HTTPHeaders.parse(header_data)
        assert "Content-Length" in headers
        stream.read_bytes(int(headers["Content-Length"]),
                          functools.partial(self._on_body, request, callback, stream, code, headers))

    def _on_body(self, request, callback, stream, code, headers, data):
        response = HTTPResponse(request, code, headers=headers,
                                buffer=StringIO(data)) # TODO
        callback(response)

def main():
    from tornado.options import define, options, parse_command_line
    args = parse_command_line()
    client = SimpleAsyncHTTPClient()
    io_loop = IOLoop.instance()
    for arg in args:
        def callback(response):
            response.rethrow()
            print response.body
            io_loop.stop()
        client.fetch(arg, callback)
        io_loop.start()

if __name__ == "__main__":
    main()