Back to index

moin  1.9.0~rc2
Public Member Functions | Public Attributes | Static Public Attributes | Private Member Functions | Private Attributes
MoinMoin.support.flup.server.fcgi_base.BaseFCGIServer Class Reference

List of all members.

Public Member Functions

def __init__
def handler
def error

Public Attributes

 application
 environ
 multithreaded
 multiprocess
 debug
 roles
 forceCGI
 capability

Static Public Attributes

 request_class = Request
 cgirequest_class = CGIRequest
int maxwrite = 8192
int inputStreamShrinkThreshold = 102400

Private Member Functions

def _setupSocket
def _cleanupSocket
def _sanitizeEnv

Private Attributes

 _bindAddress
 _umask
 _appLock
 _connectionClass

Detailed Description

Definition at line 888 of file fcgi_base.py.


Constructor & Destructor Documentation

def MoinMoin.support.flup.server.fcgi_base.BaseFCGIServer.__init__ (   self,
  application,
  environ = None,
  multithreaded = True,
  multiprocess = False,
  bindAddress = None,
  umask = None,
  multiplexed = False,
  debug = False,
  roles = (FCGI_RESPONDER,,
  forceCGI = False 
)
bindAddress, if present, must either be a string or a 2-tuple. If
present, run() will open its own listening socket. You would use
this if you wanted to run your application as an 'external' FastCGI
app. (i.e. the webserver would no longer be responsible for starting
your app) If a string, it will be interpreted as a filename and a UNIX
socket will be opened. If a tuple, the first element, a string,
is the interface name/IP to bind to, and the second element (an int)
is the port number.

If binding to a UNIX socket, umask may be set to specify what
the umask is to be changed to before the socket is created in the
filesystem. After the socket is created, the previous umask is
restored.

Set multiplexed to True if you want to handle multiple requests
per connection. Some FastCGI backends (namely mod_fastcgi) don't
multiplex requests at all, so by default this is off (which saves
on thread creation/locking overhead). If threads aren't available,
this keyword is ignored; it's not possible to multiplex requests
at all.

Definition at line 906 of file fcgi_base.py.

00906 
00907                  forceCGI=False):
00908         """
00909         bindAddress, if present, must either be a string or a 2-tuple. If
00910         present, run() will open its own listening socket. You would use
00911         this if you wanted to run your application as an 'external' FastCGI
00912         app. (i.e. the webserver would no longer be responsible for starting
00913         your app) If a string, it will be interpreted as a filename and a UNIX
00914         socket will be opened. If a tuple, the first element, a string,
00915         is the interface name/IP to bind to, and the second element (an int)
00916         is the port number.
00917 
00918         If binding to a UNIX socket, umask may be set to specify what
00919         the umask is to be changed to before the socket is created in the
00920         filesystem. After the socket is created, the previous umask is
00921         restored.
00922         
00923         Set multiplexed to True if you want to handle multiple requests
00924         per connection. Some FastCGI backends (namely mod_fastcgi) don't
00925         multiplex requests at all, so by default this is off (which saves
00926         on thread creation/locking overhead). If threads aren't available,
00927         this keyword is ignored; it's not possible to multiplex requests
00928         at all.
00929         """
00930         if environ is None:
00931             environ = {}
00932 
00933         self.application = application
00934         self.environ = environ
00935         self.multithreaded = multithreaded
00936         self.multiprocess = multiprocess
00937         self.debug = debug
00938         self.roles = roles
00939         self.forceCGI = forceCGI
00940 
00941         self._bindAddress = bindAddress
00942         self._umask = umask
00943         
00944         # Used to force single-threadedness
00945         self._appLock = thread.allocate_lock()
00946 
00947         if thread_available:
00948             try:
00949                 import resource
00950                 # Attempt to glean the maximum number of connections
00951                 # from the OS.
00952                 maxConns = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
00953             except ImportError:
00954                 maxConns = 100 # Just some made up number.
00955             maxReqs = maxConns
00956             if multiplexed:
00957                 self._connectionClass = MultiplexedConnection
00958                 maxReqs *= 5 # Another made up number.
00959             else:
00960                 self._connectionClass = Connection
00961             self.capability = {
00962                 FCGI_MAX_CONNS: maxConns,
00963                 FCGI_MAX_REQS: maxReqs,
00964                 FCGI_MPXS_CONNS: multiplexed and 1 or 0
00965                 }
00966         else:
00967             self._connectionClass = Connection
00968             self.capability = {
00969                 # If threads aren't available, these are pretty much correct.
00970                 FCGI_MAX_CONNS: 1,
00971                 FCGI_MAX_REQS: 1,
00972                 FCGI_MPXS_CONNS: 0
00973                 }


Member Function Documentation

Closes the main socket.

Definition at line 1026 of file fcgi_base.py.

01026 
01027     def _cleanupSocket(self, sock):
01028         """Closes the main socket."""
01029         sock.close()

Here is the caller graph for this function:

Ensure certain values are present, if required by WSGI.

Definition at line 1137 of file fcgi_base.py.

01137 
01138     def _sanitizeEnv(self, environ):
01139         """Ensure certain values are present, if required by WSGI."""
01140         if not environ.has_key('SCRIPT_NAME'):
01141             environ['SCRIPT_NAME'] = ''
01142 
01143         reqUri = None
01144         if environ.has_key('REQUEST_URI'):
01145             reqUri = environ['REQUEST_URI'].split('?', 1)
01146 
01147         if not environ.has_key('PATH_INFO') or not environ['PATH_INFO']:
01148             if reqUri is not None:
01149                 environ['PATH_INFO'] = reqUri[0]
01150             else:
01151                 environ['PATH_INFO'] = ''
01152         if not environ.has_key('QUERY_STRING') or not environ['QUERY_STRING']:
01153             if reqUri is not None and len(reqUri) > 1:
01154                 environ['QUERY_STRING'] = reqUri[1]
01155             else:
01156                 environ['QUERY_STRING'] = ''
01157 
01158         # If any of these are missing, it probably signifies a broken
01159         # server...
01160         for name,default in [('REQUEST_METHOD', 'GET'),
01161                              ('SERVER_NAME', 'localhost'),
01162                              ('SERVER_PORT', '80'),
01163                              ('SERVER_PROTOCOL', 'HTTP/1.0')]:
01164             if not environ.has_key(name):
01165                 environ['wsgi.errors'].write('%s: missing FastCGI param %s '
01166                                              'required by WSGI!\n' %
01167                                              (self.__class__.__name__, name))
01168                 environ[name] = default
            

Here is the caller graph for this function:

Definition at line 974 of file fcgi_base.py.

00974 
00975     def _setupSocket(self):
00976         if self._bindAddress is None: # Run as a normal FastCGI?
00977             isFCGI = True
00978 
00979             sock = socket.fromfd(FCGI_LISTENSOCK_FILENO, socket.AF_INET,
00980                                  socket.SOCK_STREAM)
00981             try:
00982                 sock.getpeername()
00983             except socket.error, e:
00984                 if e[0] == errno.ENOTSOCK:
00985                     # Not a socket, assume CGI context.
00986                     isFCGI = False
00987                 elif e[0] != errno.ENOTCONN:
00988                     raise
00989 
00990             # FastCGI/CGI discrimination is broken on Mac OS X.
00991             # Set the environment variable FCGI_FORCE_CGI to "Y" or "y"
00992             # if you want to run your app as a simple CGI. (You can do
00993             # this with Apache's mod_env [not loaded by default in OS X
00994             # client, ha ha] and the SetEnv directive.)
00995             if not isFCGI or self.forceCGI or \
00996                os.environ.get('FCGI_FORCE_CGI', 'N').upper().startswith('Y'):
00997                 req = self.cgirequest_class(self)
00998                 req.run()
00999                 sys.exit(0)
01000         else:
01001             # Run as a server
01002             oldUmask = None
01003             if type(self._bindAddress) is str:
01004                 # Unix socket
01005                 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
01006                 try:
01007                     os.unlink(self._bindAddress)
01008                 except OSError:
01009                     pass
01010                 if self._umask is not None:
01011                     oldUmask = os.umask(self._umask)
01012             else:
01013                 # INET socket
01014                 assert type(self._bindAddress) is tuple
01015                 assert len(self._bindAddress) == 2
01016                 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
01017                 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
01018 
01019             sock.bind(self._bindAddress)
01020             sock.listen(socket.SOMAXCONN)
01021 
01022             if oldUmask is not None:
01023                 os.umask(oldUmask)
01024                 
01025         return sock

Here is the caller graph for this function:

Called by Request if an exception occurs within the handler. May and
should be overridden.

Definition at line 1169 of file fcgi_base.py.

01169 
01170     def error(self, req):
01171         """
01172         Called by Request if an exception occurs within the handler. May and
01173         should be overridden.
01174         """
01175         if self.debug:
01176             import cgitb
01177             req.stdout.write('Content-Type: text/html\r\n\r\n' +
01178                              cgitb.html(sys.exc_info()))
01179         else:
01180             errorpage = """<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
01181 <html><head>
01182 <title>Unhandled Exception</title>
01183 </head><body>
01184 <h1>Unhandled Exception</h1>
01185 <p>An unhandled exception was thrown by the application.</p>
01186 </body></html>
01187 """
01188             req.stdout.write('Content-Type: text/html\r\n\r\n' +
01189                              errorpage)
Special handler for WSGI.

Definition at line 1030 of file fcgi_base.py.

01030 
01031     def handler(self, req):
01032         """Special handler for WSGI."""
01033         if req.role not in self.roles:
01034             return FCGI_UNKNOWN_ROLE, 0
01035 
01036         # Mostly taken from example CGI gateway.
01037         environ = req.params
01038         environ.update(self.environ)
01039 
01040         environ['wsgi.version'] = (1,0)
01041         environ['wsgi.input'] = req.stdin
01042         if self._bindAddress is None:
01043             stderr = req.stderr
01044         else:
01045             stderr = TeeOutputStream((sys.stderr, req.stderr))
01046         environ['wsgi.errors'] = stderr
01047         environ['wsgi.multithread'] = not isinstance(req, CGIRequest) and \
01048                                       thread_available and self.multithreaded
01049         environ['wsgi.multiprocess'] = isinstance(req, CGIRequest) or \
01050                                        self.multiprocess
01051         environ['wsgi.run_once'] = isinstance(req, CGIRequest)
01052 
01053         if environ.get('HTTPS', 'off') in ('on', '1'):
01054             environ['wsgi.url_scheme'] = 'https'
01055         else:
01056             environ['wsgi.url_scheme'] = 'http'
01057 
01058         self._sanitizeEnv(environ)
01059 
01060         headers_set = []
01061         headers_sent = []
01062         result = None
01063 
01064         def write(data):
01065             assert type(data) is str, 'write() argument must be string'
01066             assert headers_set, 'write() before start_response()'
01067 
01068             if not headers_sent:
01069                 status, responseHeaders = headers_sent[:] = headers_set
01070                 found = False
01071                 for header,value in responseHeaders:
01072                     if header.lower() == 'content-length':
01073                         found = True
01074                         break
01075                 if not found and result is not None:
01076                     try:
01077                         if len(result) == 1:
01078                             responseHeaders.append(('Content-Length',
01079                                                     str(len(data))))
01080                     except:
01081                         pass
01082                 s = 'Status: %s\r\n' % status
01083                 for header in responseHeaders:
01084                     s += '%s: %s\r\n' % header
01085                 s += '\r\n'
01086                 req.stdout.write(s)
01087 
01088             req.stdout.write(data)
01089             req.stdout.flush()
01090 
01091         def start_response(status, response_headers, exc_info=None):
01092             if exc_info:
01093                 try:
01094                     if headers_sent:
01095                         # Re-raise if too late
01096                         raise exc_info[0], exc_info[1], exc_info[2]
01097                 finally:
01098                     exc_info = None # avoid dangling circular ref
01099             else:
01100                 assert not headers_set, 'Headers already set!'
01101 
01102             assert type(status) is str, 'Status must be a string'
01103             assert len(status) >= 4, 'Status must be at least 4 characters'
01104             assert int(status[:3]), 'Status must begin with 3-digit code'
01105             assert status[3] == ' ', 'Status must have a space after code'
01106             assert type(response_headers) is list, 'Headers must be a list'
01107             if __debug__:
01108                 for name,val in response_headers:
01109                     assert type(name) is str, 'Header name "%s" must be a string' % name
01110                     assert type(val) is str, 'Value of header "%s" must be a string' % name
01111 
01112             headers_set[:] = [status, response_headers]
01113             return write
01114 
01115         if not self.multithreaded:
01116             self._appLock.acquire()
01117         try:
01118             try:
01119                 result = self.application(environ, start_response)
01120                 try:
01121                     for data in result:
01122                         if data:
01123                             write(data)
01124                     if not headers_sent:
01125                         write('') # in case body was empty
01126                 finally:
01127                     if hasattr(result, 'close'):
01128                         result.close()
01129             except socket.error, e:
01130                 if e[0] != errno.EPIPE:
01131                     raise # Don't let EPIPE propagate beyond server
01132         finally:
01133             if not self.multithreaded:
01134                 self._appLock.release()
01135 
01136         return FCGI_REQUEST_COMPLETE, 0

Here is the call graph for this function:


Member Data Documentation

Definition at line 944 of file fcgi_base.py.

Definition at line 940 of file fcgi_base.py.

Definition at line 956 of file fcgi_base.py.

Definition at line 941 of file fcgi_base.py.

Definition at line 932 of file fcgi_base.py.

Definition at line 960 of file fcgi_base.py.

Definition at line 890 of file fcgi_base.py.

Definition at line 936 of file fcgi_base.py.

Definition at line 933 of file fcgi_base.py.

Definition at line 938 of file fcgi_base.py.

Definition at line 900 of file fcgi_base.py.

Definition at line 895 of file fcgi_base.py.

Definition at line 935 of file fcgi_base.py.

Definition at line 934 of file fcgi_base.py.

Definition at line 889 of file fcgi_base.py.

Definition at line 937 of file fcgi_base.py.


The documentation for this class was generated from the following file: