Attachment 'testACHTTPServer.py'
Download 1 #!/usr/bin/env python
2 #
3 # Beat the hell out of AsyncoreHTTPServer.py.
4 #
5 # SVN Info
6 #----------------------------------
7 # $Author: cnobile $
8 # $Date: 2010-03-04 20:50:34 $
9 # $Revision: 1.6 $
10 #----------------------------------
11 ##########################################################################
12 # Copyright (c) 2010 Carl J. Nobile.
13 # All rights reserved. This program and the accompanying materials
14 # are made available under the terms of the Eclipse Public License v1.0
15 # which accompanies this distribution, and is available at
16 # http://www.eclipse.org/legal/epl-v10.html
17 #
18 # Contributors:
19 # Carl J. Nobile - initial API and implementation
20 ##########################################################################
21
22 import socket, sys, time, getopt
23 from asyncore import dispatcher, loop
24 from email.Parser import Parser
25 from email.Message import Message
26 from threading import Thread
27
28
29 class HeaderProducer:
30 def __init__(self, headers):
31 """
32 HeaderProducer constructor.
33
34 @param headers: C{email.Message.Message} object.
35 """
36 if not isinstance(headers, Message):
37 raise TypeError("Must use an email.Message.Message object.")
38
39 self.__headers = headers.items()
40 self.__done = False
41
42 def more(self):
43 result = ''
44
45 if self.__headers:
46 result = "%s: %s\r\n" % (self.__headers.pop(0))
47 elif not self.__done:
48 self.__done = True
49 result = "\r\n"
50
51 return result
52
53
54 class ListProducer:
55 def __init__(self, list):
56 """
57 ListProducer constructor.
58
59 @param list: A Python list object.
60 """
61 self.__list = list
62
63 def more(self):
64 result = ''
65 if self.__list: result = self.__list.pop(0)
66 return result
67
68
69 class WebServerTestClient(dispatcher):
70 def __init__(self, host, port, method, path, count, keepalive=True):
71 dispatcher.__init__(self)
72 self.__host = host
73 self.__port = port
74 self.__method = method
75 self.__path = path
76 self.__count = count
77 self.__keepalive = (count != 1) and keepalive
78 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
79 self.connect((host, port))
80 self.buffer = ''
81 self.getHeaders()
82 #print "In Constructor: %s, %s, %s" % (host, port, path)
83
84 def handle_connect(self):
85 print "Connected to: http://%s:%s%s" % \
86 (self.__host, self.__port, self.__path)
87
88 def getHeaders(self):
89 headers = Parser().parsestr('', headersonly=True)
90 headers.add_header('Host', '%s:%s' % (self.__host, self.__port))
91 headers.add_header('Content-Type', 'text/plain')
92 if not self.__keepalive: headers.add_header('Connection', 'close')
93 self.send('%s %s HTTP/1.1\r\n' % (self.__method, self.__path))
94 hp = HeaderProducer(headers)
95 data = hp.more()
96
97 while data:
98 self.buffer += data
99 data = hp.more()
100
101 def handle_read(self):
102 data = self.recv(8192)
103 print data
104
105 def writable(self):
106 return (len(self.buffer) > 0)
107
108 def handle_write(self):
109 for i in range(self.__count):
110 if i >= (self.__count - 1): self.__keepalive = False
111 if i != 0: self.getHeaders()
112 self.sendRequest()
113
114 def sendRequest(self):
115 sent = self.send(self.buffer)
116 self.buffer = self.buffer[sent:]
117
118 def handle_close(self):
119 self.close()
120
121
122 class Channel(Thread):
123 def __init__(self, host, port, method, path, count, keepalive, **kwargs):
124 super(Channel, self).__init__(**kwargs)
125 self.__host = host
126 self.__port = port
127 self.__method = method
128 self.__path = path
129 self.__count = count
130 self.__keepalive = keepalive
131
132 def run(self):
133 print "%s, URI: http://%s:%s%s" % (self.getName(), self.__host,
134 self.__port, self.__path)
135 WebServerTestClient(self.__host, self.__port, self.__method,
136 self.__path, self.__count, self.__keepalive)
137
138
139 class GetOptions(object):
140 """
141 This class parses the command line options and returns a dictionary
142 of {option:value, ...} pairs.
143 """
144 __slots__ = ('__args', '__options', '__longOptions', '__optmap')
145
146 def __init__(self, args=None, options=None, long_options=[]):
147 """
148 Parse the option list.
149
150 @param args: The arguments from the command line minus the program
151 name.
152 @param options: The single character arguments.
153 @param long_options: A Tuple of the long arguments.
154 """
155 self.__args = args
156 self.__options = options
157 self.__longOptions = long_options
158 self.__optmap = {}
159
160 def parse(self):
161 """
162 Parse the options into a dictionary.
163
164 @return: A key/value map of the arguments and their values.
165 """
166 optlist, extraopts = getopt.gnu_getopt(self.__args, self.__options,
167 self.__longOptions)
168 return self._createDict(optlist)
169
170 def _createDict(self, opts):
171 """
172 Create a dictionary of command line flags. If an arg is present more
173 than once put all args in a list.
174
175 @param opts: List of (option, value) pairs.
176 """
177 for arg, value in opts:
178 if value:
179 if self.__optmap.has_key(arg):
180 tmp = self.__optmap.get(arg)
181
182 if not isinstance(tmp, list):
183 self.__optmap[arg] = [tmp]
184
185 valueList = self.__optmap[arg]
186 valueList.append(value)
187 else:
188 self.__optmap[arg] = value
189 else:
190 self.__optmap[arg] = True
191
192 return self.__optmap
193
194 def getOptionMap(self):
195 """
196 Gets the option dictionary map.
197
198 @return: The raw option map.
199 """
200 return self.__optmap
201
202
203 def usage():
204 """
205 Prints the scripts usage to stdout.
206 """
207 print "Usage: %s " % (sys.argv[0]) + "-[d] " + \
208 "-[h host:port, m method, p URI, c count, t timeout," + \
209 " k keepalive(True|Flase)]"
210
211
212 if __name__ == '__main__':
213 import traceback
214
215 options = 'dh:m:p:c:t:k:'
216 longOptions = []
217 opts = None
218
219 try:
220 opt = GetOptions(sys.argv[1:], options, longOptions)
221 opts = opt.parse()
222 except Exception, e:
223 print "Error: Invalid argument list, " + str(e)
224 usage()
225 sys.exit(1)
226
227 host, port = opts.get('-h', 'localhost:8081').split(':')
228 port = int(port)
229 method = opts.get('-m', 'HEAD').strip()
230 path = opts.get('-p', '/')
231 count = int(opts.get('-c', '1'))
232 timeout = float(opts.get('-t', '30.0'))
233 keepalive = eval(opts.get('-k', 'True').strip().capitalize())
234 threadMap = {}
235
236 if keepalive:
237 # range should be different paths (Not implimented yet).
238 for i in range(1):
239 c = Channel(host, port, method, path, count, keepalive)
240 c.setName('Channel%02i' % (i+1))
241 threadMap[c.getName()] = c
242 c.run()
243 else:
244 for i in range(count):
245 print "Instance%02i, URI: http://%s:%s%s" % (i, host, port, path)
246 WebServerTestClient(host, port, method, path, 1, keepalive)
247
248 loop(timeout=timeout)
249 sys.exit(0)
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.- [get | view] (2010-03-04 20:57:06, 48.9 KB) [[attachment:AsyncoreHTTPServer.py]]
- [get | view] (2010-10-13 19:32:21, 3.2 KB) [[attachment:ChangeLog.txt]]
- [get | view] (2010-10-13 19:57:35, 4.6 KB) [[attachment:README.txt]]
- [get | view] (2010-03-04 20:58:35, 7.3 KB) [[attachment:testACHTTPServer.py]]
You are not allowed to attach a file to this page.