Mercurial > hg > wsgintegrate
comparison wsgintegrate/match.py @ 0:ec815b7cb142
initial commit of wsgintegrate
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Tue, 07 Jun 2011 08:03:09 -0700 |
parents | |
children | 89047fd9ea8f |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:ec815b7cb142 |
---|---|
1 """ | |
2 utilities for matching requests | |
3 these are just a sample; you can add arbitrary match objects if desired | |
4 """ | |
5 | |
6 from webob import exc | |
7 | |
8 class RequestMatch(object): | |
9 """abstract base class for matching requests""" | |
10 | |
11 def __init__(self, app): | |
12 self.app = app | |
13 | |
14 def __call__(self, environ, start_response): | |
15 """WSGI app""" | |
16 if not self.condition(environ): | |
17 raise exc.HTTPNotFound | |
18 return self.app(environ, start_response) | |
19 | |
20 def condition(self, environ): | |
21 """match condition""" | |
22 return True | |
23 | |
24 class ConditionMatch(RequestMatch): | |
25 """generic environment-based condition-checker""" | |
26 # XXX unused | |
27 def __init__(self, app, condition): | |
28 RequestMatch.__init__(self, app) | |
29 self.condition = condition | |
30 | |
31 ### aspect-based checkers | |
32 | |
33 class MatchPath(RequestMatch): | |
34 """match based on PATH INFO""" | |
35 | |
36 def __init__(self, app, path): | |
37 RequestMatch.__init__(self, app) | |
38 self.path = path | |
39 | |
40 def match(self, path): | |
41 if path.startswith(self.path): | |
42 # currently only matches with str.startswith; | |
43 # different types of matches could be considered | |
44 return self.path, path[len(self.path):] | |
45 | |
46 def condition(self, environ): # XXX unused | |
47 return self.match(environ['PATH_INFO']) is not None | |
48 | |
49 def __call__(self, environ, start_response): | |
50 match = self.match(environ['PATH_INFO']) | |
51 if match is None: | |
52 raise exc.HTTPNotFound | |
53 script_name, path_info = match | |
54 | |
55 # fix up the environment for downstream applications | |
56 environ['SCRIPT_NAME'] = script_name | |
57 environ['PATH_INFO'] = path_info | |
58 | |
59 return self.app(environ, start_response) | |
60 | |
61 class MatchMethod(RequestMatch): | |
62 """match based on request method""" | |
63 | |
64 def __init__(self, app, methods): | |
65 RequestMatch.__init__(self, app) | |
66 if isinstance(methods, basestring): | |
67 methods = methods.split() | |
68 self.methods = set(methods) | |
69 | |
70 def condition(self, environ): | |
71 return environ['REQUEST_METHOD'] in self.methods | |
72 | |
73 class MatchHost(RequestMatch): | |
74 """match based on the host and port""" | |
75 | |
76 def __init__(self, app, host, port=None): | |
77 RequestMatch.__init__(self, app) | |
78 self.host = host | |
79 self.port = port | |
80 def condition(self, environ): | |
81 host = environ['HTTP_HOST'] | |
82 port = None | |
83 if ':' in host: | |
84 host, port = host.rsplit(':', 1) | |
85 if self.port and port != self.port: | |
86 return False | |
87 return host == self.host | |
88 | |
89 class MatchAuthorized(RequestMatch): | |
90 """match if a user is authorized or not""" | |
91 def __init__(self, app, users=None): | |
92 RequestMatch.__init__(self, app) | |
93 self.authorized_users = users | |
94 def condition(self, environ): | |
95 raise NotImplementedError # TODO | |
96 | |
97 class MatchProtocol(RequestMatch): | |
98 """match a given protocol, i.e. http vs https://""" | |
99 def __init__(self, app, protocol): | |
100 self.protocol = protocol | |
101 RequestMatch.__init__(self, app) | |
102 def condition(self, environ): | |
103 raise NotImplementedError # TODO | |
104 | |
105 class MatchQueryString(RequestMatch): | |
106 """ | |
107 match a request based on if the right query string parameters are given | |
108 """ | |
109 def __init__(self, app, *tags, **kw): | |
110 self.app = app | |
111 self.tags = tags | |
112 self.kw = kw | |
113 def condition(self, environ): | |
114 raise NotImplementedError # TODO | |
115 | |
116 ### logical checkers (currently unused) | |
117 | |
118 class AND(RequestMatch): | |
119 def __init__(self, app, condition1, condition2, *conditions): | |
120 RequestMatch.__init__(self, app) | |
121 self.conditions = [condition1, condition2] | |
122 self.conditions.extend(conditions) | |
123 def condition(self, environ): | |
124 for condition in self.conditions: | |
125 if isinstance(condition, RequestMatch): | |
126 if not condition.condition(environ): | |
127 return False | |
128 else: | |
129 if not condition(): | |
130 return False | |
131 return True | |
132 | |
133 class OR(RequestMatch): | |
134 def __init__(self, app, condition1, condition2, *conditions): | |
135 RequestMatch.__init__(self, app) | |
136 self.conditions = [condition1, condition2] | |
137 self.conditions.extend(conditions) | |
138 def condition(self, environ): | |
139 for condition in self.conditions: | |
140 if isinstance(condition, RequestMatch): | |
141 if condition.condition(environ): | |
142 return True | |
143 else: | |
144 if condition(): | |
145 return | |
146 return False | |
147 | |
148 # string accessible list of conditions | |
149 conditions = {'host': MatchHost, | |
150 'method': MatchMethod, | |
151 'path': MatchPath } | |
152 | |
153 class WrapApp(object): | |
154 """match string-based conditions""" | |
155 | |
156 def __init__(self, conditions=None): | |
157 self.conditions = conditions or globals()['conditions'] | |
158 | |
159 def __call__(self, app, *conditions, **kwargs): | |
160 """ | |
161 wrap an app in conditions | |
162 conditions should be a key, value 2-tuple of string, args; | |
163 kwargs should be a dictionary of unordered conditions, | |
164 likewise of the form string, args. | |
165 use *conditions if order is important, otherwise kwargs | |
166 """ | |
167 | |
168 # determine the condition | |
169 conditions = list(conditions) | |
170 if kwargs: | |
171 conditions.extend(kwargs.items()) | |
172 | |
173 # wrap the application | |
174 for condition, args in conditions: | |
175 assert condition in self.conditions, 'Condition "%s" unknown' % condition | |
176 app = self.conditions[condition](app, args) | |
177 return app | |
178 | |
179 # convenience invocation | |
180 wrap = WrapApp(conditions) | |
181 |