X-Git-Url: https://git.mdrn.pl/django-ssify.git/blobdiff_plain/3d2c8ba4dfb4774daff367dae1656099eb2b562c..HEAD:/ssify/middleware_debug.py?ds=sidebyside diff --git a/ssify/middleware_debug.py b/ssify/middleware_debug.py index 2bd4fa0..f463d53 100644 --- a/ssify/middleware_debug.py +++ b/ssify/middleware_debug.py @@ -1,15 +1,33 @@ +# -*- coding: utf-8 -*- +# This file is part of django-ssify, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Nowoczesna Polska. See README.md for more information. +# """ This module should only be used for debugging SSI statements. -Using DebugUnSsiMiddleware in production defeats the purpose of using SSI +Using SsiRenderMiddleware in production defeats the purpose of using SSI in the first place, and is unsafe. You should use a proper webserver with SSI support as a proxy (i.e. Nginx with ssi=on). """ +from __future__ import unicode_literals import re -import urlparse + +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse + +try: + from django.urls import NoReverseMatch, reverse, resolve +except ImportError: + # Django < 2 + from django.core.urlresolvers import NoReverseMatch, reverse, resolve + from django.core.urlresolvers import resolve -from ssify import DEBUG_VERBOSE +from .cache import get_caches + +from .conf import conf SSI_SET = re.compile(r"") SSI_IF = re.compile(r"(?P
)" r"(?P.*?)(?:(?P.*?))?" r"", re.S) - # TODO: escaped? -SSI_VAR = re.compile(r"\$\{(?P.+)\}") # TODO: escaped? +SSI_VAR = re.compile(r"\$\{(?P.+)\}") + +UNESCAPE = re.compile(r'\\(.)') -class DebugUnSsiMiddleware(object): +class SsiRenderMiddleware(object): """ Emulates a webserver with SSI support. This middleware should only be used for debugging purposes. - SsiMiddleware will enable it automatically, if SSIFY_DEBUG setting + SsiMiddleware will enable it automatically, if SSIFY_RENDER setting is set to True, so you don't normally need to include it in MIDDLEWARE_CLASSES. - If SSIFY_DEBUG_VERBOSE setting is True, it will also leave some + If SSIFY_RENDER_VERBOSE setting is True, it will also leave some information in HTML comments. """ @@ -42,14 +61,29 @@ class DebugUnSsiMiddleware(object): def ssi_include(match): """Replaces SSI include with contents rendered by relevant view.""" path = process_value(match.group('path')) - func, args, kwargs = resolve(path) - parsed = urlparse.urlparse(path) - request.META['PATH_INFO'] = request.path_info = \ - request.path = parsed.path - request.META['QUERY_STRING'] = parsed.query - content = func(request, *args, **kwargs).content - content = process_content(content) - if DEBUG_VERBOSE: + content = None + for cache in get_caches(): + content = cache.get(path) + if content is not None: + break + if content is None: + func, args, kwargs = resolve(path) + parsed = urlparse(path) + + # Reuse the original request, but reset some attributes. + request.META['PATH_INFO'] = request.path_info = \ + request.path = parsed.path + request.META['QUERY_STRING'] = parsed.query + request.ssi_vars_needed = {} + + subresponse = func(request, *args, **kwargs) + # FIXME: we should deal directly with bytes here. + if subresponse.streaming: + content = b"".join(subresponse.streaming_content) + else: + content = subresponse.content + content = process_content(content.decode('utf-8')) + if conf.RENDER_VERBOSE: return "".join(( match.group(0), content, @@ -60,16 +94,18 @@ class DebugUnSsiMiddleware(object): def ssi_set(match): """Interprets SSI set statement.""" - variables[match.group('var')] = match.group('value') - if DEBUG_VERBOSE: - return match.group(0) + content = match.group('value') + content = re.sub(UNESCAPE, r'\1', content) + variables[match.group('var')] = content + if conf.RENDER_VERBOSE: + return content else: return "" def ssi_echo(match): """Interprets SSI echo, outputting the value of the variable.""" content = variables[match.group('var')] - if DEBUG_VERBOSE: + if conf.RENDER_VERBOSE: return "".join(( match.group(0), content, @@ -84,8 +120,8 @@ class DebugUnSsiMiddleware(object): if expr: content = match.group('value') else: - content = match.group('else') - if DEBUG_VERBOSE: + content = match.group('else') or '' + if conf.RENDER_VERBOSE: return "".join(( match.group('header'), content, @@ -111,11 +147,14 @@ class DebugUnSsiMiddleware(object): return content variables = {} - response.content = process_content(response.content) + response.content = process_content( + response.content.decode('utf-8')).encode('utf-8') response['Content-Length'] = len(response.content) def process_response(self, request, response): """Support for unrendered responses.""" + if response.streaming: + return response if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self._process_rendered_response(request, r)