Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/core/handlers/exception.py: 25%

76 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1import asyncio 

2import logging 

3import sys 

4from functools import wraps 

5 

6from asgiref.sync import sync_to_async 

7 

8from django.conf import settings 

9from django.core import signals 

10from django.core.exceptions import ( 

11 BadRequest, 

12 PermissionDenied, 

13 RequestDataTooBig, 

14 SuspiciousOperation, 

15 TooManyFieldsSent, 

16) 

17from django.http import Http404 

18from django.http.multipartparser import MultiPartParserError 

19from django.urls import get_resolver, get_urlconf 

20from django.utils.log import log_response 

21from django.views import debug 

22 

23 

24def convert_exception_to_response(get_response): 

25 """ 

26 Wrap the given get_response callable in exception-to-response conversion. 

27 

28 All exceptions will be converted. All known 4xx exceptions (Http404, 

29 PermissionDenied, MultiPartParserError, SuspiciousOperation) will be 

30 converted to the appropriate response, and all other exceptions will be 

31 converted to 500 responses. 

32 

33 This decorator is automatically applied to all middleware to ensure that 

34 no middleware leaks an exception and that the next middleware in the stack 

35 can rely on getting a response instead of an exception. 

36 """ 

37 if asyncio.iscoroutinefunction(get_response): 37 ↛ 39line 37 didn't jump to line 39, because the condition on line 37 was never true

38 

39 @wraps(get_response) 

40 async def inner(request): 

41 try: 

42 response = await get_response(request) 

43 except Exception as exc: 

44 response = await sync_to_async( 

45 response_for_exception, thread_sensitive=False 

46 )(request, exc) 

47 return response 

48 

49 return inner 

50 else: 

51 

52 @wraps(get_response) 

53 def inner(request): 

54 try: 

55 response = get_response(request) 

56 except Exception as exc: 

57 response = response_for_exception(request, exc) 

58 return response 

59 

60 return inner 

61 

62 

63def response_for_exception(request, exc): 

64 if isinstance(exc, Http404): 

65 if settings.DEBUG: 

66 response = debug.technical_404_response(request, exc) 

67 else: 

68 response = get_exception_response( 

69 request, get_resolver(get_urlconf()), 404, exc 

70 ) 

71 

72 elif isinstance(exc, PermissionDenied): 

73 response = get_exception_response( 

74 request, get_resolver(get_urlconf()), 403, exc 

75 ) 

76 log_response( 

77 "Forbidden (Permission denied): %s", 

78 request.path, 

79 response=response, 

80 request=request, 

81 exc_info=sys.exc_info(), 

82 ) 

83 

84 elif isinstance(exc, MultiPartParserError): 

85 response = get_exception_response( 

86 request, get_resolver(get_urlconf()), 400, exc 

87 ) 

88 log_response( 

89 "Bad request (Unable to parse request body): %s", 

90 request.path, 

91 response=response, 

92 request=request, 

93 exc_info=sys.exc_info(), 

94 ) 

95 

96 elif isinstance(exc, BadRequest): 

97 if settings.DEBUG: 

98 response = debug.technical_500_response( 

99 request, *sys.exc_info(), status_code=400 

100 ) 

101 else: 

102 response = get_exception_response( 

103 request, get_resolver(get_urlconf()), 400, exc 

104 ) 

105 log_response( 

106 "%s: %s", 

107 str(exc), 

108 request.path, 

109 response=response, 

110 request=request, 

111 exc_info=sys.exc_info(), 

112 ) 

113 elif isinstance(exc, SuspiciousOperation): 

114 if isinstance(exc, (RequestDataTooBig, TooManyFieldsSent)): 

115 # POST data can't be accessed again, otherwise the original 

116 # exception would be raised. 

117 request._mark_post_parse_error() 

118 

119 # The request logger receives events for any problematic request 

120 # The security logger receives events for all SuspiciousOperations 

121 security_logger = logging.getLogger( 

122 "django.security.%s" % exc.__class__.__name__ 

123 ) 

124 security_logger.error( 

125 str(exc), 

126 extra={"status_code": 400, "request": request}, 

127 ) 

128 if settings.DEBUG: 

129 response = debug.technical_500_response( 

130 request, *sys.exc_info(), status_code=400 

131 ) 

132 else: 

133 response = get_exception_response( 

134 request, get_resolver(get_urlconf()), 400, exc 

135 ) 

136 

137 else: 

138 signals.got_request_exception.send(sender=None, request=request) 

139 response = handle_uncaught_exception( 

140 request, get_resolver(get_urlconf()), sys.exc_info() 

141 ) 

142 log_response( 

143 "%s: %s", 

144 response.reason_phrase, 

145 request.path, 

146 response=response, 

147 request=request, 

148 exc_info=sys.exc_info(), 

149 ) 

150 

151 # Force a TemplateResponse to be rendered. 

152 if not getattr(response, "is_rendered", True) and callable( 

153 getattr(response, "render", None) 

154 ): 

155 response = response.render() 

156 

157 return response 

158 

159 

160def get_exception_response(request, resolver, status_code, exception): 

161 try: 

162 callback = resolver.resolve_error_handler(status_code) 

163 response = callback(request, exception=exception) 

164 except Exception: 

165 signals.got_request_exception.send(sender=None, request=request) 

166 response = handle_uncaught_exception(request, resolver, sys.exc_info()) 

167 

168 return response 

169 

170 

171def handle_uncaught_exception(request, resolver, exc_info): 

172 """ 

173 Processing for any otherwise uncaught exceptions (those that will 

174 generate HTTP 500 responses). 

175 """ 

176 if settings.DEBUG_PROPAGATE_EXCEPTIONS: 

177 raise 

178 

179 if settings.DEBUG: 

180 return debug.technical_500_response(request, *exc_info) 

181 

182 # Return an HttpResponse that displays a friendly error message. 

183 callback = resolver.resolve_error_handler(500) 

184 return callback(request)