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.scgi_base.BaseSCGIServer Class Reference

List of all members.

Public Member Functions

def __init__
def handler
def error

Public Attributes

 application
 scriptName
 environ
 multithreaded
 multiprocess
 debug
 logger

Static Public Attributes

 requestClass = Request

Private Member Functions

def _setupSocket
def _cleanupSocket
def _isClientAllowed
def _sanitizeEnv

Private Attributes

 _bindAddress
 _umask
 _allowedServers
 _appLock

Detailed Description

Definition at line 272 of file scgi_base.py.


Constructor & Destructor Documentation

def MoinMoin.support.flup.server.scgi_base.BaseSCGIServer.__init__ (   self,
  application,
  scriptName = NoDefault,
  environ = None,
  multithreaded = True,
  multiprocess = False,
  bindAddress = ('localhost', 4000,
  umask = None,
  allowedServers = NoDefault,
  loggingLevel = logging.INFO,
  debug = False 
)
scriptName is the initial portion of the URL path that "belongs"
to your application. It is used to determine PATH_INFO (which doesn't
seem to be passed in). An empty scriptName means your application
is mounted at the root of your virtual host.

environ, which must be a dictionary, can contain any additional
environment variables you want to pass to your application.

Set multithreaded to False if your application is not thread-safe.

Set multiprocess to True to explicitly set wsgi.multiprocess to
True. (Only makes sense with threaded servers.)

bindAddress is the address to bind to, which must be a string or
a tuple of length 2. If a tuple, the first element must be a string,
which is the host name or IPv4 address of a local interface. The
2nd element of the tuple is the port number. If a string, it will
be interpreted as a filename and a UNIX socket will be opened.

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.

allowedServers must be None or a list of strings representing the
IPv4 addresses of servers allowed to connect. None means accept
connections from anywhere. By default, it is a list containing
the single item '127.0.0.1'.

loggingLevel sets the logging level of the module-level logger.

Definition at line 280 of file scgi_base.py.

00280 
00281                  loggingLevel=logging.INFO, debug=False):
00282         """
00283         scriptName is the initial portion of the URL path that "belongs"
00284         to your application. It is used to determine PATH_INFO (which doesn't
00285         seem to be passed in). An empty scriptName means your application
00286         is mounted at the root of your virtual host.
00287 
00288         environ, which must be a dictionary, can contain any additional
00289         environment variables you want to pass to your application.
00290 
00291         Set multithreaded to False if your application is not thread-safe.
00292 
00293         Set multiprocess to True to explicitly set wsgi.multiprocess to
00294         True. (Only makes sense with threaded servers.)
00295 
00296         bindAddress is the address to bind to, which must be a string or
00297         a tuple of length 2. If a tuple, the first element must be a string,
00298         which is the host name or IPv4 address of a local interface. The
00299         2nd element of the tuple is the port number. If a string, it will
00300         be interpreted as a filename and a UNIX socket will be opened.
00301 
00302         If binding to a UNIX socket, umask may be set to specify what
00303         the umask is to be changed to before the socket is created in the
00304         filesystem. After the socket is created, the previous umask is
00305         restored.
00306         
00307         allowedServers must be None or a list of strings representing the
00308         IPv4 addresses of servers allowed to connect. None means accept
00309         connections from anywhere. By default, it is a list containing
00310         the single item '127.0.0.1'.
00311 
00312         loggingLevel sets the logging level of the module-level logger.
00313         """
00314         if environ is None:
00315             environ = {}
00316 
00317         self.application = application
00318         self.scriptName = scriptName
00319         self.environ = environ
00320         self.multithreaded = multithreaded
00321         self.multiprocess = multiprocess
00322         self.debug = debug
00323         self._bindAddress = bindAddress
00324         self._umask = umask
00325         if allowedServers is NoDefault:
00326             allowedServers = ['127.0.0.1']
00327         self._allowedServers = allowedServers
00328 
00329         # Used to force single-threadedness.
00330         self._appLock = thread.allocate_lock()
00331 
00332         self.logger = logging.getLogger(LoggerName)
00333         self.logger.setLevel(loggingLevel)


Member Function Documentation

Closes the main socket.

Definition at line 361 of file scgi_base.py.

00361 
00362     def _cleanupSocket(self, sock):
00363         """Closes the main socket."""
00364         sock.close()

Here is the caller graph for this function:

Definition at line 365 of file scgi_base.py.

00365 
00366     def _isClientAllowed(self, addr):
00367         ret = self._allowedServers is None or \
00368               len(addr) != 2 or \
00369               (len(addr) == 2 and addr[0] in self._allowedServers)
00370         if not ret:
00371             self.logger.warning('Server connection from %s disallowed',
00372                                 addr[0])
00373         return ret

Fill-in/deduce missing values in environ.

Definition at line 472 of file scgi_base.py.

00472 
00473     def _sanitizeEnv(self, environ):
00474         """Fill-in/deduce missing values in environ."""
00475         reqUri = None
00476         if environ.has_key('REQUEST_URI'):
00477             reqUri = environ['REQUEST_URI'].split('?', 1)
00478 
00479         # Ensure QUERY_STRING exists
00480         if not environ.has_key('QUERY_STRING') or not environ['QUERY_STRING']:
00481             if reqUri is not None and len(reqUri) > 1:
00482                 environ['QUERY_STRING'] = reqUri[1]
00483             else:
00484                 environ['QUERY_STRING'] = ''
00485 
00486         # Check WSGI_SCRIPT_NAME
00487         scriptName = environ.get('WSGI_SCRIPT_NAME')
00488         if scriptName is None:
00489             scriptName = self.scriptName
00490         else:
00491             warnings.warn('WSGI_SCRIPT_NAME environment variable for scgi '
00492                           'servers is deprecated',
00493                           DeprecationWarning)
00494             if scriptName.lower() == 'none':
00495                 scriptName = None
00496 
00497         if scriptName is None:
00498             # Do nothing (most likely coming from cgi2scgi)
00499             return
00500 
00501         if scriptName is NoDefault:
00502             # Pull SCRIPT_NAME/PATH_INFO from environment, with empty defaults
00503             if not environ.has_key('SCRIPT_NAME'):
00504                 environ['SCRIPT_NAME'] = ''
00505             if not environ.has_key('PATH_INFO') or not environ['PATH_INFO']:
00506                 if reqUri is not None:
00507                     environ['PATH_INFO'] = reqUri[0]
00508                 else:
00509                     environ['PATH_INFO'] = ''
00510         else:
00511             # Configured scriptName
00512             warnings.warn('Configured SCRIPT_NAME is deprecated\n'
00513                           'Do not use WSGI_SCRIPT_NAME or the scriptName\n'
00514                           'keyword parameter -- they will be going away',
00515                           DeprecationWarning)
00516 
00517             value = environ['SCRIPT_NAME']
00518             value += environ.get('PATH_INFO', '')
00519             if not value.startswith(scriptName):
00520                 self.logger.warning('scriptName does not match request URI')
00521 
00522             environ['PATH_INFO'] = value[len(scriptName):]
00523             environ['SCRIPT_NAME'] = scriptName

Here is the caller graph for this function:

Creates and binds the socket for communication with the server.

Definition at line 334 of file scgi_base.py.

00334 
00335     def _setupSocket(self):
00336         """Creates and binds the socket for communication with the server."""
00337         oldUmask = None
00338         if type(self._bindAddress) is str:
00339             # Unix socket
00340             sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
00341             try:
00342                 os.unlink(self._bindAddress)
00343             except OSError:
00344                 pass
00345             if self._umask is not None:
00346                 oldUmask = os.umask(self._umask)
00347         else:
00348             # INET socket
00349             assert type(self._bindAddress) is tuple
00350             assert len(self._bindAddress) == 2
00351             sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
00352             sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
00353 
00354         sock.bind(self._bindAddress)
00355         sock.listen(socket.SOMAXCONN)
00356 
00357         if oldUmask is not None:
00358             os.umask(oldUmask)
00359 
00360         return sock

Here is the caller graph for this function:

Override to provide custom error handling. Ideally, however,
all errors should be caught at the application level.

Definition at line 524 of file scgi_base.py.

00524 
00525     def error(self, request):
00526         """
00527         Override to provide custom error handling. Ideally, however,
00528         all errors should be caught at the application level.
00529         """
00530         if self.debug:
00531             import cgitb
00532             request.stdout.write('Content-Type: text/html\r\n\r\n' +
00533                                  cgitb.html(sys.exc_info()))
00534         else:
00535             errorpage = """<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
00536 <html><head>
00537 <title>Unhandled Exception</title>
00538 </head><body>
00539 <h1>Unhandled Exception</h1>
00540 <p>An unhandled exception was thrown by the application.</p>
00541 </body></html>
00542 """
00543             request.stdout.write('Content-Type: text/html\r\n\r\n' +
00544                                  errorpage)
WSGI handler. Sets up WSGI environment, calls the application,
and sends the application's response.

Definition at line 374 of file scgi_base.py.

00374 
00375     def handler(self, request):
00376         """
00377         WSGI handler. Sets up WSGI environment, calls the application,
00378         and sends the application's response.
00379         """
00380         environ = request.environ
00381         environ.update(self.environ)
00382 
00383         environ['wsgi.version'] = (1,0)
00384         environ['wsgi.input'] = request.stdin
00385         environ['wsgi.errors'] = sys.stderr
00386         environ['wsgi.multithread'] = self.multithreaded
00387         environ['wsgi.multiprocess'] = self.multiprocess
00388         environ['wsgi.run_once'] = False
00389 
00390         if environ.get('HTTPS', 'off') in ('on', '1'):
00391             environ['wsgi.url_scheme'] = 'https'
00392         else:
00393             environ['wsgi.url_scheme'] = 'http'
00394 
00395         self._sanitizeEnv(environ)
00396 
00397         headers_set = []
00398         headers_sent = []
00399         result = None
00400 
00401         def write(data):
00402             assert type(data) is str, 'write() argument must be string'
00403             assert headers_set, 'write() before start_response()'
00404 
00405             if not headers_sent:
00406                 status, responseHeaders = headers_sent[:] = headers_set
00407                 found = False
00408                 for header,value in responseHeaders:
00409                     if header.lower() == 'content-length':
00410                         found = True
00411                         break
00412                 if not found and result is not None:
00413                     try:
00414                         if len(result) == 1:
00415                             responseHeaders.append(('Content-Length',
00416                                                     str(len(data))))
00417                     except:
00418                         pass
00419                 s = 'Status: %s\r\n' % status
00420                 for header in responseHeaders:
00421                     s += '%s: %s\r\n' % header
00422                 s += '\r\n'
00423                 request.stdout.write(s)
00424 
00425             request.stdout.write(data)
00426             request.stdout.flush()
00427 
00428         def start_response(status, response_headers, exc_info=None):
00429             if exc_info:
00430                 try:
00431                     if headers_sent:
00432                         # Re-raise if too late
00433                         raise exc_info[0], exc_info[1], exc_info[2]
00434                 finally:
00435                     exc_info = None # avoid dangling circular ref
00436             else:
00437                 assert not headers_set, 'Headers already set!'
00438 
00439             assert type(status) is str, 'Status must be a string'
00440             assert len(status) >= 4, 'Status must be at least 4 characters'
00441             assert int(status[:3]), 'Status must begin with 3-digit code'
00442             assert status[3] == ' ', 'Status must have a space after code'
00443             assert type(response_headers) is list, 'Headers must be a list'
00444             if __debug__:
00445                 for name,val in response_headers:
00446                     assert type(name) is str, 'Header name "%s" must be a string' % name
00447                     assert type(val) is str, 'Value of header "%s" must be a string' % name
00448 
00449             headers_set[:] = [status, response_headers]
00450             return write
00451 
00452         if not self.multithreaded:
00453             self._appLock.acquire()
00454         try:
00455             try:
00456                 result = self.application(environ, start_response)
00457                 try:
00458                     for data in result:
00459                         if data:
00460                             write(data)
00461                     if not headers_sent:
00462                         write('') # in case body was empty
00463                 finally:
00464                     if hasattr(result, 'close'):
00465                         result.close()
00466             except socket.error, e:
00467                 if e[0] != errno.EPIPE:
00468                     raise # Don't let EPIPE propagate beyond server
00469         finally:
00470             if not self.multithreaded:
00471                 self._appLock.release()

Here is the call graph for this function:


Member Data Documentation

Definition at line 326 of file scgi_base.py.

Definition at line 329 of file scgi_base.py.

Definition at line 322 of file scgi_base.py.

Definition at line 323 of file scgi_base.py.

Definition at line 316 of file scgi_base.py.

Definition at line 321 of file scgi_base.py.

Definition at line 318 of file scgi_base.py.

Definition at line 331 of file scgi_base.py.

Definition at line 320 of file scgi_base.py.

Definition at line 319 of file scgi_base.py.

Definition at line 274 of file scgi_base.py.

Definition at line 317 of file scgi_base.py.


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