Back to index

moin  1.9.0~rc2
Public Member Functions | Private Member Functions | Private Attributes | Static Private Attributes
MoinMoin.support.flup.client.fcgi_app.FCGIApp Class Reference

List of all members.

Public Member Functions

def __init__
def __call__

Private Member Functions

def _getConnection
def _fcgiGetValues
def _fcgiParams
def _defaultFilterEnviron
def _lightFilterEnviron

Private Attributes

 _command
 _connect
 _filterEnviron

Static Private Attributes

list _environPrefixes
list _environCopies = ['SCRIPT_NAME', 'QUERY_STRING', 'AUTH_TYPE']
dictionary _environRenames = {}

Detailed Description

Definition at line 258 of file fcgi_app.py.


Constructor & Destructor Documentation

def MoinMoin.support.flup.client.fcgi_app.FCGIApp.__init__ (   self,
  command = None,
  connect = None,
  host = None,
  port = None,
  filterEnviron = True 
)

Definition at line 260 of file fcgi_app.py.

00260 
00261                  filterEnviron=True):
00262         if host is not None:
00263             assert port is not None
00264             connect=(host, port)
00265 
00266         assert (command is not None and connect is None) or \
00267                (command is None and connect is not None)
00268 
00269         self._command = command
00270         self._connect = connect
00271 
00272         self._filterEnviron = filterEnviron
00273         
00274         #sock = self._getConnection()
00275         #print self._fcgiGetValues(sock, ['FCGI_MAX_CONNS', 'FCGI_MAX_REQS', 'FCGI_MPXS_CONNS'])
00276         #sock.close()
        

Member Function Documentation

def MoinMoin.support.flup.client.fcgi_app.FCGIApp.__call__ (   self,
  environ,
  start_response 
)

Definition at line 277 of file fcgi_app.py.

00277 
00278     def __call__(self, environ, start_response):
00279         # For sanity's sake, we don't care about FCGI_MPXS_CONN
00280         # (connection multiplexing). For every request, we obtain a new
00281         # transport socket, perform the request, then discard the socket.
00282         # This is, I believe, how mod_fastcgi does things...
00283 
00284         sock = self._getConnection()
00285 
00286         # Since this is going to be the only request on this connection,
00287         # set the request ID to 1.
00288         requestId = 1
00289 
00290         # Begin the request
00291         rec = Record(FCGI_BEGIN_REQUEST, requestId)
00292         rec.contentData = struct.pack(FCGI_BeginRequestBody, FCGI_RESPONDER, 0)
00293         rec.contentLength = FCGI_BeginRequestBody_LEN
00294         rec.write(sock)
00295 
00296         # Filter WSGI environ and send it as FCGI_PARAMS
00297         if self._filterEnviron:
00298             params = self._defaultFilterEnviron(environ)
00299         else:
00300             params = self._lightFilterEnviron(environ)
00301         # TODO: Anything not from environ that needs to be sent also?
00302         self._fcgiParams(sock, requestId, params)
00303         self._fcgiParams(sock, requestId, {})
00304 
00305         # Transfer wsgi.input to FCGI_STDIN
00306         content_length = int(environ.get('CONTENT_LENGTH') or 0)
00307         while True:
00308             chunk_size = min(content_length, 4096)
00309             s = environ['wsgi.input'].read(chunk_size)
00310             content_length -= len(s)
00311             rec = Record(FCGI_STDIN, requestId)
00312             rec.contentData = s
00313             rec.contentLength = len(s)
00314             rec.write(sock)
00315 
00316             if not s: break
00317 
00318         # Empty FCGI_DATA stream
00319         rec = Record(FCGI_DATA, requestId)
00320         rec.write(sock)
00321 
00322         # Main loop. Process FCGI_STDOUT, FCGI_STDERR, FCGI_END_REQUEST
00323         # records from the application.
00324         result = []
00325         while True:
00326             inrec = Record()
00327             inrec.read(sock)
00328             if inrec.type == FCGI_STDOUT:
00329                 if inrec.contentData:
00330                     result.append(inrec.contentData)
00331                 else:
00332                     # TODO: Should probably be pedantic and no longer
00333                     # accept FCGI_STDOUT records?
00334                     pass
00335             elif inrec.type == FCGI_STDERR:
00336                 # Simply forward to wsgi.errors
00337                 environ['wsgi.errors'].write(inrec.contentData)
00338             elif inrec.type == FCGI_END_REQUEST:
00339                 # TODO: Process appStatus/protocolStatus fields?
00340                 break
00341 
00342         # Done with this transport socket, close it. (FCGI_KEEP_CONN was not
00343         # set in the FCGI_BEGIN_REQUEST record we sent above. So the
00344         # application is expected to do the same.)
00345         sock.close()
00346 
00347         result = ''.join(result)
00348 
00349         # Parse response headers from FCGI_STDOUT
00350         status = '200 OK'
00351         headers = []
00352         pos = 0
00353         while True:
00354             eolpos = result.find('\n', pos)
00355             if eolpos < 0: break
00356             line = result[pos:eolpos-1]
00357             pos = eolpos + 1
00358 
00359             # strip in case of CR. NB: This will also strip other
00360             # whitespace...
00361             line = line.strip()
00362             
00363             # Empty line signifies end of headers
00364             if not line: break
00365 
00366             # TODO: Better error handling
00367             header, value = line.split(':', 1)
00368             header = header.strip().lower()
00369             value = value.strip()
00370 
00371             if header == 'status':
00372                 # Special handling of Status header
00373                 status = value
00374                 if status.find(' ') < 0:
00375                     # Append a dummy reason phrase if one was not provided
00376                     status += ' FCGIApp'
00377             else:
00378                 headers.append((header, value))
00379 
00380         result = result[pos:]
00381 
00382         # Set WSGI status, headers, and return result.
00383         start_response(status, headers)
00384         return [result]

Here is the call graph for this function:

Definition at line 436 of file fcgi_app.py.

00436 
00437     def _defaultFilterEnviron(self, environ):
00438         result = {}
00439         for n in environ.keys():
00440             for p in self._environPrefixes:
00441                 if n.startswith(p):
00442                     result[n] = environ[n]
00443             if n in self._environCopies:
00444                 result[n] = environ[n]
00445             if n in self._environRenames:
00446                 result[self._environRenames[n]] = environ[n]
00447                 
00448         return result

Here is the caller graph for this function:

def MoinMoin.support.flup.client.fcgi_app.FCGIApp._fcgiGetValues (   self,
  sock,
  vars 
) [private]

Definition at line 399 of file fcgi_app.py.

00399 
00400     def _fcgiGetValues(self, sock, vars):
00401         # Construct FCGI_GET_VALUES record
00402         outrec = Record(FCGI_GET_VALUES)
00403         data = []
00404         for name in vars:
00405             data.append(encode_pair(name, ''))
00406         data = ''.join(data)
00407         outrec.contentData = data
00408         outrec.contentLength = len(data)
00409         outrec.write(sock)
00410 
00411         # Await response
00412         inrec = Record()
00413         inrec.read(sock)
00414         result = {}
00415         if inrec.type == FCGI_GET_VALUES_RESULT:
00416             pos = 0
00417             while pos < inrec.contentLength:
00418                 pos, (name, value) = decode_pair(inrec.contentData, pos)
00419                 result[name] = value
00420         return result

Here is the call graph for this function:

def MoinMoin.support.flup.client.fcgi_app.FCGIApp._fcgiParams (   self,
  sock,
  requestId,
  params 
) [private]

Definition at line 421 of file fcgi_app.py.

00421 
00422     def _fcgiParams(self, sock, requestId, params):
00423         rec = Record(FCGI_PARAMS, requestId)
00424         data = []
00425         for name,value in params.items():
00426             data.append(encode_pair(name, value))
00427         data = ''.join(data)
00428         rec.contentData = data
00429         rec.contentLength = len(data)
00430         rec.write(sock)

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 385 of file fcgi_app.py.

00385 
00386     def _getConnection(self):
00387         if self._connect is not None:
00388             # The simple case. Create a socket and connect to the
00389             # application.
00390             if type(self._connect) is str:
00391                 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
00392             else:
00393                 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
00394             sock.connect(self._connect)
00395             return sock
00396 
00397         # To be done when I have more time...
00398         raise NotImplementedError, 'Launching and managing FastCGI programs not yet implemented'
    

Here is the caller graph for this function:

Definition at line 449 of file fcgi_app.py.

00449 
00450     def _lightFilterEnviron(self, environ):
00451         result = {}
00452         for n in environ.keys():
00453             if n.upper() == n:
00454                 result[n] = environ[n]
00455         return result

Here is the caller graph for this function:


Member Data Documentation

Definition at line 268 of file fcgi_app.py.

Definition at line 269 of file fcgi_app.py.

list MoinMoin.support.flup.client.fcgi_app.FCGIApp._environCopies = ['SCRIPT_NAME', 'QUERY_STRING', 'AUTH_TYPE'] [static, private]

Definition at line 433 of file fcgi_app.py.

Initial value:
['SERVER_', 'HTTP_', 'REQUEST_', 'REMOTE_', 'PATH_',
                        'CONTENT_']

Definition at line 431 of file fcgi_app.py.

Definition at line 434 of file fcgi_app.py.

Definition at line 271 of file fcgi_app.py.


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