#!/usr/bin/env python """WSGIAdapter.py This is the WSGI Adapter for the WebKit AppServer. The socket address of the WebKit AppServer can be specified with the Host and AdapterPort settings in the configuration file called 'WSGIAdapter.config' (default is localhost on port 8086). Note that this adapter script and the AppServer must be running with marshal-compatible Python versions (check marshal.version). Contributed to Webware for Python by Christoph Zwerschke, 04/2010. """ # If you used the MakeAppWorkDir.py script to make a separate # application working directory, specify it here: workDir = None # If the Webware installation is located somewhere else, # then set the webwareDir variable to point to it here: webwareDir = None import os, sys if not webwareDir: webwareDir = os.path.dirname(os.path.dirname( os.path.abspath(os.path.dirname(__file__)))) sys.path.insert(0, webwareDir) webKitDir = os.path.join(webwareDir, 'WebKit') sys.path.insert(0, webKitDir) if not workDir: workDir = webKitDir from WebKit.Adapters.Adapter import Adapter class StdErr(object): """Auxiliary store for temporary redirection of sys.stderr.""" def __init__(self, stderr): if stderr: self.stderr, sys.stderr = sys.stderr, stderr else: self.stderr = None def close(self): if self.stderr: self.stderr, sys.stderr = None, self.stderr def __del__(self): self.close() class WSGIAdapter(Adapter): """WSGI application interfacing to the Webware application server.""" def __call__(self, environ, start_response): """The actual WSGI application.""" err = StdErr(environ.get('wsgi.errors', None)) try: inp = environ.get('wsgi.input', None) if inp is not None: try: inp_len = int(environ['CONTENT_LENGTH']) if inp_len <= 0: raise ValueError except (KeyError, ValueError): inp = None else: try: inp = inp.read(inp_len) except IOError: inp = None # we pass only environment variables that can be marshalled environ = dict(item for item in environ.iteritems() if isinstance(item[1], (bool, int, long, float, str, unicode, tuple, list, set, frozenset, dict))) response = self.getChunksFromAppServer(environ, inp or '') header = [] for chunk in response: if header is None: yield chunk else: chunk = chunk.split('\r\n\r\n', 1) header.append(chunk[0]) if len(chunk) > 1: chunk = chunk[1] header = ''.join(header).split('\r\n') status = header.pop(0).split(': ', 1)[-1] header = [tuple(line.split(': ', 1)) for line in header] start_response(status, header) header = None if chunk: yield chunk except: # This is a workaround for Python 2.4 which does not allow a # yield statement to live in a try block with a finally clause. # Note that this also works if the generator is simply abandoned # even though Python 2.4 does not raise a GeneratorExit, because # if the generator is deleted, the local variable err also gets # deleted and its close() method will be called by its destructor. err.close() raise # re-raise the original exception else: err.close() # Create one WSGI application instance: wsgiAdapter = WSGIAdapter(workDir) application = wsgiAdapter # the name expected by mod_wsgi