Package spade :: Module wui
[hide private]
[frames] | no frames]

Source Code for Module spade.wui

  1  # encoding: UTF-8 
  2  import traceback 
  3  import SocketServer 
  4  import SimpleHTTPServer 
  5  import BaseHTTPServer 
  6  import pyratemp 
  7  import os 
  8  import sys 
  9  import traceback 
 10  import urllib 
 11  import time 
 12  import random 
 13  import socket 
 14  import Cookie 
 15  import string 
 16   
 17  from threading import Thread 
 18   
 19  chars = string.ascii_letters + string.digits 
 20  sessionDict = {} # dictionary mapping session id's to session objects 
 21   
22 -class HTTP_REDIRECTION(Exception):
23 pass
24
25 -class WUI(Thread):
26 - def __init__(self, owner):
27 Thread.__init__(self) 28 self.owner = owner 29 self.httpd = None 30 self.port = 8009 31 self.template_path = "" 32 # Try to get SPADE's default template path 33 tpath = os.path.realpath(pyratemp.__file__) # /Users/foo/devel/trunk/spade 34 tpath = tpath.rsplit(os.sep,1) # ["/Users/foo/devel/trunk", "spade"] 35 self.spade_path = tpath[0] ###+os.sep+os.pardir 36 #self.owner.DEBUG("SPADE path: " + self.spade_path,"warn") 37 38 self.controllers = {} 39 40 self.is_running = False
41
42 - def run(self):
43 44 while not self.httpd: 45 try: 46 self.httpd = SocketServer.ThreadingTCPServer(('', self.port), WUIHandler) 47 self.httpd.owner = self 48 self.httpd.timeout = 1 49 #print "WebUserInterface serving at port "+str(self.port) 50 self.notifyAMS() 51 except: 52 self.port = random.randint(1024,65536) 53 54 self.owner.DEBUG("WebUserInterface serving at port "+str(self.port)) 55 self.registerController("error404", self.error404) 56 self.registerController("error501", self.error501) 57 self.registerController("error503", self.error503) 58 59 self.is_running = True 60 while self.isRunning(): 61 self.httpd.handle_request()
62
63 - def isRunning(self):
64 return self.is_running
65
66 - def stop(self):
67 self.is_running = False
68
69 - def setPort(self, port):
70 self.port = port
71
72 - def setTemplatePath(self,path):
73 self.template_path = os.path.realpath(path)
74
75 - def registerController(self, name, controller):
76 self.controllers[name] = controller
77
78 - def unregisterController(self, name):
79 del self.controllers[name]
80
81 - def notifyAMS(self):
82 """Notify AMS of current AWUI URL""" 83 #return 84 from spade.AMS import AmsAgentDescription 85 aad = AmsAgentDescription() 86 aid = self.owner.getAID() 87 aid.addAddress("awui://"+str(socket.gethostbyname(socket.gethostname()))+":"+str(self.port)) 88 aad.setAID(aid) 89 self.owner.modifyAgent(aad)
90 91 #Controllers 92
93 - def error404(self):
94 return "404.pyra", {"template":"404.pyra"}
95 - def error501(self):
96 return "501.pyra", {"template":"501.pyra", "error":""}
97 - def error503(self):
98 return "503.pyra", {"page":"503.pyra"}
99 100
101 -class SessionElement(object):
102 """Arbitrary objects, referenced by the session id""" 103 pass
104
105 -def generateRandom(length):
106 """Return a random string of specified length (used for session id's)""" 107 return ''.join([random.choice(chars) for i in range(length)])
108
109 -class WUIHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
110
111 - def Session(self):
112 """Session management 113 If the client has sent a cookie named sessionId, take its value and 114 return the corresponding SessionElement objet, stored in 115 sessionDict 116 Otherwise create a new SessionElement objet and generate a random 117 8-letters value sent back to the client as the value for a cookie 118 called sessionId""" 119 if self.cookie.has_key("sessionId"): 120 sessionId=self.cookie["sessionId"].value 121 else: 122 sessionId=generateRandom(8) 123 self.cookie["sessionId"]=sessionId 124 try: 125 sessionObject = sessionDict[sessionId] 126 except KeyError: 127 sessionObject = SessionElement() 128 sessionDict[sessionId] = sessionObject 129 return sessionObject
130
131 - def getPage(self, req):
132 """ 133 Return the page name from a raw GET line 134 """ 135 return req.split("?")[0]
136
137 - def getVars(self, req):
138 """ 139 Return the variables and values from a raw GET or POST request line 140 """ 141 d = dict() 142 try: 143 raw_vars = req.split("?")[1] 144 for raw in raw_vars.split("&"): 145 #print raw 146 var = raw.split("=") 147 if len(var) > 1: 148 # Check if this is a multi-valued var 149 if var[0] in d.keys(): 150 try: 151 # Try to append value to the list 152 d[var[0]].append(urllib.unquote_plus(var[1])) 153 except: 154 # Create a list with the current value and append the new one 155 d[var[0]] = [d[var[0]]] 156 d[var[0]].append(urllib.unquote_plus(var[1])) 157 else: 158 d[urllib.unquote_plus(var[0])] = urllib.unquote_plus(var[1]) 159 else: 160 d[urllib.unquote_plus(var[0])] = "" 161 except: 162 pass 163 164 return d
165
166 - def do_POST(self):
167 168 self._POST_REQ = "" 169 try: 170 length = int(self.headers.getheader('content-length')) 171 self._POST_REQ = self.rfile.read(length) 172 except: 173 pass 174 175 self.do_GET()
176 177
178 - def do_GET(self):
179 """ 180 GET petitions handler 181 """ 182 ret = None 183 request = self.raw_requestline.split() 184 page = self.getPage(request[1]) 185 186 187 if page == "/": page = "/index" 188 189 if page.startswith("/"): page = page [1:] 190 191 try: 192 req_vars = self.getVars("?"+self._POST_REQ) 193 except: 194 req_vars = self.getVars(request[1]) 195 196 s_vars="" 197 for k,v in req_vars.items(): 198 if k: 199 v = str(v) 200 if not v.startswith('"') and not v.startswith("'") and not v.startswith("["): 201 v = '"'+ v +'"' 202 s_vars+= str(k) + "=" + v +"," 203 if s_vars.endswith(","): s_vars = s_vars[:-1] 204 205 #session management 206 if self.headers.has_key('cookie'): 207 self.cookie=Cookie.SimpleCookie(self.headers.getheader("cookie")) 208 else: 209 self.cookie=Cookie.SimpleCookie() 210 211 # Switch page 212 #if page.endswith("css"): 213 if page.endswith(".css") or page.endswith(".png") or page.endswith(".html") or page.endswith(".js"): 214 #self.copyfile(urllib.urlopen(self.path), self.wfile) 215 try: 216 if os.path.exists(self.server.owner.template_path + os.sep + page): 217 page = self.server.owner.template_path + os.sep + page 218 elif os.path.exists(self.server.owner.spade_path + os.sep + "templates" + os.sep + page): 219 page = self.server.owner.spade_path + os.sep + "templates" + os.sep + page 220 elif page.startswith("doc") and os.path.exists(self.server.owner.spade_path + os.sep + page): 221 # For serving the SPADE API docs from the WUI 222 page = self.server.owner.spade_path + os.sep + page 223 else: 224 raise Exception 225 226 except: 227 self.server.owner.owner.DEBUG("Could not open file: "+ page, "err") 228 229 try: 230 self.send_response(200) 231 for morsel in self.cookie.values(): 232 self.send_header('Set-Cookie', morsel.output(header='').lstrip()) 233 self.end_headers() 234 f = open(page, "r") 235 self.copyfile(f, self.wfile) 236 f.close() 237 except: 238 self.server.owner.owner.DEBUG(str(sys.exc_info()), "err") 239 240 else: 241 sess = self.Session() 242 try: 243 # Check wether controller exists 244 # Get the first section of the URL path (e.g. the "admin" of "admin/foo/bar") 245 eval("self.server.owner.controllers['"+str(page)+"']") 246 except: 247 # The controller doesn't exist 248 _exception = sys.exc_info() 249 if _exception[0]: 250 _err = ''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip() 251 template = "404.pyra" 252 ret = {"template":page, "error":str(_err),"name":self.server.owner.owner.getName()} 253 code=404 254 try: 255 if not ret: 256 func = self.server.owner.controllers[str(page)] 257 #session object 258 sess.url = page 259 func.__self__.session = sess 260 template, ret = eval("func"+"("+s_vars+")") 261 code=200 262 except HTTP_REDIRECTION,url: 263 self.send_response(302) 264 for morsel in self.cookie.values(): 265 self.send_header('Set-Cookie', morsel.output(header='').lstrip()) 266 self.send_header('Location', url) 267 self.end_headers() 268 self.wfile.write("") 269 return 270 271 except Exception, e: 272 #No controller 273 _exception = sys.exc_info() 274 if _exception[0]: 275 _err = ''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip() 276 template = "501.pyra" 277 ret = {"template":page, "error":str(_err),"name":self.server.owner.owner.getName()} 278 code=501 279 280 try: 281 if os.path.exists(self.server.owner.template_path+os.sep+template): 282 t = pyratemp.Template(filename=self.server.owner.template_path+os.sep+template, data=ret) 283 else: 284 #olddir = os.path.curdir 285 #os.chdir(self.server.spade_path) 286 authenticated = False 287 if hasattr(sess,"user_authenticated"): 288 if sess.user_authenticated==True: authenticated=True 289 ret['authenticated'] = authenticated 290 t = pyratemp.Template(filename=self.server.owner.spade_path+os.sep+"templates"+os.sep+template, data=ret) 291 #print template, ret 292 #os.chdir(olddir) 293 except pyratemp.TemplateSyntaxError, e: 294 _exception = sys.exc_info() 295 if _exception[0]: 296 _err = ''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip() 297 t = pyratemp.Template(filename=self.server.owner.spade_path+os.sep+"templates"+os.sep+"501.pyra", data={"template":template, "error":str(_err),"name":self.server.owner.owner.getName()}) 298 code=501 299 except Exception, e: 300 #No template 301 _exception = sys.exc_info() 302 if _exception[0]: 303 _err = ''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip() 304 #print "###", _err, "###" 305 t = pyratemp.Template(filename=self.server.owner.spade_path+os.sep+"templates"+os.sep+"503.pyra", data={"page":template,"name":self.server.owner.owner.getName()}) 306 code=503 307 try: 308 result = t() 309 except Exception, e: 310 #Error in template 311 _exception = sys.exc_info() 312 if _exception[0]: 313 _err = ''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip() 314 t = pyratemp.Template(filename=self.server.owner.spade_path+os.sep+"templates"+os.sep+"501.pyra", data={"template":template, "error":str(_err),"name":self.server.owner.owner.getName()}) 315 result = t() 316 code=501 317 318 r = result.encode("ascii", 'xmlcharrefreplace') 319 320 self.send_response(code) 321 for morsel in self.cookie.values(): 322 self.send_header('Set-Cookie', morsel.output(header='').lstrip()) 323 self.end_headers() 324 self.wfile.write(r)
325