python-fcgi-19980130/0000755000175000017500000000000011772041355013504 5ustar mhabermhaberpython-fcgi-19980130/fcgi.py0000644000175000017500000003512211772015751014772 0ustar mhabermhaber#!/bin/env python #------------------------------------------------------------------------ # Copyright (c) 1998 by Total Control Software # All Rights Reserved #------------------------------------------------------------------------ # # Module Name: fcgi.py # # Description: Handles communication with the FastCGI module of the # web server without using the FastCGI developers kit, but # will also work in a non-FastCGI environment, (straight CGI.) # This module was originally fetched from someplace on the # Net (I don't remember where and I can't find it now...) and # has been significantly modified to fix several bugs, be more # readable, more robust at handling large CGI data and return # document sizes, and also to fit the model that we had previously # used for FastCGI. # # WARNING: If you don't know what you are doing, don't tinker with this # module! # # Creation Date: 1/30/98 2:59:04PM # # License: This is free software. You may use this software for any # purpose including modification/redistribution, so long as # this header remains intact and that you do not claim any # rights of ownership or authorship of this software. This # software has been tested, but no warranty is expressed or # implied. # #------------------------------------------------------------------------ import os, sys, string, socket, errno from cStringIO import StringIO import cgi #--------------------------------------------------------------------------- # Set various FastCGI constants # Maximum number of requests that can be handled FCGI_MAX_REQS=1 FCGI_MAX_CONNS = 1 # Supported version of the FastCGI protocol FCGI_VERSION_1 = 1 # Boolean: can this application multiplex connections? FCGI_MPXS_CONNS=0 # 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 # Types of management records ManagementTypes = [FCGI_GET_VALUES] FCGI_NULL_REQUEST_ID=0 # Masks for flags component of FCGI_BEGIN_REQUEST FCGI_KEEP_CONN = 1 # Values for role component of FCGI_BEGIN_REQUEST FCGI_RESPONDER = 1 ; FCGI_AUTHORIZER = 2 ; FCGI_FILTER = 3 # Values for protocolStatus component of FCGI_END_REQUEST FCGI_REQUEST_COMPLETE = 0 # Request completed nicely FCGI_CANT_MPX_CONN = 1 # This app can't multiplex FCGI_OVERLOADED = 2 # New request rejected; too busy FCGI_UNKNOWN_ROLE = 3 # Role value not known error = 'fcgi.error' #--------------------------------------------------------------------------- # The following function is used during debugging; it isn't called # anywhere at the moment def error(msg): "Append a string to /tmp/err" errf=open('/tmp/err', 'a+') errf.write(msg+'\n') errf.close() #--------------------------------------------------------------------------- class record: "Class representing FastCGI records" 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): s = map(ord, sock.recv(8)) self.version, self.recType, paddingLength = s[0], s[1], s[6] self.reqId, contentLength = (s[2]<<8)+s[3], (s[4]<<8)+s[5] self.content = "" while len(self.content) < contentLength: data = sock.recv(contentLength - len(self.content)) self.content = self.content + data if paddingLength != 0: padding = sock.recv(paddingLength) # Parse the content information 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 = readPair(c, pos) self.values[name] = value elif self.recType == FCGI_END_REQUEST: b = map(ord, c[0:4]) self.appStatus = (b[0]<<24) + (b[1]<<16) + (b[2]<<8) + b[3] self.protocolStatus = ord(c[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 + writePair(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 readPair(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] return ( s[pos:pos+nameLen], s[pos+nameLen:pos+nameLen+valueLen], pos+nameLen+valueLen ) #--------------------------------------------------------------------------- def writePair(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 #--------------------------------------------------------------------------- def HandleManTypes(r, conn): 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(conn) #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- _isFCGI = 1 # assume it is until we find out for sure def isFCGI(): global _isFCGI return _isFCGI #--------------------------------------------------------------------------- _init = None _sock = None class FCGI: def __init__(self): self.haveFinished = 0 if _init == None: _startup() if not isFCGI(): self.haveFinished = 1 self.inp, self.out, self.err, self.env = \ sys.stdin, sys.stdout, sys.stderr, os.environ return if os.environ.has_key('FCGI_WEB_SERVER_ADDRS'): good_addrs=string.split(os.environ['FCGI_WEB_SERVER_ADDRS'], ',') good_addrs=map(string.strip(good_addrs)) # Remove whitespace else: good_addrs=None self.conn, addr=_sock.accept() stdin, data="", "" self.env = {} self.requestId=0 remaining=1 # Check if the connection is from a legal address if good_addrs!=None and addr not in good_addrs: raise error, 'Connection from invalid server!' while remaining: r=record(); r.readRecord(self.conn) if r.recType in ManagementTypes: HandleManTypes(r, self.conn) elif r.reqId==0: # Oh, poopy. It's a management record of an unknown # type. Signal the error. r2=record() r2.recType=FCGI_UNKNOWN_TYPE ; r2.unknownType=r.recType r2.writeRecord(self.conn) continue # Charge onwards # Ignore requests that aren't active elif r.reqId != self.requestId and r.recType != FCGI_BEGIN_REQUEST: continue # If we're already doing a request, ignore further BEGIN_REQUESTs elif r.recType == FCGI_BEGIN_REQUEST and self.requestId != 0: continue # Begin a new request if r.recType == FCGI_BEGIN_REQUEST: self.requestId = 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: if r.content == "": remaining=remaining-1 else: for i in r.values.keys(): self.env[i] = r.values[i] elif r.recType == FCGI_STDIN: if r.content == "": remaining=remaining-1 else: stdin=stdin+r.content elif r.recType==FCGI_DATA: if r.content == "": remaining=remaining-1 else: data=data+r.content # end of while remaining: self.inp = sys.stdin = StringIO(stdin) self.err = sys.stderr = StringIO() self.out = sys.stdout = StringIO() self.data = StringIO(data) def __del__(self): self.Finish() def Finish(self, status=0): if not self.haveFinished: self.haveFinished = 1 self.err.seek(0,0) self.out.seek(0,0) r=record() r.recType = FCGI_STDERR r.reqId = self.requestId data = self.err.read() while data: chunk, data = self.getNextChunk(data) r.content = chunk r.writeRecord(self.conn) r.content="" ; r.writeRecord(self.conn) # Terminate stream r.recType = FCGI_STDOUT data = self.out.read() while data: chunk, data = self.getNextChunk(data) r.content = chunk r.writeRecord(self.conn) r.content="" ; r.writeRecord(self.conn) # Terminate stream r=record() r.recType=FCGI_END_REQUEST r.reqId=self.requestId r.appStatus=status r.protocolStatus=FCGI_REQUEST_COMPLETE r.writeRecord(self.conn) self.conn.close() def getFieldStorage(self): method = 'GET' if self.env.has_key('REQUEST_METHOD'): method = string.upper(self.env['REQUEST_METHOD']) if method == 'GET': return cgi.FieldStorage(environ=self.env, keep_blank_values=1) else: return cgi.FieldStorage(fp=self.inp, environ=self.env, keep_blank_values=1) def getNextChunk(self, data): chunk = data[:8192] data = data[8192:] return chunk, data Accept = FCGI # alias for backwards compatibility #--------------------------------------------------------------------------- def _startup(): global _init _init = 1 try: s=socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM) s.getpeername() except socket.error, (err, errmsg): if err!=errno.ENOTCONN: # must be a non-fastCGI environment global _isFCGI _isFCGI = 0 return global _sock _sock = s #--------------------------------------------------------------------------- def _test(): counter=0 try: while isFCGI(): req = Accept() counter=counter+1 try: fs = req.getFieldStorage() size = string.atoi(fs['size'].value) doc = ['*' * size] except: doc = ['FCGI TestApp\n\n'] doc.append('

FCGI TestApp

') doc.append('request count = %d
' % counter) doc.append('pid = %s
' % os.getpid()) if req.env.has_key('CONTENT_LENGTH'): cl = string.atoi(req.env['CONTENT_LENGTH']) doc.append('
POST data (%s):

' % cl)
                    keys = fs.keys()
                    keys.sort()
                    for k in keys:
                        val = fs[k]
                        if type(val) == type([]):
                            doc.append('    %-15s :  %s\n' % (k, val))
                        else:
                            doc.append('    %-15s :  %s\n' % (k, val.value))
                    doc.append('
') doc.append('


')
                keys = req.env.keys()
                keys.sort()
                for k in keys:
                    doc.append('%-20s :  %s\n' % (k, req.env[k]))
                doc.append('\n


\n') doc.append('\n') doc = string.join(doc, '') req.out.write('Content-length: %s\r\n' 'Content-type: text/html\r\n' 'Cache-Control: no-cache\r\n' '\r\n' % len(doc)) req.out.write(doc) req.Finish() except: import traceback f = open('traceback', 'w') traceback.print_exc( file = f ) # f.write('%s' % doc) if __name__=='__main__': #import pdb #pdb.run('_test()') _test() python-fcgi-19980130/setup.py0000700000175000017500000000226411772040343015207 0ustar mhabermhaber#!/usr/bin/python # -*- coding: utf-8 -*- """ Setup script for module fcgi downloaded from http://alldunn.com/python/fcgi.py """ from distutils.core import setup setup( #-- Package description name = 'python-fcgi', license = """This is free software. You may use this software for any purpose including modification/redistribution, so long as this header remains intact and that you do not claim any rights of ownership or authorship of this software. This software has been tested, but no warranty is expressed or implied. """, version = '19980130', description = 'Simple FastCGI module for Python', long_description = """Handles communication with the FastCGI module of the web server without using the FastCGI developers kit, but will also work in a non-FastCGI environment, (straight CGI.) """, author = 'Robin Dunn et al', author_email = 'robin@alldunn.com', url = 'http://alldunn.com/python/fcgi.py', py_modules = [ 'fcgi', ], classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: No Input/Output (Daemon)', 'Intended Audience :: Developers', 'Operating System :: OS Independent', 'Programming Language :: Python', ] ) python-fcgi-19980130/setup.cfg0000600000175000017500000000015411772017162015314 0ustar mhabermhaber[install] compile = 1 optimize = 1 [bdist_rpm] python=python requires=python group = Development/Libraries