public
Description: Turtles all the way down
Homepage: http://simonwillison.net/2009/May/19/djng/
Clone URL: git://github.com/simonw/djng.git
djng / djng_old.py
100644 153 lines (130 sloc) 5.701 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
"""
Just some sketched out ideas at the moment, this code has never been executed.
"""
 
from django import http
from django.core import signals
from django.utils.encoding import force_unicode
from django.utils.importlib import import_module
 
from django.core.handlers.wsgi import STATUS_CODE_TEXT, WSGIRequest
 
import sys
 
class Handler(object):
    # Changes that are always applied to a response (in this order).
    response_fixes = [
        http.fix_location_header,
        http.conditional_content_removal,
        http.fix_IE_for_attach,
        http.fix_IE_for_vary,
    ]
    request_middleware = []
    response_middleware = []
    exception_middleware = []
    
    debug = False
    propagate_exceptions = False
    
    def __init__(self, router):
        self.router = router
    
    def __call__(self, environ, start_response):
        try:
            request = WSGIRequest(environ)
        except UnicodeDecodeError:
            response = http.HttpResponseBadRequest()
        else:
            response = self.get_response(request)
 
            # Apply response middleware
            for middleware_method in self.response_middleware:
                response = middleware_method(request, response)
            response = self.apply_response_fixes(request, response)
 
        try:
            status_text = STATUS_CODE_TEXT[response.status_code]
        except KeyError:
            status_text = 'UNKNOWN STATUS CODE'
        status = '%s %s' % (response.status_code, status_text)
        response_headers = [(str(k), str(v)) for k, v in response.items()]
        for c in response.cookies.values():
            response_headers.append(('Set-Cookie', str(c.output(header=''))))
        start_response(status, response_headers)
        return response
    
    def get_response(self, request):
        "Returns an HttpResponse object for the given HttpRequest"
        from django.core import exceptions, urlresolvers
 
        # Apply request middleware
        for middleware_method in self.request_middleware:
            response = middleware_method(request)
            if response:
                return response
        
        # Resolve and execute the view, catching any errors
        try:
            response = self.router(request)
        except Exception, e:
            # If the view raised an exception, run it through exception
            # middleware, and if the exception middleware returns a
            # response, use that. Otherwise, reraise the exception.
            for middleware_method in self.exception_middleware:
                response = middleware_method(request, e)
                if response:
                    return response
            raise
        except http.Http404, e:
            return self.handle_404(request, e)
        except exceptions.PermissionDenied:
            return self.handle_permission_denied(request)
        except SystemExit:
            # Allow sys.exit() to actually exit. See tickets #1023 and #4701
            raise
        except: # Handle everything else, including SuspiciousOperation, etc.
            # Get exc_info now, in case another exception is thrown later
            exc_info = sys.exc_info()
            receivers = signals.got_request_exception.send(
                sender=self.__class__, request=request
            )
            return self.handle_uncaught_exception(request, exc_info)
 
    def handle_404(self, request, e):
        if self.debug:
            from django.views import debug
            return debug.technical_404_response(request, e)
        else:
            return http.HttpResponseNotFound('<h1>404</h1>')
    
    def handle_permission_denied(self, request):
        return http.HttpResponseForbidden('<h1>Permission denied</h1>')
 
    def handle_uncaught_exception(self, request, exc_info):
        """
Processing for any otherwise uncaught exceptions (those that will
generate HTTP 500 responses). Can be overridden by subclasses who want
customised 500 handling.
 
Be *very* careful when overriding this because the error could be
caused by anything, so assuming something like the database is always
available would be an error.
"""
        from django.core.mail import mail_admins
 
        if self.propagate_exceptions:
            raise
 
        if self.debug:
            from django.views import debug
            return debug.technical_500_response(request, *exc_info)
 
        # When DEBUG is False, send an error message to the admins.
        subject = 'Error: %s' % request.path
        try:
            request_repr = repr(request)
        except:
            request_repr = "Request repr() unavailable"
        message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr)
        mail_admins(subject, message, fail_silently=True)
        # Return an HttpResponse that displays a friendly error message.
        return self.handle_500(request, exc_info)
 
    def _get_traceback(self, exc_info=None):
        "Helper function to return the traceback as a string"
        import traceback
        return '\n'.join(
            traceback.format_exception(*(exc_info or sys.exc_info()))
        )
 
    def apply_response_fixes(self, request, response):
        """
Applies each of the functions in self.response_fixes to the request
and response, modifying the response in the process. Returns the new
response.
"""
        for func in self.response_fixes:
            response = func(request, response)
        return response
 
def serve(handler, host='localhost', port=6789):
    from django.core.servers.basehttp import run
    run(host, int(port), handler)