home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 May / maximum-cd-2009-05.iso / DiscContents / XBMC_for_Windows-8.10.exe / system / python / spyce / fcgi.py < prev    next >
Encoding:
Python Source  |  2008-11-03  |  9.2 KB  |  266 lines

  1. ##################################################
  2. # SPYCE - Python-based HTML Scripting
  3. # Copyright (c) 2002 Rimon Barr.
  4. #
  5. # Refer to spyce.py
  6. # CVS: $Id: fcgi.py 5659 2006-04-27 16:15:15Z jwnmulder $
  7. ##################################################
  8.  
  9. # Taken originally from: http://alldunn.com/python/fcgi.py
  10. # Edited a fair bit. -- RB
  11.  
  12. __doc__ = 'Python Fast CGI implementation'
  13.  
  14. import os, sys, string, socket, errno, cgi
  15. from cStringIO import StringIO
  16. import spyceUtil
  17.  
  18. ##################################################
  19. # Constants
  20. #
  21.  
  22. # Protol constants: record types
  23. FCGI_BEGIN_REQUEST     = 1
  24. FCGI_ABORT_REQUEST     = 2
  25. FCGI_END_REQUEST       = 3
  26. FCGI_PARAMS            = 4
  27. FCGI_STDIN             = 5
  28. FCGI_STDOUT            = 6
  29. FCGI_STDERR            = 7
  30. FCGI_DATA              = 8
  31. FCGI_GET_VALUES        = 9
  32. FCGI_GET_VALUES_RESULT = 10
  33. FCGI_UNKNOWN_TYPE      = 11
  34. FCGI_MAXTYPE           = FCGI_UNKNOWN_TYPE
  35. # Protocol constants: FCGI_BEGIN_REQUEST flag mask 
  36. FCGI_KEEP_CONN = 1
  37. # Protocol constants: FCGI_BEGIN_REQUEST role
  38. FCGI_RESPONDER  = 1
  39. FCGI_AUTHORIZER = 2
  40. FCGI_FILTER     = 3
  41. # Protocol constants: FCGI_END_REQUEST protocolStatus
  42. FCGI_REQUEST_COMPLETE = 0  # ok
  43. FCGI_CANT_MPX_CONN    = 1  # can not multiplex
  44. FCGI_OVERLOADED       = 2  # too busy
  45. FCGI_UNKNOWN_ROLE     = 3  # role unknown
  46. # Protocol constants: management record types
  47. FCGI_NULL_REQUEST_ID  = 0
  48.  
  49. # Protocol setting: maximum number of requests
  50. FCGI_MAX_REQS = 1
  51. FCGI_MAX_CONNS = 1
  52. # Protocol setting: can multiplex?
  53. FCGI_MPXS_CONNS = 0
  54. # Protocol setting: FastCGI protocol version
  55. FCGI_VERSION_1 = 1
  56.  
  57. ##################################################
  58. # Protocol
  59. #
  60.  
  61. class record:
  62.   def __init__(self):
  63.     self.version = FCGI_VERSION_1
  64.     self.recType = FCGI_UNKNOWN_TYPE
  65.     self.reqId   = FCGI_NULL_REQUEST_ID
  66.     self.content = ""
  67.   def readRecord(self, sock):
  68.     # read content
  69.     hdr = map(ord, self.readExact(sock, 8))
  70.     self.version  = hdr[0]
  71.     self.recType  = hdr[1]
  72.     self.reqId    = (hdr[2]<<8)+hdr[3]
  73.     contentLength = (hdr[4]<<8)+hdr[5]
  74.     paddingLength = hdr[6]
  75.     self.content  = self.readExact(sock, contentLength)
  76.     self.readExact(sock, paddingLength)
  77.     # parse
  78.     c = self.content
  79.     if self.recType == FCGI_BEGIN_REQUEST:
  80.       self.role = (ord(c[0])<<8) + ord(c[1])
  81.       self.flags = ord(c[2])
  82.     elif self.recType == FCGI_UNKNOWN_TYPE:
  83.       self.unknownType = ord(c[0])
  84.     elif self.recType == FCGI_GET_VALUES or self.recType == FCGI_PARAMS:
  85.       self.values={}
  86.       pos=0
  87.       while pos < len(c):
  88.         name, value, pos = self.decodePair(c, pos)
  89.         self.values[name] = value
  90.     elif self.recType == FCGI_END_REQUEST:
  91.       b = map(ord, c[0:5])
  92.       self.appStatus = (b[0]<<24) + (b[1]<<16) + (b[2]<<8) + b[3]
  93.       self.protocolStatus = b[4]
  94.   def writeRecord(self, sock):
  95.     content = self.content
  96.     if self.recType == FCGI_BEGIN_REQUEST:
  97.       content = chr(self.role>>8) + chr(self.role & 255) + chr(self.flags) + 5*'\000'
  98.     elif self.recType == FCGI_UNKNOWN_TYPE:
  99.       content = chr(self.unknownType) + 7*'\000'
  100.     elif self.recType==FCGI_GET_VALUES or self.recType==FCGI_PARAMS:
  101.       content = ""
  102.       for i in self.values.keys():
  103.         content = content + self.encodePair(i, self.values[i])
  104.     elif self.recType==FCGI_END_REQUEST:
  105.       v = self.appStatus
  106.       content = chr((v>>24)&255) + chr((v>>16)&255) + chr((v>>8)&255) + chr(v&255)
  107.       content = content + chr(self.protocolStatus) + 3*'\000'
  108.     cLen = len(content)
  109.     eLen = (cLen + 7) & (0xFFFF - 7)    # align to an 8-byte boundary
  110.     padLen = eLen - cLen
  111.     hdr = [ self.version, self.recType, self.reqId >> 8,
  112.       self.reqId & 255, cLen >> 8, cLen & 255, padLen, 0]
  113.     hdr = string.joinfields(map(chr, hdr), '')
  114.     sock.send(hdr + content + padLen*'\000')
  115.   def readExact(self, sock, amount):
  116.     data = ''
  117.     while amount and len(data) < amount:
  118.       data = data + sock.recv(amount-len(data))
  119.     return data
  120.   def decodePair(self, s, pos):
  121.     nameLen=ord(s[pos]) ; pos=pos+1
  122.     if nameLen & 128:
  123.       b=map(ord, s[pos:pos+3]) ; pos=pos+3
  124.       nameLen=((nameLen&127)<<24) + (b[0]<<16) + (b[1]<<8) + b[2]
  125.     valueLen=ord(s[pos]) ; pos=pos+1
  126.     if valueLen & 128:
  127.       b=map(ord, s[pos:pos+3]) ; pos=pos+3
  128.       valueLen=((valueLen&127)<<24) + (b[0]<<16) + (b[1]<<8) + b[2]
  129.     name = s[pos:pos+nameLen] ; pos = pos + nameLen
  130.     value = s[pos:pos+valueLen] ; pos = pos + valueLen
  131.     return name, value, pos
  132.   def encodePair(self, name, value):
  133.     l=len(name)
  134.     if l<128: s=chr(l)
  135.     else: s=chr(128|(l>>24)&255)+chr((l>>16)&255)+chr((l>>8)&255)+chr(l&255)
  136.     l=len(value)
  137.     if l<128: s=s+chr(l)
  138.     else: s=s+chr(128|(l>>24)&255)+chr((l>>16)&255)+chr((l>>8)&255)+chr(l&255)
  139.     return s + name + value
  140.  
  141. class FCGI:
  142.   def __init__(self, port=None):
  143.     # environment variables
  144.     try:
  145.       self.FCGI_PORT = int(os.environ['FCGI_PORT'])
  146.     except:
  147.       self.FCGI_PORT = None
  148.     if port: self.FCGI_PORT = port
  149.     self.FCGI_PORT = None
  150.     try:
  151.       self.FCGI_ALLOWED_ADDR = os.environ['FCGI_WEB_SERVER_ADDRS']
  152.       self.FCGI_ALLOWED_ADDR = map(string.strip, string.split(self.FCGI_ALLOWED_ADDR, ','))
  153.     except: 
  154.       self.FCGI_ALLOWED_ADDR = None
  155.     self.firstCall = 1
  156.     self.clearState()
  157.     self.socket = None
  158.     self.createServerSocket()
  159.   def createServerSocket(self):
  160.     if self.FCGI_PORT:
  161.       s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  162.       s.set_reuse_addr()
  163.       s.bind(('127.0.0.1', self.FCGI_PORT))
  164.     else:
  165.       try:
  166.         s=socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM)
  167.         s.getpeername()
  168.       except socket.error, (err, errmsg):
  169.         if err!=errno.ENOTCONN:
  170.           return
  171.       except:
  172.         return
  173.     self.socket = s
  174.   def accept(self):
  175.     if not self.socket:  # plain CGI
  176.       if self.firstCall:
  177.         result = sys.stdin, spyceUtil.NoCloseOut(sys.stdout), sys.stderr, os.environ
  178.       else:
  179.         return 0
  180.     else:  # FCGI
  181.       if not self.firstCall:
  182.         self.send()
  183.       result = self.recv()
  184.     self.firstCall = 0
  185.     return result
  186.   def clearState(self):
  187.     self.reqID      = 0
  188.     self.connection = None
  189.     self.environ    = {}
  190.     self.stdin      = StringIO()
  191.     self.stderr     = StringIO()
  192.     self.stdout     = StringIO()
  193.     self.data       = StringIO()
  194.   def send(self):
  195.     self.stderr.seek(0,0)
  196.     self.stdout.seek(0,0)
  197.     self.sendStream(FCGI_STDERR, self.stderr.read())
  198.     self.sendStream(FCGI_STDOUT, self.stdout.read())
  199.     r=record()
  200.     r.recType=FCGI_END_REQUEST
  201.     r.reqId=self.reqID
  202.     r.appStatus=0
  203.     r.protocolStatus=FCGI_REQUEST_COMPLETE
  204.     r.writeRecord(self.connection)
  205.     self.connection.close()
  206.     self.clearState()
  207.   def sendStream(self, streamType, streamData):
  208.     r=record()
  209.     r.recType = streamType
  210.     r.reqId = self.reqID
  211.     data = streamData
  212.     while data:
  213.       r.content, data = data[:8192], data[8192:]
  214.       r.writeRecord(self.connection)
  215.     r.content='' ; r.writeRecord(self.connection)
  216.   def recv(self):
  217.     self.connection, address = self.socket.accept()
  218.     # rimtodo: filter to serve only allowed addresses
  219.     # if good_addrs!=None and addr not in good_addrs:
  220.     #  raise 'Connection from invalid server!'
  221.     remaining=1
  222.     while remaining:
  223.       r=record(); r.readRecord(self.connection)
  224.       if r.recType in [FCGI_GET_VALUES]:  # management records
  225.         if r.recType == FCGI_GET_VALUES:
  226.           r.recType = FCGI_GET_VALUES_RESULT
  227.           v={}
  228.           vars={'FCGI_MAX_CONNS' : FCGI_MAX_CONNS,
  229.                 'FCGI_MAX_REQS'  : FCGI_MAX_REQS,
  230.                 'FCGI_MPXS_CONNS': FCGI_MPXS_CONNS}
  231.           for i in r.values.keys():
  232.             if vars.has_key(i): v[i]=vars[i]
  233.           r.values=vars
  234.           r.writeRecord(self.connection)
  235.       elif r.reqId == 0:  # management record of unknown type
  236.         r2 = record()
  237.         r2.recType = FCGI_UNKNOWN_TYPE ; r2.unknownType = r.recType
  238.         r2.writeRecord(self.connection)
  239.         continue
  240.       elif r.reqId != self.reqID and r.recType != FCGI_BEGIN_REQUEST:
  241.         continue # ignore inactive requests
  242.       elif r.recType == FCGI_BEGIN_REQUEST and self.reqID != 0:
  243.         continue # ignore BEGIN_REQUESTs in the middle of request
  244.       if r.recType == FCGI_BEGIN_REQUEST: # begin request
  245.         self.reqID = r.reqId
  246.         if r.role == FCGI_AUTHORIZER:   remaining=1
  247.         elif r.role == FCGI_RESPONDER:  remaining=2
  248.         elif r.role == FCGI_FILTER:     remaining=3
  249.       elif r.recType == FCGI_PARAMS:  # environment
  250.         if r.content == '': remaining=remaining-1
  251.         else:
  252.           for i in r.values.keys():
  253.             self.environ[i] = r.values[i]
  254.       elif r.recType == FCGI_STDIN:   # stdin
  255.         if r.content == '': remaining=remaining-1
  256.         else: self.stdin.write(r.content)
  257.       elif r.recType == FCGI_DATA:    # data
  258.         if r.content == '': remaining=remaining-1
  259.         else: self.data.write(r.content)
  260.     # end while
  261.     self.stdin.seek(0,0)
  262.     self.data.seek(0,0)
  263.     # return CGI environment
  264.     return self.stdin, spyceUtil.NoCloseOut(self.stdout), self.stderr, self.environ
  265.  
  266.