fcgi.py :  » Web-Frameworks » Spyce » spyce-2.1 » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Web Frameworks » Spyce 
Spyce » spyce 2.1 » fcgi.py
##################################################
# SPYCE - Python-based HTML Scripting
# Copyright (c) 2002 Rimon Barr.
#
# Refer to spyce.py
# CVS: $Id: fcgi.py 915 2006-07-20 00:00:51Z ellisj $
##################################################

# Taken originally from: http://alldunn.com/python/fcgi.py
# Edited a fair bit. -- RB

__doc__ = 'Python Fast CGI implementation'

import os, sys, string, socket, errno, cgi
from cStringIO import StringIO
import spyceUtil

##################################################
# Constants
#

# Protol constants: record types
FCGI_BEGIN_REQUEST     = 1
FCGI_ABORT_REQUEST     = 2
FCGI_END_REQUEST       = 3
FCGI_PARAMS            = 4
FCGI_STDIN             = 5
FCGI_STDOUT            = 6
FCGI_STDERR            = 7
FCGI_DATA              = 8
FCGI_GET_VALUES        = 9
FCGI_GET_VALUES_RESULT = 10
FCGI_UNKNOWN_TYPE      = 11
FCGI_MAXTYPE           = FCGI_UNKNOWN_TYPE
# Protocol constants: FCGI_BEGIN_REQUEST flag mask 
FCGI_KEEP_CONN = 1
# Protocol constants: FCGI_BEGIN_REQUEST role
FCGI_RESPONDER  = 1
FCGI_AUTHORIZER = 2
FCGI_FILTER     = 3
# Protocol constants: FCGI_END_REQUEST protocolStatus
FCGI_REQUEST_COMPLETE = 0  # ok
FCGI_CANT_MPX_CONN    = 1  # can not multiplex
FCGI_OVERLOADED       = 2  # too busy
FCGI_UNKNOWN_ROLE     = 3  # role unknown
# Protocol constants: management record types
FCGI_NULL_REQUEST_ID  = 0

# Protocol setting: maximum number of requests
FCGI_MAX_REQS = 1
FCGI_MAX_CONNS = 1
# Protocol setting: can multiplex?
FCGI_MPXS_CONNS = 0
# Protocol setting: FastCGI protocol version
FCGI_VERSION_1 = 1

##################################################
# Protocol
#

class record:
  def __init__(self):
    self.version = FCGI_VERSION_1
    self.recType = FCGI_UNKNOWN_TYPE
    self.reqId   = FCGI_NULL_REQUEST_ID
    self.content = ""
  def readRecord(self, sock):
    # read content
    hdr = map(ord, self.readExact(sock, 8))
    self.version  = hdr[0]
    self.recType  = hdr[1]
    self.reqId    = (hdr[2]<<8)+hdr[3]
    contentLength = (hdr[4]<<8)+hdr[5]
    paddingLength = hdr[6]
    self.content  = self.readExact(sock, contentLength)
    self.readExact(sock, paddingLength)
    # parse
    c = self.content
    if self.recType == FCGI_BEGIN_REQUEST:
      self.role = (ord(c[0])<<8) + ord(c[1])
      self.flags = ord(c[2])
    elif self.recType == FCGI_UNKNOWN_TYPE:
      self.unknownType = ord(c[0])
    elif self.recType == FCGI_GET_VALUES or self.recType == FCGI_PARAMS:
      self.values={}
      pos=0
      while pos < len(c):
        name, value, pos = self.decodePair(c, pos)
        self.values[name] = value
    elif self.recType == FCGI_END_REQUEST:
      b = map(ord, c[0:5])
      self.appStatus = (b[0]<<24) + (b[1]<<16) + (b[2]<<8) + b[3]
      self.protocolStatus = b[4]
  def writeRecord(self, sock):
    content = self.content
    if self.recType == FCGI_BEGIN_REQUEST:
      content = chr(self.role>>8) + chr(self.role & 255) + chr(self.flags) + 5*'\000'
    elif self.recType == FCGI_UNKNOWN_TYPE:
      content = chr(self.unknownType) + 7*'\000'
    elif self.recType==FCGI_GET_VALUES or self.recType==FCGI_PARAMS:
      content = ""
      for i in self.values.keys():
        content = content + self.encodePair(i, self.values[i])
    elif self.recType==FCGI_END_REQUEST:
      v = self.appStatus
      content = chr((v>>24)&255) + chr((v>>16)&255) + chr((v>>8)&255) + chr(v&255)
      content = content + chr(self.protocolStatus) + 3*'\000'
    cLen = len(content)
    eLen = (cLen + 7) & (0xFFFF - 7)    # align to an 8-byte boundary
    padLen = eLen - cLen
    hdr = [ self.version, self.recType, self.reqId >> 8,
      self.reqId & 255, cLen >> 8, cLen & 255, padLen, 0]
    hdr = string.joinfields(map(chr, hdr), '')
    sock.send(hdr + content + padLen*'\000')
  def readExact(self, sock, amount):
    data = ''
    while amount and len(data) < amount:
      data = data + sock.recv(amount-len(data))
    return data
  def decodePair(self, s, pos):
    nameLen=ord(s[pos]) ; pos=pos+1
    if nameLen & 128:
      b=map(ord, s[pos:pos+3]) ; pos=pos+3
      nameLen=((nameLen&127)<<24) + (b[0]<<16) + (b[1]<<8) + b[2]
    valueLen=ord(s[pos]) ; pos=pos+1
    if valueLen & 128:
      b=map(ord, s[pos:pos+3]) ; pos=pos+3
      valueLen=((valueLen&127)<<24) + (b[0]<<16) + (b[1]<<8) + b[2]
    name = s[pos:pos+nameLen] ; pos = pos + nameLen
    value = s[pos:pos+valueLen] ; pos = pos + valueLen
    return name, value, pos
  def encodePair(self, name, value):
    l=len(name)
    if l<128: s=chr(l)
    else: s=chr(128|(l>>24)&255)+chr((l>>16)&255)+chr((l>>8)&255)+chr(l&255)
    l=len(value)
    if l<128: s=s+chr(l)
    else: s=s+chr(128|(l>>24)&255)+chr((l>>16)&255)+chr((l>>8)&255)+chr(l&255)
    return s + name + value

class FCGI:
  def __init__(self, port=None):
    # environment variables
    try:
      self.FCGI_PORT = int(os.environ['FCGI_PORT'])
    except:
      self.FCGI_PORT = None
    if port: self.FCGI_PORT = port
    self.FCGI_PORT = None
    try:
      self.FCGI_ALLOWED_ADDR = os.environ['FCGI_WEB_SERVER_ADDRS']
      self.FCGI_ALLOWED_ADDR = map(string.strip, string.split(self.FCGI_ALLOWED_ADDR, ','))
    except: 
      self.FCGI_ALLOWED_ADDR = None
    self.firstCall = 1
    self.clearState()
    self.socket = None
    self.createServerSocket()
  def createServerSocket(self):
    if self.FCGI_PORT:
      s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      s.set_reuse_addr()
      s.bind(('127.0.0.1', self.FCGI_PORT))
    else:
      try:
        s=socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM)
        s.getpeername()
      except socket.error, (err, errmsg):
        if err!=errno.ENOTCONN:
          return
      except:
        return
    self.socket = s
  def accept(self):
    if not self.socket:  # plain CGI
      if self.firstCall:
        result = sys.stdin, spyceUtil.NoCloseOut(sys.stdout), sys.stderr, os.environ
      else:
        return 0
    else:  # FCGI
      result = self.recv()
    self.firstCall = 0
    return result
  def finish(self):
    if self.firstCall or not self.socket: return
    self.send()
  def clearState(self):
    self.reqID      = 0
    self.connection = None
    self.environ    = {}
    self.stdin      = StringIO()
    self.stderr     = StringIO()
    self.stdout     = StringIO()
    self.data       = StringIO()
  def send(self):
    self.stderr.seek(0,0)
    self.stdout.seek(0,0)
    self.sendStream(FCGI_STDERR, self.stderr.read())
    self.sendStream(FCGI_STDOUT, self.stdout.read())
    r=record()
    r.recType=FCGI_END_REQUEST
    r.reqId=self.reqID
    r.appStatus=0
    r.protocolStatus=FCGI_REQUEST_COMPLETE
    r.writeRecord(self.connection)
    self.connection.close()
    self.clearState()
  def sendStream(self, streamType, streamData):
    if not streamData:
      return
    r=record()
    r.recType = streamType
    r.reqId = self.reqID
    data = streamData
    while data:
      r.content, data = data[:8192], data[8192:]
      r.writeRecord(self.connection)
    r.content='' ; r.writeRecord(self.connection)
  def recv(self):
    self.connection, address = self.socket.accept()
    # rimtodo: filter to serve only allowed addresses
    # if good_addrs!=None and addr not in good_addrs:
    #  raise 'Connection from invalid server!'
    remaining=1
    while remaining:
      r=record(); r.readRecord(self.connection)
      if r.recType in [FCGI_GET_VALUES]:  # management records
        if r.recType == FCGI_GET_VALUES:
          r.recType = FCGI_GET_VALUES_RESULT
          v={}
          vars={'FCGI_MAX_CONNS' : FCGI_MAX_CONNS,
                'FCGI_MAX_REQS'  : FCGI_MAX_REQS,
                'FCGI_MPXS_CONNS': FCGI_MPXS_CONNS}
          for i in r.values.keys():
            if vars.has_key(i): v[i]=vars[i]
          r.values=vars
          r.writeRecord(self.connection)
      elif r.reqId == 0:  # management record of unknown type
        r2 = record()
        r2.recType = FCGI_UNKNOWN_TYPE ; r2.unknownType = r.recType
        r2.writeRecord(self.connection)
        continue
      elif r.reqId != self.reqID and r.recType != FCGI_BEGIN_REQUEST:
        continue # ignore inactive requests
      elif r.recType == FCGI_BEGIN_REQUEST and self.reqID != 0:
        continue # ignore BEGIN_REQUESTs in the middle of request
      if r.recType == FCGI_BEGIN_REQUEST: # begin request
        self.reqID = r.reqId
        if r.role == FCGI_AUTHORIZER:   remaining=1
        elif r.role == FCGI_RESPONDER:  remaining=2
        elif r.role == FCGI_FILTER:     remaining=3
      elif r.recType == FCGI_PARAMS:  # environment
        if r.content == '': remaining=remaining-1
        else:
          for i in r.values.keys():
            self.environ[i] = r.values[i]
      elif r.recType == FCGI_STDIN:   # stdin
        if r.content == '': remaining=remaining-1
        else: self.stdin.write(r.content)
      elif r.recType == FCGI_DATA:    # data
        if r.content == '': remaining=remaining-1
        else: self.data.write(r.content)
    # end while
    self.stdin.seek(0,0)
    self.data.seek(0,0)
    # return CGI environment
    return self.stdin, spyceUtil.NoCloseOut(self.stdout), self.stderr, self.environ

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.