zoom.middleware module¶
zoom.middleware
A set of functions that can be placed between the HTTP server and the application layer. These functions can provide various services such as content serving, caching, error trapping, security, etc..
-
zoom.middleware.capture_stdout(request, handler, *rest)¶ Capture printed output for debugging purposes
>>> request = zoom.request.build('http://localhost') >>> def get_content(request): ... print('hey') ... return zoom.response.HTMLResponse('I said {*stdout*}') >>> response = capture_stdout(request, get_content) >>> response.content 'I said hey\n'
-
zoom.middleware.check_csrf(request, handler, *rest)¶ Check csrf token
>>> zoom.system.providers = [] >>> data = dict(csrf_token='1234', name='Pat') >>> request = zoom.request.build('http://localhost/', data) >>> request.session = zoom.utils.Bunch() >>> request.site = zoom.sites.Site() >>> result = check_csrf(request, lambda a: False) >>> isinstance(result, zoom.response.RedirectResponse) True
>>> data = dict(csrf_token='1234', name='Pat') >>> request = zoom.request.build('http://localhost/', data) >>> request.session = zoom.utils.Bunch(csrf_token='4321') >>> request.site = zoom.sites.Site() >>> result = check_csrf(request, lambda a: False) >>> isinstance(result, zoom.response.RedirectResponse) True
>>> data = dict(csrf_token='1234', name='Pat') >>> request = zoom.request.build('http://localhost/', data) >>> request.session = zoom.utils.Bunch(csrf_token='1234') >>> request.site = zoom.sites.Site() >>> result = check_csrf(request, lambda a: False) >>> isinstance(result, zoom.response.RedirectResponse) False
-
zoom.middleware.debug(request)¶ Debugging page
>>> type(debug(zoom.request.build('http://localhost/'))) <class 'zoom.response.HTMLResponse'>
-
zoom.middleware.display_errors(request, handler, *rest)¶ Display errors for developers
>>> request = zoom.request.build('http://localhost') >>> request.app = zoom.utils.Bunch(theme='default', templates_paths=[]) >>> request.host = 'localhost' >>> request.site = zoom.sites.Site() >>> request.site.theme = 'default' >>> request.site.request = request >>> zoom.system.request = request >>> zoom.system.site = request.site >>> zoom.system.user = request.site.users.first(username='admin') >>> zoom.system.user.is_admin = True >>> def throw(request): ... raise Exception('ouch!') >>> response = display_errors(request, throw) >>> isinstance(response, HTMLResponse) True >>> zoom.system.user.is_admin = False >>> response = display_errors(request, throw) >>> isinstance(response, HTMLResponse) True
-
zoom.middleware.get_csrf_token(session)¶ generate a csrf token
>>> zoom.system.request.session = session = zoom.utils.Bunch() >>> hasattr(session, 'csrf_token') False >>> bool(get_csrf_token(session)) True >>> hasattr(session, 'csrf_token') False >>> _ = zoom.forms.form_for('test') >>> hasattr(session, 'csrf_token') True
-
zoom.middleware.handle(request, handlers=None)¶ handle a request
-
zoom.middleware.not_found(request)¶ return a 404 page for site
>>> zoom.system.site = site = zoom.sites.Site() >>> site.theme = 'default' >>> site.title = 'My Site' >>> request = zoom.request.build('http://localhost') >>> request.app = zoom.utils.Bunch(theme='default') >>> request.site = site >>> response = not_found(request) >>> response.status '404 Not Found'
-
zoom.middleware.reset_modules(request, handler, *rest)¶ reset the modules to a known starting set
Memorizes the modules in use on the first round. Then on every subsequent round, it removes any extra modules before passing the request on.
>>> def loader(request): ... import zoom.audit
>>> def not_a_loader(request): ... pass
>>> if 'zoom.audit' in sys.modules: ... del sys.modules['zoom.audit'] >>> fresh = list(sys.modules) >>> reset_modules(zoom.request.build('http://localhost'), loader) >>> fresh == list(sys.modules) False
>>> reset_modules(zoom.request.build('http://localhost'), not_a_loader) >>> fresh == list(sys.modules) True
-
zoom.middleware.serve_favicon(request, handler, *rest)¶ Serve a favicon file
This function only handles the case where the favicon reference is /favicon.ico, as would be typical in a local dev environment. For production environments the favicon would typically be either part of the theme or would be stored statically, both of which would typically be served up by your proxy or your web server depending on your config.
If your web sever is not configured to handle static or themes for you, Zoom will happily serve them up via the serve_theme or serve_static middleware found elsewhere in this module.
>>> from zoom.request import Request >>> def content_handler(request, *rest): ... return '200 OK', [], 'nuthin'
>>> request = Request( ... dict(REQUEST_URI='/favicon.ico'), ... ) >>> response = serve_favicon( ... request, ... content_handler, ... ) >>> isinstance(response, ICOResponse) True
>>> request = Request( ... dict(REQUEST_URI='/'), ... ) >>> status, _, content = serve_favicon( ... request, ... content_handler, ... ) >>> content 'nuthin'
-
zoom.middleware.serve_html(request, handler, *rest)¶ Serve HTML from the Content app
Direct a request for an HTML page to the content app
>>> site = zoom.sites.Site() >>> url = 'http://localhost/index.html' >>> request = zoom.request.build(url) >>> request.path == '/index.html' True >>> response = serve_html(request, lambda a: None) >>> request.path == '/content/index.html' True
>>> url = 'http://localhost/index.css' >>> request = zoom.request.build(url) >>> request.path == '/index.css' True >>> response = serve_html(request, lambda a: None) >>> request.path == '/index.css' True
-
zoom.middleware.serve_images(request, handler, *rest)¶ Serve an image file
>>> url = 'http://localhost/images/banner_logo.png' >>> request = zoom.request.build(url) >>> request.site = zoom.sites.Site() >>> result = serve_images(request, lambda a: False) >>> isinstance(result, PNGResponse) True
>>> url = 'http://localhost/notimages/banner_logo.png' >>> request = zoom.request.build(url) >>> serve_images(request, lambda a: False) False
-
zoom.middleware.serve_redirects(request, handler, *rest)¶ Serves redirects
>>> request = zoom.request.build('http://localhost') >>> result = serve_redirects(request, lambda a: False) >>> print(result) False
>>> request.site = zoom.utils.Bunch(abs_url='http://localhost') >>> redirect_home = zoom.response.RedirectResponse('/home') >>> result = serve_redirects(request, lambda a: redirect_home) >>> print(result.headers) OrderedDict([('Location', '/home')])
-
zoom.middleware.serve_response(*path)¶ Serve up various respones with their correct response type
>>> zoom_js = zoom.tools.zoompath('web/www/static/zoom/zoom.js') >>> response = serve_response(zoom_js) >>> isinstance(response, JavascriptResponse) True
>>> zoom_path = zoom.tools.zoompath('web') >>> response = serve_response(zoom_path, 'www/static/zoom/nada.js') >>> isinstance(response, JavascriptResponse) False
>>> response.content "file not found: 'www/static/zoom/nada.js'" >>> response.status '404 Not Found'
>>> zoom_path = zoom.tools.zoompath('web') >>> response = serve_response(zoom_path, 'www/static/zoom/images') >>> isinstance(response, JavascriptResponse) False
>>> response.content "unknown file type ''" >>> response.status '415 Unsupported Media Type'
-
zoom.middleware.serve_static(request, handler, *rest)¶ Serve a static file
Static files can be served in serveral ways. This particular middleware intended to be inserted into the middleware stack near the front before most other things. The reason being is that in many cases the static files are not site specific or app specific but rather are shared by the entire instance. In addition, many times static files require no authorization or special rights. This means that in many cases static files can be served without knowing who is asking or what site they are for. That is what this middleware does.
This handler is mainly intended for development purposes as in a production evironment this type of content would typically be served up by the HTTP server or a caching layer.
Note: This layer looks in four separate places for static files to serve. Three related to the zoom instance, and one, as a last resort, from the zoom library itself. If you are concerned about exposing the wrong files, be careful what you put in those directories or better yet, use a proxy.
In addition to this instance wide static serving Sites and Apps may implement static file serving. If they do, this layer is unaware of that fact.
The locations this handler will look are relative to the zoom instance. They are:
<instance>/static <instance>/www/static <instance>/../static zoom/web/www/static>>> url = 'http://localhost/static/zoom/zoom.js' >>> request = zoom.request.build(url) >>> result = serve_static(request, lambda a: False) >>> isinstance(result, JavascriptResponse) True
>>> url = 'http://localhost/notstatic/zoom/zoom.js' >>> request = zoom.request.build(url) >>> result = serve_static(request, lambda a: False) >>> isinstance(result, JavascriptResponse) False
-
zoom.middleware.serve_themes(request, handler, *rest)¶ Serve a theme file
>>> url = 'http://localhost/themes/default/css/style.css' >>> request = zoom.request.build(url) >>> request.site = zoom.sites.Site() >>> result = serve_themes(request, lambda a: False) >>> isinstance(result, CSSResponse) True
>>> url = 'http://localhost/notthemes/default/default.html' >>> request = zoom.request.build(url) >>> serve_themes(request, lambda a: False) False
-
zoom.middleware.trap_errors(request, handler, *rest)¶ Trap exceptions and raise a server error
>>> def exception_handler(request, *rest): ... raise Exception('error!') >>> def content_handler(request, *rest): ... return HTMLResponse('nuthin') >>> request = {} >>> response = trap_errors(request, content_handler) >>> status, headers, content = response.as_wsgi() >>> content b'nuthin' >>> status '200 OK' >>> response = trap_errors(request, exception_handler) >>> status, headers, content = response.as_wsgi() >>> status '500 Internal Server Error' >>> 'Exception: error!' in str(content) True