
import string, cStringIO
from twisted.internet.app import Application
from twisted.protocols import http
from twisted.internet import reactor, protocol
from twisted.web import server

# Ports this server will listen on
HTTP_PORT = 8098
SCGI_PORT = 4000
SCGI_PROTOCOL_VERSION = "1"



class SCGIProtocol(protocol.Protocol):
    
    def connectionMade(self):
        self.transport.write(self.factory.hdr)
        
    def connectionLost(self, reason):
        self.factory.done =1

    def dataReceived(self,data):
        self.factory.data += data
        

class SCGIClientFactory(protocol.ClientFactory):

    def __init__(self,hdr):
        self.hdr = hdr
        self.done= 0
        self.data = ""

    def buildProtocol(self, addr):
        p = SCGIProtocol()
        p.factory = self
        self.protocol = p
        return p

class SCGIFactory (http.HTTPFactory):
    def buildProtocol (self, addr):
        h = http.HTTPChannel()
        h.requestFactory = SCGIRequest
        h.factory = self
        return h

class SCGIRequest (http.Request):
    def write(self, data):
        reactor.callFromThread(http.Request.write, self, data)

    def process(self):
        reactor.callInThread(self._process)

    def _process(self):
        ## this seek is important
        self.content.seek(0,0)
        resp = self.do_scgi_request()
        self.startedWriting = 1
        self.write(resp.replace("Status:", "HTTP/1.1"))
        self.finish()
        
    def do_scgi_request(self):
        data_out = self.get_data_for_scgi()
        factory =SCGIClientFactory(data_out)
        p = reactor.connectTCP("localhost", SCGI_PORT, factory)
        while not factory.done:
            reactor.iterate()
        return factory.data
        
    def get_data_for_scgi (self):
        host = self.getHeader('host') or self.getHost()
        if ':' in host:
            serverName = string.split(host, ':')[0]
        else:
            serverName = host
        content_type = self.getHeader('content-type')
        typ, remote_addr, remote_port = self.transport.getPeer()
        t = range(22)
        bdy = self.content.read()
        t[0] = "CONTENT_LENGTH",str(len(bdy or ""))
	t[1]= "SCGI", SCGI_PROTOCOL_VERSION
	t[2]= "SERVER_SOFTWARE", server.version or ""
	t[3]= "SERVER_PROTOCOL", self.clientproto or ""
	t[4]= "SERVER_NAME", serverName or ""
        t[5]= "SERVER_ADMIN", ""
        t[6]= "SERVER_ADDR", ""
        t[7]= "SERVER_PORT", str(HTTP_PORT)
        t[8]= "REMOTE_ADDR", self.getClientIP() or ""
        t[9]= "REMOTE_PORT", str(remote_port) or ""
        t[10]= "REMOTE_USER", self.getUser() or ""
        t[11]= "REQUEST_METHOD", self.method or ""
        t[12]= "REQUEST_URI", self.uri or ""
        x = self.uri.split('?', 2)
        if len(x) == 2:
            t[13]= "QUERY_STRING", x[1] or ""
        else:
            t[13]= "QUERY_STRING",""

        t[14]= "SCRIPT_NAME", self.uri
        #	/* skip PATH_INFO, it's always empty */
        t[15]= "HTTP_USER_AGENT", self.getHeader("User-Agent") or ""
        t[16]= "HTTP_COOKIE", self.getHeader("Cookie") or ""
        t[17]= "HTTPS", "" #lookup_env(r, "HTTPS")
        t[18]= "CONTENT_TYPE", self.getHeader("Content-type") or ""
        t[19]= "DOCUMENT_ROOT", "" #ap_document_root(r) 
        t[20]= "HTTP_ACCEPT", self.getHeader("Accept") or ""
        t[21]= "HTTP_REFERER", self.getHeader("Referer") or ""
        ### now make a netstring
        buffer=""
        for i in t:
            s = "%s\0%s\0" % i
            buffer += s
        n = len(buffer)
        buffer += ','
        ## addon the body 
        buffer += bdy
        ns = "%lu:" % n    
        ns += buffer
        return ns



def run():
    reactor.listenTCP(HTTP_PORT, SCGIFactory())
    reactor.run()


if __name__ == '__main__':
    run()
