Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Initial commit

  • Loading branch information...
commit fd406bfecd5b715d77566e741075c1396312b395 0 parents
Simon Willison authored

Showing 1 changed file with 181 additions and 0 deletions. Show diff stats Hide diff stats

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

0 comments on commit fd406bf

Please sign in to comment.
Something went wrong with that request. Please try again.