comparison env/lib/python3.9/site-packages/routes/middleware.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 """Routes WSGI Middleware"""
2 import re
3 import logging
4
5 from webob import Request
6
7 from routes.base import request_config
8 from routes.util import URLGenerator
9
10 log = logging.getLogger('routes.middleware')
11
12
13 class RoutesMiddleware(object):
14 """Routing middleware that handles resolving the PATH_INFO in
15 addition to optionally recognizing method overriding.
16
17 .. Note::
18 This module requires webob to be installed. To depend on it, you may
19 list routes[middleware] in your ``requirements.txt``
20 """
21 def __init__(self, wsgi_app, mapper, use_method_override=True,
22 path_info=True, singleton=True):
23 """Create a Route middleware object
24
25 Using the use_method_override keyword will require Paste to be
26 installed, and your application should use Paste's WSGIRequest
27 object as it will properly handle POST issues with wsgi.input
28 should Routes check it.
29
30 If path_info is True, then should a route var contain
31 path_info, the SCRIPT_NAME and PATH_INFO will be altered
32 accordingly. This should be used with routes like:
33
34 .. code-block:: python
35
36 map.connect('blog/*path_info', controller='blog', path_info='')
37
38 """
39 self.app = wsgi_app
40 self.mapper = mapper
41 self.singleton = singleton
42 self.use_method_override = use_method_override
43 self.path_info = path_info
44 self.log_debug = logging.DEBUG >= log.getEffectiveLevel()
45 if self.log_debug:
46 log.debug("Initialized with method overriding = %s, and path "
47 "info altering = %s", use_method_override, path_info)
48
49 def __call__(self, environ, start_response):
50 """Resolves the URL in PATH_INFO, and uses wsgi.routing_args
51 to pass on URL resolver results."""
52 old_method = None
53 if self.use_method_override:
54 req = None
55
56 # In some odd cases, there's no query string
57 try:
58 qs = environ['QUERY_STRING']
59 except KeyError:
60 qs = ''
61 if '_method' in qs:
62 req = Request(environ)
63 req.errors = 'ignore'
64
65 try:
66 method = req.GET.get('_method')
67 except UnicodeDecodeError:
68 method = None
69
70 if method:
71 old_method = environ['REQUEST_METHOD']
72 environ['REQUEST_METHOD'] = method.upper()
73 if self.log_debug:
74 log.debug("_method found in QUERY_STRING, altering "
75 "request method to %s",
76 environ['REQUEST_METHOD'])
77 elif environ['REQUEST_METHOD'] == 'POST' and is_form_post(environ):
78 if req is None:
79 req = Request(environ)
80 req.errors = 'ignore'
81
82 try:
83 method = req.POST.get('_method')
84 except UnicodeDecodeError:
85 method = None
86
87 if method:
88 old_method = environ['REQUEST_METHOD']
89 environ['REQUEST_METHOD'] = method.upper()
90 if self.log_debug:
91 log.debug("_method found in POST data, altering "
92 "request method to %s",
93 environ['REQUEST_METHOD'])
94
95 # Run the actual route matching
96 # -- Assignment of environ to config triggers route matching
97 if self.singleton:
98 config = request_config()
99 config.mapper = self.mapper
100 config.environ = environ
101 match = config.mapper_dict
102 route = config.route
103 else:
104 results = self.mapper.routematch(environ=environ)
105 if results:
106 match, route = results[0], results[1]
107 else:
108 match = route = None
109
110 if old_method:
111 environ['REQUEST_METHOD'] = old_method
112
113 if not match:
114 match = {}
115 if self.log_debug:
116 urlinfo = "%s %s" % (environ['REQUEST_METHOD'],
117 environ['PATH_INFO'])
118 log.debug("No route matched for %s", urlinfo)
119 elif self.log_debug:
120 urlinfo = "%s %s" % (environ['REQUEST_METHOD'],
121 environ['PATH_INFO'])
122 log.debug("Matched %s", urlinfo)
123 log.debug("Route path: '%s', defaults: %s", route.routepath,
124 route.defaults)
125 log.debug("Match dict: %s", match)
126
127 url = URLGenerator(self.mapper, environ)
128 environ['wsgiorg.routing_args'] = ((url), match)
129 environ['routes.route'] = route
130 environ['routes.url'] = url
131
132 if route and route.redirect:
133 route_name = '_redirect_%s' % id(route)
134 location = url(route_name, **match)
135 log.debug("Using redirect route, redirect to '%s' with status"
136 "code: %s", location, route.redirect_status)
137 start_response(route.redirect_status,
138 [('Content-Type', 'text/plain; charset=utf8'),
139 ('Location', location)])
140 return []
141
142 # If the route included a path_info attribute and it should be used to
143 # alter the environ, we'll pull it out
144 if self.path_info and 'path_info' in match:
145 oldpath = environ['PATH_INFO']
146 newpath = match.get('path_info') or ''
147 environ['PATH_INFO'] = newpath
148 if not environ['PATH_INFO'].startswith('/'):
149 environ['PATH_INFO'] = '/' + environ['PATH_INFO']
150 environ['SCRIPT_NAME'] += re.sub(
151 r'^(.*?)/' + re.escape(newpath) + '$', r'\1', oldpath)
152
153 response = self.app(environ, start_response)
154
155 # Wrapped in try as in rare cases the attribute will be gone already
156 try:
157 del self.mapper.environ
158 except AttributeError:
159 pass
160 return response
161
162
163 def is_form_post(environ):
164 """Determine whether the request is a POSTed html form"""
165 content_type = environ.get('CONTENT_TYPE', '').lower()
166 if ';' in content_type:
167 content_type = content_type.split(';', 1)[0]
168 return content_type in ('application/x-www-form-urlencoded',
169 'multipart/form-data')