Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(439)

Side by Side Diff: third_party/Paste/paste/urlmap.py.orig

Issue 1729313002: Remove ".orig" files and add a check to presubmit (Closed) Base URL: git@github.com:catapult-project/catapult.git@master
Patch Set: Generate a single presubmit error message Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/Paste/README.chromium ('k') | third_party/Paste/paste/util/template.py.orig » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.o rg)
2 # Licensed under the MIT license: http://www.opensource.org/licenses/mit-license .php
3 """
4 Map URL prefixes to WSGI applications. See ``URLMap``
5 """
6
7 import re
8 import os
9 import cgi
10 try:
11 # Python 3
12 from collections import MutableMapping as DictMixin
13 except ImportError:
14 # Python 2
15 from UserDict import DictMixin
16
17 from paste import httpexceptions
18
19 __all__ = ['URLMap', 'PathProxyURLMap']
20
21 def urlmap_factory(loader, global_conf, **local_conf):
22 if 'not_found_app' in local_conf:
23 not_found_app = local_conf.pop('not_found_app')
24 else:
25 not_found_app = global_conf.get('not_found_app')
26 if not_found_app:
27 not_found_app = loader.get_app(not_found_app, global_conf=global_conf)
28 urlmap = URLMap(not_found_app=not_found_app)
29 for path, app_name in local_conf.items():
30 path = parse_path_expression(path)
31 app = loader.get_app(app_name, global_conf=global_conf)
32 urlmap[path] = app
33 return urlmap
34
35 def parse_path_expression(path):
36 """
37 Parses a path expression like 'domain foobar.com port 20 /' or
38 just '/foobar' for a path alone. Returns as an address that
39 URLMap likes.
40 """
41 parts = path.split()
42 domain = port = path = None
43 while parts:
44 if parts[0] == 'domain':
45 parts.pop(0)
46 if not parts:
47 raise ValueError("'domain' must be followed with a domain name")
48 if domain:
49 raise ValueError("'domain' given twice")
50 domain = parts.pop(0)
51 elif parts[0] == 'port':
52 parts.pop(0)
53 if not parts:
54 raise ValueError("'port' must be followed with a port number")
55 if port:
56 raise ValueError("'port' given twice")
57 port = parts.pop(0)
58 else:
59 if path:
60 raise ValueError("more than one path given (have %r, got %r)"
61 % (path, parts[0]))
62 path = parts.pop(0)
63 s = ''
64 if domain:
65 s = 'http://%s' % domain
66 if port:
67 if not domain:
68 raise ValueError("If you give a port, you must also give a domain")
69 s += ':' + port
70 if path:
71 if s:
72 s += '/'
73 s += path
74 return s
75
76 class URLMap(DictMixin):
77
78 """
79 URLMap instances are dictionary-like object that dispatch to one
80 of several applications based on the URL.
81
82 The dictionary keys are URLs to match (like
83 ``PATH_INFO.startswith(url)``), and the values are applications to
84 dispatch to. URLs are matched most-specific-first, i.e., longest
85 URL first. The ``SCRIPT_NAME`` and ``PATH_INFO`` environmental
86 variables are adjusted to indicate the new context.
87
88 URLs can also include domains, like ``http://blah.com/foo``, or as
89 tuples ``('blah.com', '/foo')``. This will match domain names; without
90 the ``http://domain`` or with a domain of ``None`` any domain will be
91 matched (so long as no other explicit domain matches). """
92
93 def __init__(self, not_found_app=None):
94 self.applications = []
95 if not not_found_app:
96 not_found_app = self.not_found_app
97 self.not_found_application = not_found_app
98
99 def __len__(self):
100 return len(self.applications)
101
102 def __iter__(self):
103 for app_url, app in self.applications:
104 yield app_url
105
106 norm_url_re = re.compile('//+')
107 domain_url_re = re.compile('^(http|https)://')
108
109 def not_found_app(self, environ, start_response):
110 mapper = environ.get('paste.urlmap_object')
111 if mapper:
112 matches = [p for p, a in mapper.applications]
113 extra = 'defined apps: %s' % (
114 ',\n '.join(map(repr, matches)))
115 else:
116 extra = ''
117 extra += '\nSCRIPT_NAME: %r' % cgi.escape(environ.get('SCRIPT_NAME'))
118 extra += '\nPATH_INFO: %r' % cgi.escape(environ.get('PATH_INFO'))
119 extra += '\nHTTP_HOST: %r' % cgi.escape(environ.get('HTTP_HOST'))
120 app = httpexceptions.HTTPNotFound(
121 environ['PATH_INFO'],
122 comment=cgi.escape(extra)).wsgi_application
123 return app(environ, start_response)
124
125 def normalize_url(self, url, trim=True):
126 if isinstance(url, (list, tuple)):
127 domain = url[0]
128 url = self.normalize_url(url[1])[1]
129 return domain, url
130 assert (not url or url.startswith('/')
131 or self.domain_url_re.search(url)), (
132 "URL fragments must start with / or http:// (you gave %r)" % url)
133 match = self.domain_url_re.search(url)
134 if match:
135 url = url[match.end():]
136 if '/' in url:
137 domain, url = url.split('/', 1)
138 url = '/' + url
139 else:
140 domain, url = url, ''
141 else:
142 domain = None
143 url = self.norm_url_re.sub('/', url)
144 if trim:
145 url = url.rstrip('/')
146 return domain, url
147
148 def sort_apps(self):
149 """
150 Make sure applications are sorted with longest URLs first
151 """
152 def key(app_desc):
153 (domain, url), app = app_desc
154 if not domain:
155 # Make sure empty domains sort last:
156 return '\xff', -len(url)
157 else:
158 return domain, -len(url)
159 apps = [(key(desc), desc) for desc in self.applications]
160 apps.sort()
161 self.applications = [desc for (sortable, desc) in apps]
162
163 def __setitem__(self, url, app):
164 if app is None:
165 try:
166 del self[url]
167 except KeyError:
168 pass
169 return
170 dom_url = self.normalize_url(url)
171 if dom_url in self:
172 del self[dom_url]
173 self.applications.append((dom_url, app))
174 self.sort_apps()
175
176 def __getitem__(self, url):
177 dom_url = self.normalize_url(url)
178 for app_url, app in self.applications:
179 if app_url == dom_url:
180 return app
181 raise KeyError(
182 "No application with the url %r (domain: %r; existing: %s)"
183 % (url[1], url[0] or '*', self.applications))
184
185 def __delitem__(self, url):
186 url = self.normalize_url(url)
187 for app_url, app in self.applications:
188 if app_url == url:
189 self.applications.remove((app_url, app))
190 break
191 else:
192 raise KeyError(
193 "No application with the url %r" % (url,))
194
195 def keys(self):
196 return [app_url for app_url, app in self.applications]
197
198 def __call__(self, environ, start_response):
199 host = environ.get('HTTP_HOST', environ.get('SERVER_NAME')).lower()
200 if ':' in host:
201 host, port = host.split(':', 1)
202 else:
203 if environ['wsgi.url_scheme'] == 'http':
204 port = '80'
205 else:
206 port = '443'
207 path_info = environ.get('PATH_INFO')
208 path_info = self.normalize_url(path_info, False)[1]
209 for (domain, app_url), app in self.applications:
210 if domain and domain != host and domain != host+':'+port:
211 continue
212 if (path_info == app_url
213 or path_info.startswith(app_url + '/')):
214 environ['SCRIPT_NAME'] += app_url
215 environ['PATH_INFO'] = path_info[len(app_url):]
216 return app(environ, start_response)
217 environ['paste.urlmap_object'] = self
218 return self.not_found_application(environ, start_response)
219
220
221 class PathProxyURLMap(object):
222
223 """
224 This is a wrapper for URLMap that catches any strings that
225 are passed in as applications; these strings are treated as
226 filenames (relative to `base_path`) and are passed to the
227 callable `builder`, which will return an application.
228
229 This is intended for cases when configuration files can be
230 treated as applications.
231
232 `base_paste_url` is the URL under which all applications added through
233 this wrapper must go. Use ``""`` if you want this to not
234 change incoming URLs.
235 """
236
237 def __init__(self, map, base_paste_url, base_path, builder):
238 self.map = map
239 self.base_paste_url = self.map.normalize_url(base_paste_url)
240 self.base_path = base_path
241 self.builder = builder
242
243 def __setitem__(self, url, app):
244 if isinstance(app, (str, unicode)):
245 app_fn = os.path.join(self.base_path, app)
246 app = self.builder(app_fn)
247 url = self.map.normalize_url(url)
248 # @@: This means http://foo.com/bar will potentially
249 # match foo.com, but /base_paste_url/bar, which is unintuitive
250 url = (url[0] or self.base_paste_url[0],
251 self.base_paste_url[1] + url[1])
252 self.map[url] = app
253
254 def __getattr__(self, attr):
255 return getattr(self.map, attr)
256
257 # This is really the only settable attribute
258 def not_found_application__get(self):
259 return self.map.not_found_application
260 def not_found_application__set(self, value):
261 self.map.not_found_application = value
262 not_found_application = property(not_found_application__get,
263 not_found_application__set)
OLDNEW
« no previous file with comments | « third_party/Paste/README.chromium ('k') | third_party/Paste/paste/util/template.py.orig » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698