Back to index

moin  1.9.0~rc2
Public Member Functions | Public Attributes
MoinMoin.support.werkzeug.contrib.lint.LintMiddleware Class Reference

List of all members.

Public Member Functions

def __init__
def check_environ
def check_start_response
def check_headers
def check_iterator
def __call__

Public Attributes

 app

Detailed Description

This middleware wraps an application and warns on common errors.
Among other thing it currently checks for the following problems:

-   invalid status codes
-   non-bytestrings sent to the WSGI server
-   strings returned from the WSGI application
-   non-empty conditional responses
-   unquoted etags
-   relative URLs in the Location header
-   unsafe calls to wsgi.input
-   unclosed iterators

Detected errors are emitted using the standard Python :mod:`warnings`
system and usually end up on :data:`stderr`.

::

    from werkzeug.contrib.lint import LintMiddleware
    app = LintMiddleware(app)

:param app: the application to wrap

Definition at line 184 of file lint.py.


Constructor & Destructor Documentation

Definition at line 208 of file lint.py.

00208 
00209     def __init__(self, app):
00210         self.app = app


Member Function Documentation

Definition at line 293 of file lint.py.

00293 
00294     def __call__(self, *args, **kwargs):
00295         if len(args) != 2:
00296             warn(WSGIWarning('Two arguments to WSGI app required'), stacklevel=2)
00297         if kwargs:
00298             warn(WSGIWarning('No keyword arguments to WSGI app allowed'),
00299                  stacklevel=2)
00300         environ, start_response = args
00301 
00302         self.check_environ(environ)
00303         environ['wsgi.input'] = InputStream(environ['wsgi.input'])
00304         environ['wsgi.errors'] = ErrorStream(environ['wsgi.errors'])
00305 
00306         # hook our own file wrapper in so that applications will always
00307         # iterate to the end and we can check the content length
00308         environ['wsgi.file_wrapper'] = FileWrapper
00309 
00310         headers_set = []
00311         chunks = []
00312 
00313         def checking_start_response(*args, **kwargs):
00314             if len(args) not in (2, 3):
00315                 warn(WSGIWarning('Invalid number of arguments: %s, expected '
00316                      '2 or 3' % len(args), stacklevel=2))
00317             if kwargs:
00318                 warn(WSGIWarning('no keyword arguments allowed.'))
00319 
00320             status, headers = args[:2]
00321             if len(args) == 3:
00322                 exc_info = args[2]
00323             else:
00324                 exc_info = None
00325 
00326             headers_set[:] = self.check_start_response(status, headers,
00327                                                        exc_info)
00328             return GuardedWrite(start_response(status, headers, exc_info),
00329                                 chunks)
00330 
00331         app_iter = self.app(environ, checking_start_response)
00332         self.check_iterator(app_iter)
00333         return GuardedIterator(app_iter, headers_set, chunks)

Here is the call graph for this function:

Definition at line 211 of file lint.py.

00211 
00212     def check_environ(self, environ):
00213         if type(environ) is not dict:
00214             warn(WSGIWarning('WSGI environment is not a standard python dict.'),
00215                  stacklevel=4)
00216         for key in ('REQUEST_METHOD', 'SERVER_NAME', 'SERVER_PORT',
00217                     'wsgi.version', 'wsgi.input', 'wsgi.errors',
00218                     'wsgi.multithread', 'wsgi.multiprocess',
00219                     'wsgi.run_once'):
00220             if key not in environ:
00221                 warn(WSGIWarning('required environment key %r not found'
00222                      % key), stacklevel=3)
00223         if environ['wsgi.version'] != (1, 0):
00224             warn(WSGIWarning('environ is not a WSGI 1.0 environ'),
00225                  stacklevel=3)
00226 
00227         script_name = environ.get('SCRIPT_NAME', '')
00228         if script_name and script_name[:1] != '/':
00229             warn(WSGIWarning('SCRIPT_NAME does not start with a slash: %r'
00230                              % script_name), stacklevel=3)
00231         path_info = environ.get('PATH_INFO', '')
00232         if path_info[:1] != '/':
00233             warn(WSGIWarning('PATH_INFO does not start with a slash: %r'
00234                              % path_info), stacklevel=3)
00235 

Here is the caller graph for this function:

Definition at line 272 of file lint.py.

00272 
00273     def check_headers(self, headers):
00274         etag = headers.get('etag')
00275         if etag is not None:
00276             if etag.startswith('w/'):
00277                 etag = etag[2:]
00278             if not (etag[:1] == etag[-1:] == '"'):
00279                 warn(HTTPWarning('unquoted etag emitted.'), stacklevel=4)
00280 
00281         location = headers.get('location')
00282         if location is not None:
00283             if not urlparse(location).netloc:
00284                 warn(HTTPWarning('absolute URLs required for location header'),
00285                      stacklevel=4)

Here is the caller graph for this function:

Definition at line 286 of file lint.py.

00286 
00287     def check_iterator(self, app_iter):
00288         if isinstance(app_iter, basestring):
00289             warn(WSGIWarning('application returned string.  Response will '
00290                              'send character for character to the client '
00291                              'which will kill the performance.  Return a '
00292                              'list or iterable instead.'), stacklevel=3)

Here is the caller graph for this function:

def MoinMoin.support.werkzeug.contrib.lint.LintMiddleware.check_start_response (   self,
  status,
  headers,
  exc_info 
)

Definition at line 236 of file lint.py.

00236 
00237     def check_start_response(self, status, headers, exc_info):
00238         check_string('status', status)
00239         status_code = status.split(None, 1)[0]
00240         if len(status_code) != 3 or not status_code.isdigit():
00241             warn(WSGIWarning('Status code must be three digits'), stacklevel=3)
00242         if len(status) < 4 or status[3] != ' ':
00243             warn(WSGIWarning('Invalid value for status %r.  Valid '
00244                              'status strings are three digits, a space '
00245                              'and a status explanation'), stacklevel=3)
00246         status_code = int(status_code)
00247         if status_code < 100:
00248             warn(WSGIWarning('status code < 100 detected'), stacklevel=3)
00249 
00250         if type(headers) is not list:
00251             warn(WSGIWarning('header list is not a list'), stacklevel=3)
00252         for item in headers:
00253             if type(item) is not tuple or len(item) != 2:
00254                 warn(WSGIWarning('Headers must tuple 2-item tuples'),
00255                      stacklevel=3)
00256             name, value = item
00257             if type(name) is not str or type(value) is not str:
00258                 warn(WSGIWarning('header items must be strings'),
00259                      stacklevel=3)
00260             if name.lower() == 'status':
00261                 warn(WSGIWarning('The status header is not supported due to '
00262                                  'conflicts with the CGI spec.'),
00263                                  stacklevel=3)
00264 
00265         if exc_info is not None and not isinstance(exc_info, tuple):
00266             warn(WSGIWarning('invalid value for exc_info'), stacklevel=3)
00267 
00268         headers = Headers(headers)
00269         self.check_headers(headers)
00270 
00271         return status_code, headers

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 209 of file lint.py.


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