Coverage for /Users/davegaeddert/Development/dropseed/plain/plain/plain/internal/middleware/slash.py: 57%

28 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-10-16 22:24 -0500

1from plain.http import ResponsePermanentRedirect 

2from plain.runtime import settings 

3from plain.urls import is_valid_path 

4from plain.utils.http import escape_leading_slashes 

5 

6 

7class RedirectSlashMiddleware: 

8 def __init__(self, get_response): 

9 self.get_response = get_response 

10 

11 def __call__(self, request): 

12 """ 

13 Rewrite the URL based on settings.APPEND_SLASH 

14 """ 

15 

16 response = self.get_response(request) 

17 

18 """ 

19 When the status code of the response is 404, it may redirect to a path 

20 with an appended slash if should_redirect_with_slash() returns True. 

21 """ 

22 # If the given URL is "Not Found", then check if we should redirect to 

23 # a path with a slash appended. 

24 if response.status_code == 404 and self.should_redirect_with_slash(request): 

25 return ResponsePermanentRedirect(self.get_full_path_with_slash(request)) 

26 

27 return response 

28 

29 def should_redirect_with_slash(self, request): 

30 """ 

31 Return True if settings.APPEND_SLASH is True and appending a slash to 

32 the request path turns an invalid path into a valid one. 

33 """ 

34 if settings.APPEND_SLASH and not request.path_info.endswith("/"): 

35 urlconf = getattr(request, "urlconf", None) 

36 if not is_valid_path(request.path_info, urlconf): 

37 match = is_valid_path("%s/" % request.path_info, urlconf) 

38 if match: 

39 view = match.func 

40 return getattr(view, "should_append_slash", True) 

41 return False 

42 

43 def get_full_path_with_slash(self, request): 

44 """ 

45 Return the full path of the request with a trailing slash appended. 

46 

47 Raise a RuntimeError if settings.DEBUG is True and request.method is 

48 POST, PUT, or PATCH. 

49 """ 

50 new_path = request.get_full_path(force_append_slash=True) 

51 # Prevent construction of scheme relative urls. 

52 new_path = escape_leading_slashes(new_path) 

53 if settings.DEBUG and request.method in ("POST", "PUT", "PATCH"): 

54 raise RuntimeError( 

55 "You called this URL via {method}, but the URL doesn't end " 

56 "in a slash and you have APPEND_SLASH set. Plain can't " 

57 "redirect to the slash URL while maintaining {method} data. " 

58 "Change your form to point to {url} (note the trailing " 

59 "slash), or set APPEND_SLASH=False in your Plain settings.".format( 

60 method=request.method, 

61 url=request.get_host() + new_path, 

62 ) 

63 ) 

64 return new_path