Package starcluster :: Module webtools
[hide private]
[frames] | no frames]

Source Code for Module starcluster.webtools

  1  import os 
  2  import sys 
  3  import shlex 
  4  import optparse 
  5  import mimetypes 
  6  import posixpath 
  7  import webbrowser 
  8  import subprocess 
  9  import BaseHTTPServer as httpserv 
 10   
 11  from starcluster import templates 
 12  from starcluster import exception 
 13  from starcluster.logger import log 
 14   
 15  ERROR_MSG = """\ 
 16  <head> 
 17  <title>DOH!</title> 
 18  </head> 
 19  <body> 
 20  <pre> 
 21   _  _    ___  _  _ 
 22  | || |  / _ \| || | 
 23  | || |_| | | | || |_ 
 24  |__   _| |_| |__   _| 
 25     |_|  \___/   |_| 
 26   
 27  </pre> 
 28  <h1>Error response</h1> 
 29  <p>Error code %(code)d. 
 30  <p>Message: %(message)s. 
 31  <p>Error code explanation: %(code)s = %(explain)s. 
 32  </body> 
 33  """ 
 34   
 35   
36 -class StoppableHttpServer(httpserv.HTTPServer):
37 """http server that reacts to self.stop flag""" 38
39 - def serve_forever(self):
40 """Handle one request at a time until stopped.""" 41 self.stop = False 42 while not self.stop: 43 self.handle_request()
44 45
46 -class BaseHandler(httpserv.BaseHTTPRequestHandler):
47 error_message_format = ERROR_MSG 48
49 - def do_GET(self):
50 print 'GET not supported'
51
52 - def do_POST(self):
53 print 'POSTing not supported'
54
55 - def do_shutdown(self):
56 log.info("Shutting down server...") 57 self.send_response(200) 58 self.send_header('Content-type', 'text/html') 59 self.end_headers() 60 self.server.stop = True
61 62
63 -class DocrootHandler(BaseHandler):
64
65 - def do_GET(self):
66 try: 67 docroot = globals()['DOCUMENTROOT'] 68 fname = posixpath.join(docroot, self.path[1:]) 69 #remove query args. query args are ignored in static server 70 fname = fname.split('?')[0] 71 if fname.endswith('/') or os.path.isdir(fname): 72 fname = posixpath.join(fname, 'index.html') 73 f = open(fname) # self.path has /test.html 74 content_type = mimetypes.guess_type(fname)[0] 75 self.send_response(200) 76 self.send_header('Content-type', content_type) 77 self.end_headers() 78 while True: 79 data = f.read(2097152) 80 if not data: 81 break 82 self.wfile.write(data) 83 #self.wfile.write(f.read()) 84 f.close() 85 return 86 except IOError: 87 self.send_error(404, 'File Not Found: %s' % self.path)
88 89
90 -class TemplateHandler(DocrootHandler):
91 """ 92 Simple GET handler that loads and renders files/templates within a package 93 under the starcluster.templates package. You can set the _root_template_pkg 94 attribute on this class before passing to BaseHTTPServer to specify a 95 starcluster.templates subpackage to render templates from. Defaults to 96 rendering starcluster.templates (i.e. '/') 97 """ 98 _root_template_pkg = '/' 99 _tmpl_context = {} 100 _bin_exts = ('.ico', '.gif', '.jpg', '.png') 101
102 - def do_GET(self):
103 relpath = self.path[1:].split('?')[0] 104 if relpath == "shutdown": 105 self.do_shutdown() 106 return 107 fullpath = posixpath.join(self._root_template_pkg, relpath) 108 try: 109 if relpath.endswith(self._bin_exts): 110 data = templates.get_resource(fullpath).read() 111 else: 112 tmpl = templates.get_web_template(fullpath) 113 data = tmpl.render(**self._tmpl_context) 114 content_type = mimetypes.guess_type(os.path.basename(relpath))[0] 115 self.send_response(200) 116 self.send_header('Content-type', content_type) 117 self.end_headers() 118 self.wfile.write(data) 119 except IOError, templates.TemplateNotFound: 120 self.send_error(404, 'File Not Found: %s' % self.path) 121 return
122 123
124 -def get_template_server(root_template_pkg='/', interface="localhost", 125 port=None, context={}):
126 TemplateHandler._root_template_pkg = root_template_pkg 127 TemplateHandler._tmpl_context = context 128 server = get_webserver(interface=interface, port=port, 129 handler=TemplateHandler) 130 return server
131 132
133 -def get_webserver(interface="localhost", port=None, handler=DocrootHandler):
134 if port is None: 135 port = 0 136 server = StoppableHttpServer((interface, port), handler) 137 return server
138 139
140 -class BackgroundBrowser(webbrowser.GenericBrowser):
141 """Class for all browsers which are to be started in the background."""
142 - def open(self, url, new=0, autoraise=1):
143 cmdline = [self.name] + [arg.replace("%s", url) 144 for arg in self.args] 145 try: 146 if sys.platform[:3] == 'win': 147 p = subprocess.Popen(cmdline, stdout=subprocess.PIPE) 148 else: 149 setsid = getattr(os, 'setsid', None) 150 if not setsid: 151 setsid = getattr(os, 'setpgrp', None) 152 p = subprocess.Popen(cmdline, close_fds=True, 153 preexec_fn=setsid, stdout=subprocess.PIPE) 154 return (p.poll() is None) 155 except OSError: 156 return False
157 158
159 -def _is_exe(fpath):
160 return os.path.exists(fpath) and os.access(fpath, os.X_OK)
161 162
163 -def _which(program):
164 fpath, fname = os.path.split(program) 165 if fpath: 166 if _is_exe(program): 167 return program 168 else: 169 for path in os.environ["PATH"].split(os.pathsep): 170 exe_file = os.path.join(path, program) 171 if _is_exe(exe_file): 172 return exe_file
173 174
175 -def open_browser(url, browser_cmd=None):
176 if browser_cmd: 177 cmd = shlex.split(browser_cmd) 178 arg0 = cmd[0] 179 if not _which(arg0): 180 raise exception.BaseException("browser %s does not exist" % arg0) 181 if "%s" not in browser_cmd: 182 cmd.append("%s") 183 browser = BackgroundBrowser(cmd) 184 else: 185 # use 'default' browser from webbrowser module 186 browser = webbrowser.get() 187 browser_name = getattr(browser, 'name', None) 188 if not browser_name: 189 browser_name = getattr(browser, '_name', 'UNKNOWN') 190 log.info("Browsing %s using '%s'..." % (url, browser_name)) 191 return browser.open(url)
192 193
194 -def main(path, interface="localhost", port=8080):
195 try: 196 docroot = os.path.realpath(path) 197 globals()['DOCUMENTROOT'] = docroot 198 server = get_webserver(interface=interface, port=port, 199 handler=DocrootHandler) 200 log.info('Starting httpserver...') 201 log.info('Document_root = %s' % docroot) 202 server.serve_forever() 203 except KeyboardInterrupt: 204 print '^C received, shutting down server' 205 server.socket.close()
206 207 208 if __name__ == '__main__': 209 parser = optparse.OptionParser() 210 parser.add_option("-i", "--interface", dest="interface", action="store", 211 default="localhost") 212 parser.add_option("-p", "--port", dest="port", action="store", type="int", 213 default=8080) 214 opts, args = parser.parse_args() 215 if len(args) != 1: 216 parser.error('usage: webserver.py <document_root>') 217 path = args[0] 218 main(path, **opts.__dict__) 219