Back to index

moin  1.9.0~rc2
fcgi.py
Go to the documentation of this file.
00001 # Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
00002 # All rights reserved.
00003 #
00004 # Redistribution and use in source and binary forms, with or without
00005 # modification, are permitted provided that the following conditions
00006 # are met:
00007 # 1. Redistributions of source code must retain the above copyright
00008 #    notice, this list of conditions and the following disclaimer.
00009 # 2. Redistributions in binary form must reproduce the above copyright
00010 #    notice, this list of conditions and the following disclaimer in the
00011 #    documentation and/or other materials provided with the distribution.
00012 #
00013 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00014 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00015 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00016 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00017 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00018 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00019 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00020 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00021 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00022 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00023 # SUCH DAMAGE.
00024 #
00025 # $Id$
00026 
00027 """
00028 fcgi - a FastCGI/WSGI gateway.
00029 
00030 For more information about FastCGI, see <http://www.fastcgi.com/>.
00031 
00032 For more information about the Web Server Gateway Interface, see
00033 <http://www.python.org/peps/pep-0333.html>.
00034 
00035 Example usage:
00036 
00037   #!/usr/bin/env python
00038   from myapplication import app # Assume app is your WSGI application object
00039   from fcgi import WSGIServer
00040   WSGIServer(app).run()
00041 
00042 See the documentation for WSGIServer for more information.
00043 
00044 On most platforms, fcgi will fallback to regular CGI behavior if run in a
00045 non-FastCGI context. If you want to force CGI behavior, set the environment
00046 variable FCGI_FORCE_CGI to "Y" or "y".
00047 """
00048 
00049 __author__ = 'Allan Saddi <allan@saddi.com>'
00050 __version__ = '$Revision$'
00051 
00052 import os
00053 
00054 from flup.server.fcgi_base import BaseFCGIServer, FCGI_RESPONDER
00055 from flup.server.threadedserver import ThreadedServer
00056 
00057 __all__ = ['WSGIServer']
00058 
00059 class WSGIServer(BaseFCGIServer, ThreadedServer):
00060     """
00061     FastCGI server that supports the Web Server Gateway Interface. See
00062     <http://www.python.org/peps/pep-0333.html>.
00063     """
00064     def __init__(self, application, environ=None,
00065                  multithreaded=True, multiprocess=False,
00066                  bindAddress=None, umask=None, multiplexed=False,
00067                  debug=False, roles=(FCGI_RESPONDER,), forceCGI=False, **kw):
00068         """
00069         environ, if present, must be a dictionary-like object. Its
00070         contents will be copied into application's environ. Useful
00071         for passing application-specific variables.
00072 
00073         bindAddress, if present, must either be a string or a 2-tuple. If
00074         present, run() will open its own listening socket. You would use
00075         this if you wanted to run your application as an 'external' FastCGI
00076         app. (i.e. the webserver would no longer be responsible for starting
00077         your app) If a string, it will be interpreted as a filename and a UNIX
00078         socket will be opened. If a tuple, the first element, a string,
00079         is the interface name/IP to bind to, and the second element (an int)
00080         is the port number.
00081         """
00082         BaseFCGIServer.__init__(self, application,
00083                                 environ=environ,
00084                                 multithreaded=multithreaded,
00085                                 multiprocess=multiprocess,
00086                                 bindAddress=bindAddress,
00087                                 umask=umask,
00088                                 multiplexed=multiplexed,
00089                                 debug=debug,
00090                                 roles=roles,
00091                                 forceCGI=forceCGI)
00092         for key in ('jobClass', 'jobArgs'):
00093             if kw.has_key(key):
00094                 del kw[key]
00095         ThreadedServer.__init__(self, jobClass=self._connectionClass,
00096                                 jobArgs=(self,), **kw)
00097 
00098     def _isClientAllowed(self, addr):
00099         return self._web_server_addrs is None or \
00100                (len(addr) == 2 and addr[0] in self._web_server_addrs)
00101 
00102     def run(self):
00103         """
00104         The main loop. Exits on SIGHUP, SIGINT, SIGTERM. Returns True if
00105         SIGHUP was received, False otherwise.
00106         """
00107         self._web_server_addrs = os.environ.get('FCGI_WEB_SERVER_ADDRS')
00108         if self._web_server_addrs is not None:
00109             self._web_server_addrs = map(lambda x: x.strip(),
00110                                          self._web_server_addrs.split(','))
00111 
00112         sock = self._setupSocket()
00113 
00114         ret = ThreadedServer.run(self, sock)
00115 
00116         self._cleanupSocket(sock)
00117         self.shutdown()
00118 
00119         return ret
00120 
00121 if __name__ == '__main__':
00122     def test_app(environ, start_response):
00123         """Probably not the most efficient example."""
00124         import cgi
00125         start_response('200 OK', [('Content-Type', 'text/html')])
00126         yield '<html><head><title>Hello World!</title></head>\n' \
00127               '<body>\n' \
00128               '<p>Hello World!</p>\n' \
00129               '<table border="1">'
00130         names = environ.keys()
00131         names.sort()
00132         for name in names:
00133             yield '<tr><td>%s</td><td>%s</td></tr>\n' % (
00134                 name, cgi.escape(`environ[name]`))
00135 
00136         form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ,
00137                                 keep_blank_values=1)
00138         if form.list:
00139             yield '<tr><th colspan="2">Form data</th></tr>'
00140 
00141         for field in form.list:
00142             yield '<tr><td>%s</td><td>%s</td></tr>\n' % (
00143                 field.name, field.value)
00144 
00145         yield '</table>\n' \
00146               '</body></html>\n'
00147 
00148     from wsgiref import validate
00149     test_app = validate.validator(test_app)
00150     WSGIServer(test_app).run()