I needed to get quixote up and running under windows, and since scgi's passfd.c doesn't compile under mingw32 I wrote an asyncore based scgi server. It's working fine together with scgi-cgi (however, scgi-cgi doesn't compile unchanged under mingw32 either). Patrik scgi_server.py: # Copyright 2003 by Patrik Simons, Neotide Ab (patrik.simons@neotide.fi) # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """Asyncore based SCGI server. Example use: import asyncore from quixote.publish import Publisher from scgi_server import SCGIServer, QuixoteProducer app = Publisher('test') # add app setup here class TestProducer(QuixoteProducer): publisher = app server = SCGIServer(TestProducer) asyncore.loop() """ import asynchat import asyncore import cStringIO import socket class SCGIServer(asyncore.dispatcher): def __init__(self, producer, here=('',4001)): asyncore.dispatcher.__init__(self) self.producer = producer self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind(here) self.listen(5) def handle_accept(self): sock_addr = self.accept() if sock_addr: sock, addr = sock_addr else: return # Failed SCGIHandler(sock, self.producer) class SCGIHandler(asynchat.async_chat): def __init__(self, sock, producer): asynchat.async_chat.__init__(self, sock) self.set_terminator(':') self.producer = producer self.env = None self.buffer = [] def collect_incoming_data(self, data): self.buffer.append(data) def found_terminator(self): data = ''.join(self.buffer) self.buffer = [] if self.get_terminator() == ':': self.set_terminator(int(data)+1) # Headers + comma return elif not self.env: self.env = self.read_env(data) length = int(self.env['CONTENT_LENGTH']) if length: self.set_terminator(length) return data = '' self.push_with_producer(self.producer(self.env, data)) self.close_when_done() self.env = None self.set_terminator(':') def read_env(self, data): headers = data.split('\0') headers = headers[:-1] # Skip ending comma assert len(headers)%2 == 0, 'malformed scgi headers' env = {} for i in xrange(0, len(headers), 2): env[headers[i]] = headers[i+1] return env class QuixoteProducer: publisher = None # Override in subclass def __init__(self, env, data): self.env = env self.data = data self.stdin = cStringIO.StringIO(data) self.stderr = self.publisher.error_log self.has_data = 1 def more(self): if not self.has_data: return '' stdout = cStringIO.StringIO() try: self.publisher.publish(self.stdin, stdout, self.stderr, self.env) except: pass #raise # Change to pass in production self.stdin.close() data = stdout.getvalue() stdout.close() self.has_data = 0 return data