ia64/xen-unstable

view tools/python/xen/web/httpserver.py @ 6552:a9873d384da4

Merge.
author adsharma@los-vmm.sc.intel.com
date Thu Aug 25 12:24:48 2005 -0700 (2005-08-25)
parents 112d44270733 fa0754a9f64f
children dfaf788ab18c
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
16 #============================================================================
17 import threading
19 import string
20 import socket
21 import types
22 from urllib import quote, unquote
23 import os
24 import os.path
26 from xen.xend import sxp
27 from xen.xend.Args import ArgError
28 from xen.xend.XendError import XendError
30 import http
31 from resource import Resource, ErrorPage
32 from SrvDir import SrvDir
34 class ThreadRequest:
35 """A request to complete processing using a thread.
36 """
38 def __init__(self, processor, req, fn, args, kwds):
39 self.processor = processor
40 self.req = req
41 self.fn = fn
42 self.args = args
43 self.kwds = kwds
45 def run(self):
46 self.processor.setInThread()
47 thread = threading.Thread(target=self.main)
48 thread.setDaemon(True)
49 thread.start()
51 def call(self):
52 try:
53 self.fn(*self.args, **self.kwds)
54 except SystemExit:
55 raise
56 except Exception, ex:
57 self.req.resultErr(ex)
58 self.req.finish()
60 def main(self):
61 self.call()
62 self.processor.process()
65 class RequestProcessor:
66 """Processor for requests on a connection to an http server.
67 Requests are executed synchonously unless they ask for a thread by returning
68 a ThreadRequest.
69 """
71 done = False
73 inThread = False
75 def __init__(self, server, sock, addr):
76 self.server = server
77 self.sock = sock
78 self.srd = sock.makefile('rb')
79 self.srw = sock.makefile('wb')
80 self.srvaddr = server.getServerAddr()
82 def isInThread(self):
83 return self.inThread
85 def setInThread(self):
86 self.inThread = True
88 def getServer(self):
89 return self.server
91 def getRequest(self):
92 return HttpServerRequest(self, self.srvaddr, self.srd, self.srw)
94 def close(self):
95 try:
96 self.sock.close()
97 except:
98 pass
100 def finish(self):
101 self.done = True
102 self.close()
104 def process(self):
105 while not self.done:
106 req = self.getRequest()
107 res = req.process()
108 if isinstance(res, ThreadRequest):
109 if self.isInThread():
110 res.call()
111 else:
112 res.run()
113 break
114 else:
115 req.finish()
117 class HttpServerRequest(http.HttpRequest):
118 """A single request to an http server.
119 """
121 def __init__(self, processor, addr, srd, srw):
122 self.processor = processor
123 self.prepath = ''
124 http.HttpRequest.__init__(self, addr, srd, srw)
126 def getServer(self):
127 return self.processor.getServer()
129 def process(self):
130 """Process the request. If the return value is a ThreadRequest
131 it is evaluated in a thread.
132 """
133 try:
134 self.prepath = []
135 self.postpath = map(unquote, string.split(self.request_path[1:], '/'))
136 resource = self.getResource()
137 return self.render(resource)
138 except SystemExit:
139 raise
140 except Exception, ex:
141 self.processError(ex)
143 def processError(self, ex):
144 import traceback; traceback.print_exc()
145 self.sendError(http.INTERNAL_SERVER_ERROR, msg=str(ex))
146 self.setCloseConnection('close')
148 def finish(self):
149 self.sendResponse()
150 if self.close_connection:
151 self.processor.finish()
153 def prePathURL(self):
154 url_host = self.getRequestHostname()
155 port = self.getPort()
156 if self.isSecure():
157 url_proto = "https"
158 default_port = 443
159 else:
160 url_proto = "http"
161 default_port = 80
162 if port != default_port:
163 url_host += (':%d' % port)
164 url_path = quote(string.join(self.prepath, '/'))
165 return ('%s://%s/%s' % (url_proto, url_host, url_path))
167 def getResource(self):
168 return self.getServer().getResource(self)
170 def render(self, resource):
171 val = None
172 if resource is None:
173 self.sendError(http.NOT_FOUND)
174 else:
175 try:
176 while True:
177 val = resource.render(self)
178 if not isinstance(val, Resource):
179 break
180 val = self.result(val)
181 except SystemExit:
182 raise
183 except Exception, ex:
184 self.resultErr(ex)
185 return val
187 def threadRequest(self, _fn, *_args, **_kwds):
188 """Create a request to finish request processing in a thread.
189 Use this to create a ThreadRequest to return from rendering a
190 resource if you need a thread to complete processing.
191 """
192 return ThreadRequest(self.processor, self, _fn, _args, _kwds)
194 def result(self, val):
195 if isinstance(val, Exception):
196 return self.resultErr(val)
197 else:
198 return self.resultVal(val)
200 def resultVal(self, val):
201 """Callback to complete the request.
203 @param val: the value
204 """
205 if val is None:
206 return val
207 elif isinstance(val, ThreadRequest):
208 return val
209 elif self.useSxp():
210 self.setHeader("Content-Type", sxp.mime_type)
211 sxp.show(val, out=self)
212 else:
213 self.write('<html><head></head><body>')
214 self.printPath()
215 if isinstance(val, types.ListType):
216 self.write('<code><pre>')
217 PrettyPrint.prettyprint(val, out=self)
218 self.write('</pre></code>')
219 else:
220 self.write(str(val))
221 self.write('</body></html>')
222 return None
224 def resultErr(self, err):
225 """Error callback to complete a request.
227 @param err: the error
228 """
229 if not isinstance(err, (ArgError, sxp.ParseError, XendError)):
230 raise
231 #log.exception("op=%s: %s", op, str(err))
232 if self.useSxp():
233 self.setHeader("Content-Type", sxp.mime_type)
234 sxp.show(['xend.err', str(err)], out=self)
235 else:
236 self.setHeader("Content-Type", "text/plain")
237 self.write('Error ')
238 self.write(': ')
239 self.write(str(err))
240 return None
242 def useSxp(self):
243 """Determine whether to send an SXP response to a request.
244 Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept.
246 returns 1 for SXP, 0 otherwise
247 """
248 ok = 0
249 user_agent = self.getHeader('User-Agent')
250 accept = self.getHeader('Accept')
251 if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0):
252 ok = 1
253 return ok
255 def printPath(self):
256 pathlist = [x for x in self.prepath if x != '' ]
257 s = "/"
258 self.write('<h1><a href="/">/</a>')
259 for x in pathlist:
260 s += x + "/"
261 self.write(' <a href="%s">%s</a>/' % (s, x))
262 self.write("</h1>")
264 class HttpServer:
266 backlog = 5
268 closed = False
270 def __init__(self, interface='', port=8080, root=None):
271 if root is None:
272 root = SrvDir()
273 self.interface = interface
274 self.port = port
275 self.root = root
277 def getRoot(self):
278 return self.root
280 def getPort(self):
281 return self.port
283 def run(self):
284 self.bind()
285 self.listen()
286 self.requestLoop()
288 def stop(self):
289 self.close()
291 def bind(self):
292 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
293 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
294 self.socket.bind((self.interface, self.port))
296 def listen(self):
297 self.socket.listen(self.backlog)
299 def accept(self):
300 return self.socket.accept()
302 def requestLoop(self):
303 while not self.closed:
304 self.acceptRequest()
306 def close(self):
307 self.closed = True
308 try:
309 self.socket.close()
310 except:
311 pass
313 def acceptRequest(self):
314 try:
315 (sock, addr) = self.accept()
316 self.processRequest(sock, addr)
317 except socket.error:
318 return
320 def processRequest(self, sock, addr):
321 try:
322 rp = RequestProcessor(self, sock, addr)
323 rp.process()
324 except SystemExit:
325 raise
326 except Exception, ex:
327 print 'HttpServer>processRequest> exception: ', ex
328 try:
329 sock.close()
330 except:
331 pass
333 def getServerAddr(self):
334 return (socket.gethostname(), self.port)
336 def getResource(self, req):
337 return self.root.getRequestResource(req)
339 class UnixHttpServer(HttpServer):
341 def __init__(self, path=None, root=None):
342 HttpServer.__init__(self, interface='localhost', root=root)
343 self.path = path
345 def bind(self):
346 pathdir = os.path.dirname(self.path)
347 if not os.path.exists(pathdir):
348 os.makedirs(pathdir)
349 else:
350 try:
351 os.unlink(self.path)
352 except SystemExit:
353 raise
354 except Exception, ex:
355 pass
356 self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
357 #self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
358 self.socket.bind(self.path)