Package tangled :: Module client
[hide private]
[frames] | no frames]

Source Code for Module tangled.client

  1  # -*- coding: utf-8 -*- 
  2  # 
  3  # Copyright (c) 2001-2010 Pär Bohrarper. 
  4  # See LICENSE for details. 
  5   
  6  import asyncore 
  7  import socket 
  8  import urlparse 
  9  import mimetools 
 10  import cStringIO 
 11  import core 
 12   
 13  import logging 
 14  log = logging.getLogger("tangled.client") 
 15   
16 -class Response(object):
17 """ 18 This is the response object returned by L{AsyncHTTPClient}. 19 """
20 - def __init__(self, addr):
21 self.data = "" 22 self.header = "" 23 self.finished = False 24 self.server_address = addr
25
26 - def close(self):
27 self.finished = True
28
29 - def feed(self, data):
30 self.data += data
31
32 - def http_header(self, header):
33 self.header = header
34
35 - def http_status(self, status):
36 self.status = int(status[1]) 37 try: 38 self.reason = status[2] 39 except IndexError: 40 self.reason = ""
41 42
43 -class AsyncHTTPClient(asyncore.dispatcher_with_send):
44 """ 45 Asynchronous HTTP client, based on 46 http://effbot.org/librarybook/SimpleAsyncHTTP.py 47 """
48 - def __init__(self, url, command="GET", data="", consumer=None):
49 asyncore.dispatcher_with_send.__init__(self) 50 parsed = urlparse.urlparse(url) 51 self._request = '%s %s HTTP/1.1\r\n' % (command, parsed.path) 52 self._request = self._request + 'Host: %s\r\n' % parsed.netloc 53 if len(data) > 0: 54 self._request = self._request + 'Content-Length: %d\r\n\r\n%s' % (len(data), data) 55 else: 56 self._request = self._request + "\r\n" 57 addr = parsed.netloc.split(":") 58 host = addr[0] 59 try: 60 port = int(addr[1]) 61 except IndexError: 62 port = 80 63 self.consumer = consumer 64 if self.consumer is None: 65 self.consumer = Response((host, port)) 66 self.response = self.consumer 67 self.status = None 68 self.header = None 69 self.data = "" 70 self._result = core.Deferred() 71 self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 72 self.connect((host, port))
73
74 - def request(self):
75 return self._result
76
77 - def handle_connect(self):
78 self.send(self._request)
79
80 - def notify_header(self):
81 self.consumer.http_status(self.status) 82 self.consumer.http_header(self.header)
83
84 - def handle_expt(self):
85 # connection failed; notify consumer (status is None) 86 self.close() 87 self.notify_header() 88 self._result.callback(self.response)
89
90 - def handle_read(self):
91 data = self.recv(2048) 92 if not self.header: 93 self.data = self.data + data 94 i = self.data.find("\r\n\r\n") 95 if i != -1: 96 # parse header 97 fp = cStringIO.StringIO(self.data[:i+4]) 98 # status line is "HTTP/version status message" 99 status = fp.readline() 100 self.status = status.split(" ", 2) 101 # followed by a rfc822-style message header 102 self.header = mimetools.Message(fp) 103 # followed by a newline, and the payload (if any) 104 data = self.data[i+4:] 105 self.data = "" 106 # notify consumer (status is non-zero) 107 self.notify_header() 108 if not self.connected: 109 return # channel was closed by consumer 110 111 if self.header: 112 self.consumer.feed(data)
113
114 - def handle_close(self):
115 self.consumer.close() 116 self.close() 117 self._result.callback(self.response)
118
119 -def request(url, command="GET", data=""):
120 """ 121 Helper function to make a request without needing 122 to know about L{AsyncHTTPClient}. 123 """ 124 c = AsyncHTTPClient(url, command, data) 125 return c.request()
126 127 if __name__=="__main__": 128 import optparse 129 130 parser = optparse.OptionParser() 131 132 parser.add_option("-n", "--number", dest="number", type="int", 133 help="Number of connections") 134 parser.add_option("-c", "--concurrent", dest="concurrent", type="int", 135 help="Number of concurrent connections") 136 parser.add_option("-p", "--printresponse", dest="printresponse", action="store_true", default=False, 137 help="Number of concurrent connections") 138 139 (options, args) = parser.parse_args() 140 141 num = 0 142 for n in range(0, options.number, options.concurrent): 143 clients = [AsyncHTTPClient(args[0]) for i in range(options.concurrent)] 144 asyncore.loop() 145 if options.printresponse: 146 for c in clients: 147 print c.response.header 148 print c.response.data 149 num += len(clients) 150 print "Completed", num, "requests" 151