-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
middleware.py
110 lines (90 loc) · 3.84 KB
/
middleware.py
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
"""
Debug Toolbar middleware
"""
import re
from functools import lru_cache
from django.conf import settings
from django.utils.module_loading import import_string
from debug_toolbar import settings as dt_settings
from debug_toolbar.toolbar import DebugToolbar
from debug_toolbar.utils import clear_stack_trace_caches
_HTML_TYPES = ("text/html", "application/xhtml+xml")
def show_toolbar(request):
"""
Default function to determine whether to show the toolbar on a given page.
"""
return settings.DEBUG and request.META.get("REMOTE_ADDR") in settings.INTERNAL_IPS
@lru_cache(maxsize=None)
def get_show_toolbar():
# If SHOW_TOOLBAR_CALLBACK is a string, which is the recommended
# setup, resolve it to the corresponding callable.
func_or_path = dt_settings.get_config()["SHOW_TOOLBAR_CALLBACK"]
if isinstance(func_or_path, str):
return import_string(func_or_path)
else:
return func_or_path
class DebugToolbarMiddleware:
"""
Middleware to set up Debug Toolbar on incoming request and render toolbar
on outgoing response.
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Decide whether the toolbar is active for this request.
show_toolbar = get_show_toolbar()
if not show_toolbar(request) or DebugToolbar.is_toolbar_request(request):
return self.get_response(request)
toolbar = DebugToolbar(request, self.get_response)
# Activate instrumentation ie. monkey-patch.
for panel in toolbar.enabled_panels:
panel.enable_instrumentation()
try:
# Run panels like Django middleware.
response = toolbar.process_request(request)
finally:
clear_stack_trace_caches()
# Deactivate instrumentation ie. monkey-unpatch. This must run
# regardless of the response. Keep 'return' clauses below.
for panel in reversed(toolbar.enabled_panels):
panel.disable_instrumentation()
# Generate the stats for all requests when the toolbar is being shown,
# but not necessarily inserted.
for panel in reversed(toolbar.enabled_panels):
panel.generate_stats(request, response)
panel.generate_server_timing(request, response)
# Always render the toolbar for the history panel, even if it is not
# included in the response.
rendered = toolbar.render_toolbar()
for header, value in self.get_headers(request, toolbar.enabled_panels).items():
response.headers[header] = value
# Check for responses where the toolbar can't be inserted.
content_encoding = response.get("Content-Encoding", "")
content_type = response.get("Content-Type", "").split(";")[0]
if (
getattr(response, "streaming", False)
or content_encoding != ""
or content_type not in _HTML_TYPES
):
return response
# Insert the toolbar in the response.
content = response.content.decode(response.charset)
insert_before = dt_settings.get_config()["INSERT_BEFORE"]
pattern = re.escape(insert_before)
bits = re.split(pattern, content, flags=re.IGNORECASE)
if len(bits) > 1:
bits[-2] += rendered
response.content = insert_before.join(bits)
if "Content-Length" in response:
response["Content-Length"] = len(response.content)
return response
@staticmethod
def get_headers(request, panels):
headers = {}
for panel in panels:
for header, value in panel.get_headers(request).items():
if header in headers:
headers[header] += f", {value}"
else:
headers[header] = value
return headers