|
|
@@ -491,112 +491,6 @@ class AuditLoggingMiddleware(MiddlewareMixin):
|
|
|
return allowed
|
|
|
|
|
|
|
|
|
-try:
|
|
|
- import tidylib
|
|
|
- _has_tidylib = True
|
|
|
-except Exception as ex:
|
|
|
- # The exception type is not ImportError. It's actually an OSError.
|
|
|
- logging.warn("Failed to import tidylib (for debugging). Is libtidy installed?")
|
|
|
- _has_tidylib = False
|
|
|
-
|
|
|
-
|
|
|
-class HtmlValidationMiddleware(MiddlewareMixin):
|
|
|
- """
|
|
|
- If configured, validate output html for every response.
|
|
|
- """
|
|
|
- def __init__(self, get_response):
|
|
|
- self.get_response = get_response
|
|
|
- self._logger = logging.getLogger('HtmlValidationMiddleware')
|
|
|
-
|
|
|
- if not _has_tidylib:
|
|
|
- logging.error("HtmlValidationMiddleware not activatived: Failed to import tidylib.")
|
|
|
- return
|
|
|
-
|
|
|
- # Things that we don't care about
|
|
|
- self._to_ignore = (
|
|
|
- re.compile('- Warning: <.*> proprietary attribute "data-'),
|
|
|
- re.compile('- Warning: trimming empty'),
|
|
|
- re.compile('- Info:'),
|
|
|
- )
|
|
|
-
|
|
|
- # Find the directory to write tidy html output
|
|
|
- try:
|
|
|
- self._outdir = os.path.join(tempfile.gettempdir(), 'hue_html_validation')
|
|
|
- if not os.path.isdir(self._outdir):
|
|
|
- os.mkdir(self._outdir, 0o755)
|
|
|
- except Exception as ex:
|
|
|
- self._logger.exception('Failed to get temp directory: %s', (ex,))
|
|
|
- self._outdir = tempfile.mkdtemp(prefix='hue_html_validation-')
|
|
|
-
|
|
|
- # Options to pass to libtidy. See
|
|
|
- # http://tidy.sourceforge.net/docs/quickref.html
|
|
|
- self._options = {
|
|
|
- 'show-warnings': 1,
|
|
|
- 'output-html': 0,
|
|
|
- 'output-xhtml': 1,
|
|
|
- 'char-encoding': 'utf8',
|
|
|
- 'output-encoding': 'utf8',
|
|
|
- 'indent': 1,
|
|
|
- 'wrap': 0,
|
|
|
- }
|
|
|
-
|
|
|
- def process_response(self, request, response):
|
|
|
-
|
|
|
- if not _has_tidylib or not self._is_html(request, response):
|
|
|
- return response
|
|
|
-
|
|
|
- html, errors = tidylib.tidy_document(response.content,
|
|
|
- self._options,
|
|
|
- keep_doc=True)
|
|
|
- if not errors:
|
|
|
- return response
|
|
|
-
|
|
|
- # Filter out what we care about
|
|
|
- err_list = errors.rstrip().split('\n')
|
|
|
- err_list = self._filter_warnings(err_list)
|
|
|
- if not err_list:
|
|
|
- return response
|
|
|
-
|
|
|
- try:
|
|
|
- fn = resolve(request.path)[0]
|
|
|
- fn_name = '%s.%s' % (fn.__module__, fn.__name__)
|
|
|
- except Exception:
|
|
|
- LOG.exception('failed to resolve url')
|
|
|
- fn_name = '<unresolved_url>'
|
|
|
-
|
|
|
- # Write the two versions of html out for offline debugging
|
|
|
- filename = os.path.join(self._outdir, fn_name)
|
|
|
-
|
|
|
- result = "HTML tidy result: %s [%s]:" \
|
|
|
- "\n\t%s" \
|
|
|
- "\nPlease see %s.orig %s.tidy\n-------" % \
|
|
|
- (request.path, fn_name, '\n\t'.join(err_list), filename, filename)
|
|
|
-
|
|
|
- file(filename + '.orig', 'w').write(i18n.smart_str(response.content))
|
|
|
- file(filename + '.tidy', 'w').write(i18n.smart_str(html))
|
|
|
- file(filename + '.info', 'w').write(i18n.smart_str(result))
|
|
|
-
|
|
|
- self._logger.error(result)
|
|
|
-
|
|
|
- return response
|
|
|
-
|
|
|
- def _filter_warnings(self, err_list):
|
|
|
- """A hacky way to filter out things that we don't care about."""
|
|
|
- res = []
|
|
|
- for err in err_list:
|
|
|
- for ignore in self._to_ignore:
|
|
|
- if ignore.search(err):
|
|
|
- break
|
|
|
- else:
|
|
|
- res.append(err)
|
|
|
- return res
|
|
|
-
|
|
|
- def _is_html(self, request, response):
|
|
|
- return not is_ajax(request) and \
|
|
|
- 'html' in response['Content-Type'] and \
|
|
|
- 200 <= response.status_code < 300
|
|
|
-
|
|
|
-
|
|
|
class ProxyMiddleware(MiddlewareMixin):
|
|
|
|
|
|
def __init__(self, get_response):
|