home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 January / maximum-cd-2011-01.iso / DiscContents / xbmc-9.11.exe / system / python / spyce / spyceWWW.py < prev    next >
Encoding:
Python Source  |  2009-12-23  |  11.4 KB  |  325 lines

  1. ##################################################
  2. # SPYCE - Python-based HTML Scripting
  3. # Copyright (c) 2002 Rimon Barr.
  4. #
  5. # Refer to spyce.py
  6. # CVS: $Id: spyceWWW.py 20864 2009-06-02 06:16:47Z ceros7 $
  7. ##################################################
  8.  
  9. import sys, os, string, socket, BaseHTTPServer, SocketServer, cgi, stat, time
  10. import spyce, spyceConfig, spyceException, spyceCmd, spyceUtil
  11.  
  12. __doc__ = '''Self-standing Spyce web server.'''
  13.  
  14. LOG = 1
  15.  
  16. def formatBytes(bytes):
  17.   bytes = float(bytes)
  18.   if bytes<=9999: return "%6.0f" % bytes
  19.   bytes = bytes / float(1024)
  20.   if bytes<=999: return "%5.1fK" % bytes
  21.   bytes = bytes / float(1024)
  22.   return "%5.1fM" % bytes
  23.  
  24. ##################################################
  25. # Request / response handlers
  26. #
  27.  
  28. class spyceHTTPRequest(spyce.spyceRequest):
  29.   'HTTP Spyce request object. (see spyce.spyceRequest)'
  30.   def __init__(self, httpdHandler, documentRoot):
  31.     spyce.spyceRequest.__init__(self)
  32.     self._in = httpdHandler.rfile
  33.     self._headers = httpdHandler.headers
  34.     self._httpdHandler = httpdHandler
  35.     self._documentRoot = documentRoot
  36.     self._env = None
  37.   def env(self, name=None):
  38.     if not self._env:
  39.       self._env = {
  40.         'REMOTE_ADDR': self._httpdHandler.client_address[0],
  41.         'REMOTE_PORT': self._httpdHandler.client_address[1],
  42.         'GATEWAY_INTERFACE': "CGI/1.1",
  43.         'REQUEST_METHOD': self._httpdHandler.command,
  44.         'REQUEST_URI': self._httpdHandler.path,
  45.         'PATH_INFO': self._httpdHandler.pathinfo,
  46.         'SERVER_SOFTWARE': 'spyce/%s' % spyce.__version__,
  47.         'SERVER_PROTOCOL': self._httpdHandler.request_version,
  48.         # 'SERVER_ADDR' ... '127.0.0.1'
  49.         # 'SERVER_PORT' ... '80'
  50.         # 'SERVER_NAME' ... 'mymachine.mydomain.com'
  51.         # 'SERVER_SIGNATURE' ... ' Apache/1.3.22 Server at mymachine.mydomain.com Port 80'
  52.         # 'SERVER_ADMIN'] ... 'rimon@acm.org'
  53.         'DOCUMENT_ROOT': self._documentRoot,
  54.         'QUERY_STRING': 
  55.           string.join(string.split(self._httpdHandler.path, '?')[1:]) or '',
  56.         'CONTENT_LENGTH': self.getHeader('Content-Length'),
  57.         'CONTENT_TYPE': self.getHeader('Content-type'),
  58.         'HTTP_USER_AGENT': self.getHeader('User-Agent'),
  59.         'HTTP_ACCEPT': self.getHeader('Accept'),
  60.         'HTTP_ACCEPT_ENCODING': self.getHeader('Accept-Encoding'),
  61.         'HTTP_ACCEPT_LANGUAGE': self.getHeader('Accept-Language'),
  62.         'HTTP_ACCEPT_CHARSET': self.getHeader('Accept-Charset'),
  63.         'HTTP_COOKIE': self.getHeader('Cookie'),
  64.         'HTTP_REFERER': self.getHeader('Referer'),
  65.         'HTTP_HOST': self.getHeader('Host'),
  66.         'HTTP_CONNECTION': self.getHeader('Connection'),
  67.         'HTTP_KEEP_ALIVE': self.getHeader('Keep-alive'),
  68.         # From ASP
  69.         # AUTH_TYPE, 
  70.         # APPL_PHYSICAL_PATH, 
  71.         # REMOTE_HOST,
  72.         # SERVER_PROTOCOL, 
  73.         # SERVER_SOFWARE
  74.       }
  75.     return spyceUtil.extractValue(self._env, name)
  76.   def getHeader(self, type=None):
  77.     if type: type=string.lower(type)
  78.     return spyceUtil.extractValue(self._headers.dict, type)
  79.   def getServerID(self):
  80.     return os.getpid()
  81.  
  82. class spyceHTTPResponse(spyceCmd.spyceCmdlineResponse):
  83.   'HTTP Spyce response object. (see spyce.spyceResponse)'
  84.   def __init__(self, httpdHandler):
  85.     self._httpheader = httpdHandler.request_version!='HTTP/0.9'
  86.     spyceCmd.spyceCmdlineResponse.__init__(self, spyceUtil.NoCloseOut(httpdHandler.wfile), sys.stdout, self._httpheader)
  87.     self._httpdHandler = httpdHandler
  88.     # incidentally, this a rather expensive operation!
  89.     if LOG:
  90.       httpdHandler.log_request()
  91.   def sendHeaders(self):
  92.     if self._httpheader and not self.headersSent:
  93.       resultText = spyceUtil.extractValue(self.RETURN_CODE, self.returncode)
  94.       self.origout.write('%s %s %s\n' % (self._httpdHandler.request_version, self.returncode, resultText))
  95.       spyceCmd.spyceCmdlineResponse.sendHeaders(self)
  96.   def close(self):
  97.     spyceCmd.spyceCmdlineResponse.close(self)
  98.     self._httpdHandler.request.close()
  99.  
  100.  
  101. ##################################################
  102. # Spyce web server
  103. #
  104.  
  105. class myHTTPhandler(BaseHTTPServer.BaseHTTPRequestHandler):
  106.   def do_GET(self):
  107.     try:
  108.       # parse pathinfo
  109.       pathinfo = os.path.normpath(string.split(self.path, '?')[0])
  110.       while pathinfo and (pathinfo[0]==os.sep or pathinfo[0:2]==os.pardir):
  111.         if pathinfo[0:len(os.sep)]==os.sep: pathinfo=pathinfo[len(os.sep):]
  112.         if pathinfo[0:len(os.pardir)]==os.pardir: pathinfo=pathinfo[len(os.pardir):]
  113.       self.pathinfo = "/"+pathinfo
  114.       # convert to path
  115.       path = os.path.join(self.server.documentRoot, pathinfo)
  116.       # directory listing
  117.       if os.path.isdir(path):
  118.         return self.handler_dir(path)
  119.       # search up path (path_info)
  120.       while len(path)>len(self.server.documentRoot) and not os.path.exists(path):
  121.         path, _ = os.path.split(path)
  122.       # for files (or links), find appropriate handler
  123.       if os.path.isfile(path) or os.path.islink(path):
  124.         _, ext = os.path.splitext(path)
  125.         if ext: ext = ext[1:]
  126.         try:
  127.           handler = self.server.handler[ext]
  128.         except:
  129.           handler = self.server.handler[None]
  130.         # process request
  131.         return handler(self, path)
  132.       # invalid path
  133.       self.send_error(404, "Invalid path")
  134.       return None
  135.     except IOError: 
  136.       self.send_error(404, "Unexpected IOError")
  137.       return None
  138.   do_POST=do_GET
  139.   def handler_spyce(self, path):
  140.     # process spyce
  141.     request = spyceHTTPRequest(self, self.server.documentRoot)
  142.     response = spyceHTTPResponse(self)
  143.     result = spyce.spyceFileHandler(request, response, path)
  144.     response.close()
  145.   def handler_dump(self, path):
  146.     # process content to dump (with correct mime type)
  147.     f = None
  148.     try:
  149.       try:
  150.         f = open(path, 'rb')
  151.       except IOError:
  152.         self.send_error(404, "No permission to open file")
  153.         return None
  154.       try:
  155.         _, ext = os.path.splitext(path)
  156.         if ext: ext=ext[1:]
  157.         mimetype = self.server.mimeTable[ext]
  158.       except:
  159.         mimetype = "application/octet-stream"
  160.       self.send_response(200)
  161.       self.send_header("Content-type", mimetype)
  162.       self.end_headers()
  163.       self.wfile.write(f.read())
  164.       self.request.close()
  165.     finally:
  166.       try:
  167.         if f: f.close()
  168.       except: pass
  169.   def handler_dir(self, path):
  170.     # process directory
  171.     if(self.path[-1:]!='/'):
  172.       self.send_response(301)
  173.       self.send_header('Location', self.path+'/')
  174.       self.end_headers()
  175.       return
  176.     try:
  177.       list = os.listdir(path)
  178.     except os.error:
  179.       self.send_error(404, "Path does not exist")
  180.       return None
  181.     list.sort(lambda a, b: cmp(a.lower(), b.lower()))
  182.     def info(name, path=path):
  183.       fullname = os.path.join(path, name)
  184.       displayname = linkname = name = cgi.escape(name)
  185.       # Append / for directories or @ for symbolic links
  186.       if os.path.isdir(fullname):
  187.         displayname = name + "/"
  188.         linkname = name + "/"
  189.       elif os.path.islink(fullname):
  190.         displayname = name + "@"
  191.       statinfo = os.stat(fullname)
  192.       mtime = statinfo[stat.ST_MTIME]
  193.       size = statinfo[stat.ST_SIZE]
  194.       return linkname, displayname, mtime, size
  195.     list = map(info, list)
  196.  
  197.     NAME_WIDTH = 30
  198.     output = '''
  199. <html><head>
  200.   <title>Index of %(title)s</title>
  201. </head>
  202. <body>
  203. <h1>Index of /%(title)s</h1>
  204. <pre> Name%(filler)s  Date%(filler_date)s  Size<hr/>''' % {
  205.     'title' : self.pathinfo,
  206.     'filler': ' '*(NAME_WIDTH-len('Name')),
  207.     'filler_date': ' '*(len(time.asctime(time.localtime(0)))-len('Date')),
  208.     }
  209.  
  210.     if list:
  211.       for link, display, mtime, size in list:
  212.         output = output + ' <a href="%(link)s">%(display)s</a>%(filler)s  %(mtime)s  %(size)s\n' % {
  213.           'link': link,
  214.           'display': display[:NAME_WIDTH],
  215.           'link': link,
  216.           'filler': ' '*(NAME_WIDTH-len(display)),
  217.           'mtime': time.asctime(time.localtime(mtime)),
  218.           'size': formatBytes(size),
  219.         }
  220.     else:
  221.       output = output + 'No files\n'
  222.  
  223.     output = output[:-1] + '''<hr/></pre>
  224. <address>Spyce-WWW/%(version)s server</address>
  225. </body></html>
  226. ''' % {
  227.     'version' : spyce.__version__,
  228.     }
  229.     self.send_response(200)
  230.     self.send_header("Content-type", "text/html")
  231.     self.end_headers()
  232.     self.wfile.write(output)
  233.  
  234. def buildMimeTable(files):
  235.   mimetable = {}
  236.   for file in files:
  237.     try:
  238.       f = None
  239.       try:
  240.         f = open(file, 'r')
  241.         print "#   MIME file: "+file
  242.         line = f.readline()
  243.         while line:
  244.           if line[0]=='#': 
  245.             line = f.readline(); continue
  246.           line = string.strip(line)
  247.           if not line:
  248.             line = f.readline(); continue
  249.           line = string.replace(line, '\t', ' ')
  250.           items = filter(None, map(string.strip, string.split(line, ' ')))
  251.           mimetype, extensions = items[0], items[1:]
  252.           for ext in extensions:
  253.             mimetable[ext] = mimetype
  254.           line = f.readline()
  255.       except IOError: pass
  256.     finally:
  257.       try:
  258.         if f: f.close()
  259.       except: pass
  260.   return mimetable
  261.  
  262. def buildHandlerTable(handler, server):
  263.   for ext in handler.keys():
  264.     handler[ext] = eval('server.handler_'+handler[ext])
  265.   return handler
  266.  
  267. def spyceHTTPserver(port, root, config_file=None, daemon=None):
  268.   os.environ[spyce.SPYCE_ENTRY] = 'www'
  269.   spyceCmd.showVersion()
  270.   print '# Starting web server'
  271.   # test for threading support, if needed
  272.   try:
  273.     server = spyce.getServer(
  274.       config_file=config_file, 
  275.       overide_www_port=port, 
  276.       overide_www_root=root)
  277.   except (spyceException.spyceForbidden, spyceException.spyceNotFound), e:
  278.     print e
  279.     return
  280.   if server.concurrency==spyceConfig.SPYCE_CONCURRENCY_THREAD:
  281.     spyceUtil.ThreadedWriter()  # will raise exception if 'import thread' fails
  282.   # determine type of server concurrency
  283.   serverSuperClass = {
  284.     spyceConfig.SPYCE_CONCURRENCY_SINGLE: SocketServer.TCPServer,
  285.     spyceConfig.SPYCE_CONCURRENCY_FORK:   SocketServer.ForkingTCPServer,
  286.     spyceConfig.SPYCE_CONCURRENCY_THREAD: SocketServer.ThreadingTCPServer,
  287.   } [server.concurrency]
  288.   class sharedSocketServer(serverSuperClass):
  289.     def server_bind(self):
  290.       self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  291.       SocketServer.TCPServer.server_bind(self)
  292.   try:
  293.     # initialize server
  294.     try:
  295.       httpd = sharedSocketServer(('',server.config.getSpyceWWWPort()), myHTTPhandler)
  296.       print '# Server Port: %d' % server.config.getSpyceWWWPort()
  297.       httpd.documentRoot = os.path.abspath(server.config.getSpyceWWWRoot())
  298.       print '# Server Root: '+httpd.documentRoot
  299.       httpd.mimeTable = buildMimeTable(server.config.getSpyceWWWMime())
  300.       httpd.handler = buildHandlerTable(server.config.getSpyceWWWHandler(), myHTTPhandler)
  301.     except:
  302.       print 'Unable to start server on port %s' % server.config.getSpyceWWWPort()
  303.       return -1
  304.     # daemonize
  305.     if daemon:
  306.       print '# Daemonizing process.'
  307.       try:
  308.         spyceCmd.daemonize(pidfile=daemon)
  309.       except SystemExit: # expected
  310.         return 0
  311.       global LOG
  312.       LOG = 0
  313.     # process requests
  314.     print '# Ready.'
  315.     while 1:
  316.       try:
  317.         httpd.handle_request()
  318.       except KeyboardInterrupt: raise
  319.       except:
  320.         print 'Error: %s' % spyceUtil.exceptionString()
  321.   except KeyboardInterrupt:
  322.     print 'Break!'
  323.   return 0
  324.  
  325.