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

Source Code for Module starcluster.webtools

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