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

Side by Side Diff: third_party/cherrypy/_cptree.py

Issue 9368042: Add CherryPy to third_party. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build/
Patch Set: '' Created 8 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 | Annotate | Revision Log
« no previous file with comments | « third_party/cherrypy/_cptools.py ('k') | third_party/cherrypy/_cpwsgi.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 """CherryPy Application and Tree objects."""
2
3 import os
4 import sys
5
6 import cherrypy
7 from cherrypy._cpcompat import ntou, py3k
8 from cherrypy import _cpconfig, _cplogging, _cprequest, _cpwsgi, tools
9 from cherrypy.lib import httputil
10
11
12 class Application(object):
13 """A CherryPy Application.
14
15 Servers and gateways should not instantiate Request objects directly.
16 Instead, they should ask an Application object for a request object.
17
18 An instance of this class may also be used as a WSGI callable
19 (WSGI application object) for itself.
20 """
21
22 root = None
23 """The top-most container of page handlers for this app. Handlers should
24 be arranged in a hierarchy of attributes, matching the expected URI
25 hierarchy; the default dispatcher then searches this hierarchy for a
26 matching handler. When using a dispatcher other than the default,
27 this value may be None."""
28
29 config = {}
30 """A dict of {path: pathconf} pairs, where 'pathconf' is itself a dict
31 of {key: value} pairs."""
32
33 namespaces = _cpconfig.NamespaceSet()
34 toolboxes = {'tools': cherrypy.tools}
35
36 log = None
37 """A LogManager instance. See _cplogging."""
38
39 wsgiapp = None
40 """A CPWSGIApp instance. See _cpwsgi."""
41
42 request_class = _cprequest.Request
43 response_class = _cprequest.Response
44
45 relative_urls = False
46
47 def __init__(self, root, script_name="", config=None):
48 self.log = _cplogging.LogManager(id(self), cherrypy.log.logger_root)
49 self.root = root
50 self.script_name = script_name
51 self.wsgiapp = _cpwsgi.CPWSGIApp(self)
52
53 self.namespaces = self.namespaces.copy()
54 self.namespaces["log"] = lambda k, v: setattr(self.log, k, v)
55 self.namespaces["wsgi"] = self.wsgiapp.namespace_handler
56
57 self.config = self.__class__.config.copy()
58 if config:
59 self.merge(config)
60
61 def __repr__(self):
62 return "%s.%s(%r, %r)" % (self.__module__, self.__class__.__name__,
63 self.root, self.script_name)
64
65 script_name_doc = """The URI "mount point" for this app. A mount point is th at portion of
66 the URI which is constant for all URIs that are serviced by this
67 application; it does not include scheme, host, or proxy ("virtual host")
68 portions of the URI.
69
70 For example, if script_name is "/my/cool/app", then the URL
71 "http://www.example.com/my/cool/app/page1" might be handled by a
72 "page1" method on the root object.
73
74 The value of script_name MUST NOT end in a slash. If the script_name
75 refers to the root of the URI, it MUST be an empty string (not "/").
76
77 If script_name is explicitly set to None, then the script_name will be
78 provided for each call from request.wsgi_environ['SCRIPT_NAME'].
79 """
80 def _get_script_name(self):
81 if self._script_name is None:
82 # None signals that the script name should be pulled from WSGI envir on.
83 return cherrypy.serving.request.wsgi_environ['SCRIPT_NAME'].rstrip(" /")
84 return self._script_name
85 def _set_script_name(self, value):
86 if value:
87 value = value.rstrip("/")
88 self._script_name = value
89 script_name = property(fget=_get_script_name, fset=_set_script_name,
90 doc=script_name_doc)
91
92 def merge(self, config):
93 """Merge the given config into self.config."""
94 _cpconfig.merge(self.config, config)
95
96 # Handle namespaces specified in config.
97 self.namespaces(self.config.get("/", {}))
98
99 def find_config(self, path, key, default=None):
100 """Return the most-specific value for key along path, or default."""
101 trail = path or "/"
102 while trail:
103 nodeconf = self.config.get(trail, {})
104
105 if key in nodeconf:
106 return nodeconf[key]
107
108 lastslash = trail.rfind("/")
109 if lastslash == -1:
110 break
111 elif lastslash == 0 and trail != "/":
112 trail = "/"
113 else:
114 trail = trail[:lastslash]
115
116 return default
117
118 def get_serving(self, local, remote, scheme, sproto):
119 """Create and return a Request and Response object."""
120 req = self.request_class(local, remote, scheme, sproto)
121 req.app = self
122
123 for name, toolbox in self.toolboxes.items():
124 req.namespaces[name] = toolbox
125
126 resp = self.response_class()
127 cherrypy.serving.load(req, resp)
128 cherrypy.engine.publish('acquire_thread')
129 cherrypy.engine.publish('before_request')
130
131 return req, resp
132
133 def release_serving(self):
134 """Release the current serving (request and response)."""
135 req = cherrypy.serving.request
136
137 cherrypy.engine.publish('after_request')
138
139 try:
140 req.close()
141 except:
142 cherrypy.log(traceback=True, severity=40)
143
144 cherrypy.serving.clear()
145
146 def __call__(self, environ, start_response):
147 return self.wsgiapp(environ, start_response)
148
149
150 class Tree(object):
151 """A registry of CherryPy applications, mounted at diverse points.
152
153 An instance of this class may also be used as a WSGI callable
154 (WSGI application object), in which case it dispatches to all
155 mounted apps.
156 """
157
158 apps = {}
159 """
160 A dict of the form {script name: application}, where "script name"
161 is a string declaring the URI mount point (no trailing slash), and
162 "application" is an instance of cherrypy.Application (or an arbitrary
163 WSGI callable if you happen to be using a WSGI server)."""
164
165 def __init__(self):
166 self.apps = {}
167
168 def mount(self, root, script_name="", config=None):
169 """Mount a new app from a root object, script_name, and config.
170
171 root
172 An instance of a "controller class" (a collection of page
173 handler methods) which represents the root of the application.
174 This may also be an Application instance, or None if using
175 a dispatcher other than the default.
176
177 script_name
178 A string containing the "mount point" of the application.
179 This should start with a slash, and be the path portion of the
180 URL at which to mount the given root. For example, if root.index()
181 will handle requests to "http://www.example.com:8080/dept/app1/",
182 then the script_name argument would be "/dept/app1".
183
184 It MUST NOT end in a slash. If the script_name refers to the
185 root of the URI, it MUST be an empty string (not "/").
186
187 config
188 A file or dict containing application config.
189 """
190 if script_name is None:
191 raise TypeError(
192 "The 'script_name' argument may not be None. Application "
193 "objects may, however, possess a script_name of None (in "
194 "order to inpect the WSGI environ for SCRIPT_NAME upon each "
195 "request). You cannot mount such Applications on this Tree; "
196 "you must pass them to a WSGI server interface directly.")
197
198 # Next line both 1) strips trailing slash and 2) maps "/" -> "".
199 script_name = script_name.rstrip("/")
200
201 if isinstance(root, Application):
202 app = root
203 if script_name != "" and script_name != app.script_name:
204 raise ValueError("Cannot specify a different script name and "
205 "pass an Application instance to cherrypy.mount ")
206 script_name = app.script_name
207 else:
208 app = Application(root, script_name)
209
210 # If mounted at "", add favicon.ico
211 if (script_name == "" and root is not None
212 and not hasattr(root, "favicon_ico")):
213 favicon = os.path.join(os.getcwd(), os.path.dirname(__file__),
214 "favicon.ico")
215 root.favicon_ico = tools.staticfile.handler(favicon)
216
217 if config:
218 app.merge(config)
219
220 self.apps[script_name] = app
221
222 return app
223
224 def graft(self, wsgi_callable, script_name=""):
225 """Mount a wsgi callable at the given script_name."""
226 # Next line both 1) strips trailing slash and 2) maps "/" -> "".
227 script_name = script_name.rstrip("/")
228 self.apps[script_name] = wsgi_callable
229
230 def script_name(self, path=None):
231 """The script_name of the app at the given path, or None.
232
233 If path is None, cherrypy.request is used.
234 """
235 if path is None:
236 try:
237 request = cherrypy.serving.request
238 path = httputil.urljoin(request.script_name,
239 request.path_info)
240 except AttributeError:
241 return None
242
243 while True:
244 if path in self.apps:
245 return path
246
247 if path == "":
248 return None
249
250 # Move one node up the tree and try again.
251 path = path[:path.rfind("/")]
252
253 def __call__(self, environ, start_response):
254 # If you're calling this, then you're probably setting SCRIPT_NAME
255 # to '' (some WSGI servers always set SCRIPT_NAME to '').
256 # Try to look up the app using the full path.
257 env1x = environ
258 if environ.get(ntou('wsgi.version')) == (ntou('u'), 0):
259 env1x = _cpwsgi.downgrade_wsgi_ux_to_1x(environ)
260 path = httputil.urljoin(env1x.get('SCRIPT_NAME', ''),
261 env1x.get('PATH_INFO', ''))
262 sn = self.script_name(path or "/")
263 if sn is None:
264 start_response('404 Not Found', [])
265 return []
266
267 app = self.apps[sn]
268
269 # Correct the SCRIPT_NAME and PATH_INFO environ entries.
270 environ = environ.copy()
271 if not py3k:
272 if environ.get(ntou('wsgi.version')) == (ntou('u'), 0):
273 # Python 2/WSGI u.0: all strings MUST be of type unicode
274 enc = environ[ntou('wsgi.url_encoding')]
275 environ[ntou('SCRIPT_NAME')] = sn.decode(enc)
276 environ[ntou('PATH_INFO')] = path[len(sn.rstrip("/")):].decode(e nc)
277 else:
278 # Python 2/WSGI 1.x: all strings MUST be of type str
279 environ['SCRIPT_NAME'] = sn
280 environ['PATH_INFO'] = path[len(sn.rstrip("/")):]
281 else:
282 if environ.get(ntou('wsgi.version')) == (ntou('u'), 0):
283 # Python 3/WSGI u.0: all strings MUST be full unicode
284 environ['SCRIPT_NAME'] = sn
285 environ['PATH_INFO'] = path[len(sn.rstrip("/")):]
286 else:
287 # Python 3/WSGI 1.x: all strings MUST be ISO-8859-1 str
288 environ['SCRIPT_NAME'] = sn.encode('utf-8').decode('ISO-8859-1')
289 environ['PATH_INFO'] = path[len(sn.rstrip("/")):].encode('utf-8' ).decode('ISO-8859-1')
290 return app(environ, start_response)
OLDNEW
« no previous file with comments | « third_party/cherrypy/_cptools.py ('k') | third_party/cherrypy/_cpwsgi.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698