Back to index

moin  1.9.0~rc2
fcgi_single.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      FCGI_MAX_CONNS, FCGI_MAX_REQS, FCGI_MPXS_CONNS
00056 from flup.server.singleserver import SingleServer
00057 
00058 __all__ = ['WSGIServer']
00059 
00060 class WSGIServer(BaseFCGIServer, SingleServer):
00061     """
00062     FastCGI server that supports the Web Server Gateway Interface. See
00063     <http://www.python.org/peps/pep-0333.html>.
00064     """
00065     def __init__(self, application, environ=None,
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=False,
00085                                 multiprocess=False,
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         SingleServer.__init__(self, jobClass=self._connectionClass,
00096                               jobArgs=(self,), **kw)
00097         self.capability = {
00098             FCGI_MAX_CONNS: 1,
00099             FCGI_MAX_REQS: 1,
00100             FCGI_MPXS_CONNS: 0
00101             }
00102 
00103     def _isClientAllowed(self, addr):
00104         return self._web_server_addrs is None or \
00105                (len(addr) == 2 and addr[0] in self._web_server_addrs)
00106 
00107     def run(self):
00108         """
00109         The main loop. Exits on SIGHUP, SIGINT, SIGTERM. Returns True if
00110         SIGHUP was received, False otherwise.
00111         """
00112         self._web_server_addrs = os.environ.get('FCGI_WEB_SERVER_ADDRS')
00113         if self._web_server_addrs is not None:
00114             self._web_server_addrs = map(lambda x: x.strip(),
00115                                          self._web_server_addrs.split(','))
00116 
00117         sock = self._setupSocket()
00118 
00119         ret = SingleServer.run(self, sock)
00120 
00121         self._cleanupSocket(sock)
00122 
00123         return ret
00124 
00125 if __name__ == '__main__':
00126     def test_app(environ, start_response):
00127         """Probably not the most efficient example."""
00128         import cgi
00129         start_response('200 OK', [('Content-Type', 'text/html')])
00130         yield '<html><head><title>Hello World!</title></head>\n' \
00131               '<body>\n' \
00132               '<p>Hello World!</p>\n' \
00133               '<table border="1">'
00134         names = environ.keys()
00135         names.sort()
00136         for name in names:
00137             yield '<tr><td>%s</td><td>%s</td></tr>\n' % (
00138                 name, cgi.escape(`environ[name]`))
00139 
00140         form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ,
00141                                 keep_blank_values=1)
00142         if form.list:
00143             yield '<tr><th colspan="2">Form data</th></tr>'
00144 
00145         for field in form.list:
00146             yield '<tr><td>%s</td><td>%s</td></tr>\n' % (
00147                 field.name, field.value)
00148 
00149         yield '</table>\n' \
00150               '</body></html>\n'
00151 
00152     from wsgiref import validate
00153     test_app = validate.validator(test_app)
00154     WSGIServer(test_app).run()