pylons.middleware
Covered: 156 lines
Missed: 0 lines
Skipped 40 lines
Percent: 100 %

      1

    """Pylons' WSGI middlewares"""

      2

    import logging

      3

    import os.path

      4

      5

    from paste.deploy.converters import asbool

      6

    from paste.urlparser import StaticURLParser

      7

    from weberror.evalexception import EvalException

      8

    from weberror.errormiddleware import ErrorMiddleware

      9

    from webob import Request, Response

     10

    from webhelpers.html import literal

     11

     12

    import pylons

     13

    from pylons.error import template_error_formatters

     14

    from pylons.util import call_wsgi_application

     15

     16

    __all__ = ['ErrorHandler', 'StaticJavascripts', 'error_document_template',

     17

               'footer_html', 'head_html', 'media_path']

     18

     19

    log = logging.getLogger(__name__)

     20

     21

    media_path = os.path.join(os.path.dirname(__file__), 'media')

     22

     23

    head_html = """\

     24

    <link rel="stylesheet" href="{{prefix}}/media/pylons/style/itraceback.css" \

     25

    type="text/css" media="screen" />"""

     26

     27

    footer_html = """\

     28

    <script src="{{prefix}}/media/pylons/javascripts/traceback.js"></script>

     29

    <script>

     30

    var TRACEBACK = {

     31

        uri: "{{prefix}}",

     32

        host: "%s",

     33

        traceback: "/tracebacks"

     34

    }

     35

    </script>

     36

    <div id="service_widget">

     37

    <h2 class="assistance">Online Assistance</h2>

     38

    <div id="nv">

     39

    <ul id="supportnav">

     40

        <li class="nav active"><a class="overview" href="#">Overview</a></li>

     41

        <li class="nav"><a class="search" href="#">Search Mail Lists</a></li>

     42

        <li class="nav"><a class="posttraceback" href="#">Post Traceback</a></li>

     43

    </ul>

     44

    </div>

     45

    <div class="clearfix">&nbsp;</div>

     46

    <div class="overviewtab">

     47

    <b>Looking for help?</b>

     48

     49

    <p>Here are a few tips for troubleshooting if the above traceback isn't

     50

    helping out.</p>

     51

     52

    <ol>

     53

    <li>Search the mail list</li>

     54

    <li>Post the traceback, and ask for help on IRC</li>

     55

    <li>Post a message to the mail list, referring to the posted traceback</li>

     56

     57

    </div>

     58

    <div class="posttracebacktab">

     59

    <p><b>Note:</b> Clicking this button will post your traceback to the PylonsHQ website.

     60

    The traceback includes the module names, Python version, and lines of code that you

     61

    can see above. All tracebacks are posted anonymously unless you're logged into the

     62

    PylonsHQ website in this browser.</p>

     63

    <input type="button" href="#" class="submit_traceback" value="Send TraceBack to PylonsHQ" style="text-align: center;"/>

     64

    </div>

     65

     66

    <div class="searchtab">

     67

    <p>The following mail lists will be searched:<br />

     68

    <input type="checkbox" name="lists" value="pylons" checked="checked" /> Pylons<br />

     69

    <input type="checkbox" name="lists" value="python" /> Python<br />

     70

    <input type="checkbox" name="lists" value="mako" /> Mako<br />

     71

    <input type="checkbox" name="lists" value="sqlalchemy" /> SQLAlchemy</p>

     72

    <p class="query">for: <input type="text" name="query" class="query" /></p>

     73

     74

    <p><input type="submit" value="Search" /></p>

     75

    <div class="searchresults">

     76

     77

    </div>

     78

    </div>

     79

     80

    </div>

     81

    <div id="pylons_logo">\

     82

    <img src="{{prefix}}/media/pylons/img/pylons-powered-02.png" /></div>

     83

    <div class="credits">Pylons version %s</div>"""

     84

     85

    report_libs = ['pylons', 'genshi', 'sqlalchemy']

     86

     87

    def ErrorHandler(app, global_conf, **errorware):

     88

        """ErrorHandler Toggle

     89

     90

        If debug is enabled, this function will return the app wrapped in

     91

        the WebError ``EvalException`` middleware which displays

     92

        interactive debugging sessions when a traceback occurs.

     93

     94

        Otherwise, the app will be wrapped in the WebError

     95

        ``ErrorMiddleware``, and the ``errorware`` dict will be passed into

     96

        it. The ``ErrorMiddleware`` handles sending an email to the address

     97

        listed in the .ini file, under ``email_to``.

     98

     99

        """

    100

        if asbool(global_conf.get('debug')):

    101

            footer = footer_html % (pylons.config.get('traceback_host',

    102

                                                      'pylonshq.com'),

    103

                                    pylons.__version__)

    104

            py_media = dict(pylons=media_path)

    105

            app = EvalException(app, global_conf,

    106

                                templating_formatters=template_error_formatters,

    107

                                media_paths=py_media, head_html=head_html,

    108

                                footer_html=footer,

    109

                                libraries=report_libs)

    110

        else:

    111

            app = ErrorMiddleware(app, global_conf, **errorware)

    112

        return app

    113

    114

    115

    class StatusCodeRedirect(object):

    116

        """Internally redirects a request based on status code

    117

    118

        StatusCodeRedirect watches the response of the app it wraps. If the

    119

        response is an error code in the errors sequence passed the request

    120

        will be re-run with the path URL set to the path passed in.

    121

    122

        This operation is non-recursive and the output of the second

    123

        request will be used no matter what it is.

    124

    125

        Should an application wish to bypass the error response (ie, to

    126

        purposely return a 401), set

    127

        ``environ['pylons.status_code_redirect'] = True`` in the application.

    128

    129

        """

    130

        def __init__(self, app, errors=(400, 401, 403, 404),

    131

                     path='/error/document'):

    132

            """Initialize the ErrorRedirect

    133

    134

            ``errors``

    135

                A sequence (list, tuple) of error code integers that should

    136

                be caught.

    137

            ``path``

    138

                The path to set for the next request down to the

    139

                application.

    140

    141

            """

    142

            self.app = app

    143

            self.error_path = path

    144

    145

            # Transform errors to str for comparison

    146

            self.errors = tuple([str(x) for x in errors])

    147

    148

        def __call__(self, environ, start_response):

    149

            status, headers, app_iter, exc_info = call_wsgi_application(

    150

                self.app, environ, catch_exc_info=True)

    151

            if status[:3] in self.errors and \

    152

                'pylons.status_code_redirect' not in environ and self.error_path:

    153

                # Create a response object

    154

                environ['pylons.original_response'] = Response(

    155

                    status=status, headerlist=headers, app_iter=app_iter)

    156

                environ['pylons.original_request'] = Request(environ)

    157

    158

                # Create a new environ to avoid touching the original request data

    159

                new_environ = environ.copy()

    160

                new_environ['PATH_INFO'] = self.error_path

    161

    162

                newstatus, headers, app_iter, exc_info = call_wsgi_application(

    163

                        self.app, new_environ, catch_exc_info=True)

    164

            start_response(status, headers, exc_info)

    165

            return app_iter

    166

    167

    168

    error_document_template = literal("""\

    169

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

    170

    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

    171

    <head>

    172

     <title>Server Error %(code)s</title>

    173

    <!-- CSS Imports -->

    174

    <link rel="stylesheet" href="%(prefix)s/error/style/black.css" type="text/css" media="screen" />

    175

    176

    <!-- Favorite Icons -->

    177

    <link rel="icon" href="%(prefix)s/error/img/favicon.ico" type="image/png" />

    178

    179

    <style type="text/css">

    180

            .red {

    181

                color:#FF0000;

    182

            }

    183

            .bold {

    184

                font-weight: bold;

    185

            }

    186

    </style>

    187

    </head>

    188

    189

    <body>

    190

        <div id="container">

    191

            %(message)s

    192

        </div>

    193

    </body>

    194

    </html>

    195

    """)

    196