comparison env/lib/python3.7/site-packages/routes/middleware.py @ 0:26e78fe6e8c4 draft

"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author shellac
date Sat, 02 May 2020 07:14:21 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:26e78fe6e8c4
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 if '_method' in req.GET:
65 old_method = environ['REQUEST_METHOD']
66 environ['REQUEST_METHOD'] = req.GET['_method'].upper()
67 if self.log_debug:
68 log.debug("_method found in QUERY_STRING, altering "
69 "request method to %s",
70 environ['REQUEST_METHOD'])
71 elif environ['REQUEST_METHOD'] == 'POST' and is_form_post(environ):
72 if req is None:
73 req = Request(environ)
74 req.errors = 'ignore'
75 if '_method' in req.POST:
76 old_method = environ['REQUEST_METHOD']
77 environ['REQUEST_METHOD'] = req.POST['_method'].upper()
78 if self.log_debug:
79 log.debug("_method found in POST data, altering "
80 "request method to %s",
81 environ['REQUEST_METHOD'])
82
83 # Run the actual route matching
84 # -- Assignment of environ to config triggers route matching
85 if self.singleton:
86 config = request_config()
87 config.mapper = self.mapper
88 config.environ = environ
89 match = config.mapper_dict
90 route = config.route
91 else:
92 results = self.mapper.routematch(environ=environ)
93 if results:
94 match, route = results[0], results[1]
95 else:
96 match = route = None
97
98 if old_method:
99 environ['REQUEST_METHOD'] = old_method
100
101 if not match:
102 match = {}
103 if self.log_debug:
104 urlinfo = "%s %s" % (environ['REQUEST_METHOD'],
105 environ['PATH_INFO'])
106 log.debug("No route matched for %s", urlinfo)
107 elif self.log_debug:
108 urlinfo = "%s %s" % (environ['REQUEST_METHOD'],
109 environ['PATH_INFO'])
110 log.debug("Matched %s", urlinfo)
111 log.debug("Route path: '%s', defaults: %s", route.routepath,
112 route.defaults)
113 log.debug("Match dict: %s", match)
114
115 url = URLGenerator(self.mapper, environ)
116 environ['wsgiorg.routing_args'] = ((url), match)
117 environ['routes.route'] = route
118 environ['routes.url'] = url
119
120 if route and route.redirect:
121 route_name = '_redirect_%s' % id(route)
122 location = url(route_name, **match)
123 log.debug("Using redirect route, redirect to '%s' with status"
124 "code: %s", location, route.redirect_status)
125 start_response(route.redirect_status,
126 [('Content-Type', 'text/plain; charset=utf8'),
127 ('Location', location)])
128 return []
129
130 # If the route included a path_info attribute and it should be used to
131 # alter the environ, we'll pull it out
132 if self.path_info and 'path_info' in match:
133 oldpath = environ['PATH_INFO']
134 newpath = match.get('path_info') or ''
135 environ['PATH_INFO'] = newpath
136 if not environ['PATH_INFO'].startswith('/'):
137 environ['PATH_INFO'] = '/' + environ['PATH_INFO']
138 environ['SCRIPT_NAME'] += re.sub(
139 r'^(.*?)/' + re.escape(newpath) + '$', r'\1', oldpath)
140
141 response = self.app(environ, start_response)
142
143 # Wrapped in try as in rare cases the attribute will be gone already
144 try:
145 del self.mapper.environ
146 except AttributeError:
147 pass
148 return response
149
150
151 def is_form_post(environ):
152 """Determine whether the request is a POSTed html form"""
153 content_type = environ.get('CONTENT_TYPE', '').lower()
154 if ';' in content_type:
155 content_type = content_type.split(';', 1)[0]
156 return content_type in ('application/x-www-form-urlencoded',
157 'multipart/form-data')