Changeset 910
- Timestamp:
- 01/02/06 18:06:45
- Files:
-
- trunk/cherrypy/__init__.py (modified) (1 diff)
- trunk/cherrypy/_cphttptools.py (modified) (2 diffs)
- trunk/cherrypy/_cptree.py (added)
- trunk/cherrypy/_cputil.py (modified) (2 diffs)
- trunk/cherrypy/config.py (modified) (4 diffs)
- trunk/cherrypy/lib/httptools.py (modified) (1 diff)
- trunk/cherrypy/test/helper.py (modified) (5 diffs)
- trunk/cherrypy/test/test_baseurl_filter.py (modified) (1 diff)
- trunk/cherrypy/test/test_config.py (modified) (5 diffs)
- trunk/cherrypy/test/test_core.py (modified) (5 diffs)
- trunk/cherrypy/test/test_logdebuginfo_filter.py (modified) (1 diff)
- trunk/cherrypy/test/test_objectmapping.py (modified) (3 diffs)
- trunk/cherrypy/test/test_response_headers_filter.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/__init__.py
r887 r910 9 9 from _cperror import * 10 10 import config 11 12 import _cptree 13 tree = _cptree.Tree() 14 15 # Legacy code may clobber this. 16 root = None 17 11 18 import _cpserver 12 19 server = _cpserver.Server() trunk/cherrypy/_cphttptools.py
r904 r910 275 275 names = [name for name, candidate in objectTrail] 276 276 277 # Try successive objects 277 # Try successive objects (reverse order) 278 mounted_app_roots = cherrypy.tree.mount_points.values() 278 279 for i in xrange(len(objectTrail) - 1, -1, -1): 279 280 … … 300 301 raise cherrypy.HTTPRedirect(newUrl) 301 302 return candidate, names[:i+1], names[i+1:-1] 303 304 if candidate in mounted_app_roots: 305 break 302 306 303 307 # We didn't find anything trunk/cherrypy/_cputil.py
r901 r910 62 62 # First, we look in the right-most object to see if this special 63 63 # attribute is implemented. If not, then we try the previous object, 64 # and so on until we reach cherrypy.root . If it's still not there,65 # we use the implementation from this module.66 64 # and so on until we reach cherrypy.root, or a mount point. 65 # If it's still not there, we use the implementation from this module. 66 mounted_app_roots = cherrypy.tree.mount_points.values() 67 67 objectList = get_object_trail() 68 68 objectList.reverse() … … 72 72 elif hasattr(obj, name): 73 73 return getattr(obj, name) 74 if obj in mounted_app_roots: 75 break 74 76 75 77 try: trunk/cherrypy/config.py
r892 r910 6 6 import cherrypy 7 7 from cherrypy import _cputil 8 from cherrypy.lib import autoreload, cptools 8 from cherrypy.lib import autoreload, cptools, httptools 9 9 10 10 … … 56 56 } 57 57 58 def update(updateMap=None, file=None, overwrite=True ):58 def update(updateMap=None, file=None, overwrite=True, baseurl=""): 59 59 """Update configs from a dictionary or a config file. 60 60 … … 79 79 section = 'global' 80 80 81 if baseurl and section.startswith("/"): 82 if section == "/": 83 section = baseurl 84 else: 85 section = httptools.urljoin(baseurl, section) 86 81 87 bucket = configs.setdefault(section, {}) 82 88 if overwrite: … … 142 148 # Move one node up the tree and try again. 143 149 if path == "/": 150 path = "global" 151 elif path in cherrypy.tree.mount_points: 152 # We've reached the mount point for an application, 153 # and should skip the rest of the tree (up to "global"). 144 154 path = "global" 145 155 else: trunk/cherrypy/lib/httptools.py
r899 r910 21 21 import urllib 22 22 from urlparse import urlparse 23 24 25 def urljoin(*atoms): 26 url = "/".join(atoms) 27 while "//" in url: 28 url = url.replace("//", "/") 29 return url 23 30 24 31 trunk/cherrypy/test/helper.py
r893 r910 30 30 import cherrypy 31 31 from cherrypy import _cpwsgi 32 from cherrypy.lib import httptools 32 33 import webtest 33 34 … … 43 44 if not handled: 44 45 cherrypy._cputil._cp_on_error() 45 46 47 class VirtualRootFilter:48 49 def __init__(self, prefix):50 self.prefix = prefix51 52 def on_start_resource(self):53 path = cherrypy.request.object_path54 if path.startswith(self.prefix):55 cherrypy.request.object_path = path[len(self.prefix):]56 vroot = ""57 ##vroot = "/vpath"58 test_vrf = VirtualRootFilter(vroot)59 46 60 47 … … 85 72 86 73 class CPWebCase(webtest.WebCase): 74 75 mount_point = "" 76 77 def prefix(self): 78 return self.mount_point.rstrip("/") 87 79 88 80 def exit(self): … … 147 139 cherrypy.root._cpOnError = onerror 148 140 149 if vroot: 150 if url != "*": 151 url = vroot + url 152 filters = getattr(cherrypy.root, "_cp_filters", None) 153 if filters is None: 154 cherrypy.root._cp_filters = filters = [] 155 if test_vrf not in filters: 156 filters.append(test_vrf) 141 if self.mount_point: 142 url = httptools.urljoin(self.mount_point, url) 157 143 158 144 if cherrypy.server.httpserver is None: … … 220 206 # Must run each module in a separate suite, 221 207 # because each module uses/overwrites cherrypy globals. 208 cherrypy.root = None 222 209 cherrypy.config.reset() 223 210 setConfig(conf) trunk/cherrypy/test/test_baseurl_filter.py
r856 r910 25 25 self.getPage("/") 26 26 self.assertHeader('Location', 27 "http://www.mydomain.com%s/dummy" % helper.vroot)27 "http://www.mydomain.com%s/dummy" % self.prefix()) 28 28 29 29 trunk/cherrypy/test/test_config.py
r856 r910 5 5 import StringIO 6 6 import cherrypy 7 7 8 8 9 class Root: … … 26 27 prod = index 27 28 28 cherrypy.root = Root() 29 30 cherrypy.tree.mount(Root()) 29 31 cherrypy.root.foo = Foo() 30 cherrypy.root.env = Env() 32 31 33 cherrypy.config.update({ 32 34 'global': {'server.log_to_screen': False, … … 46 48 'bax': 'this4', 47 49 }, 48 '/env': {'server.environment': 'development'},49 '/env/prod': {'server.environment': 'production'},50 50 }) 51 52 _env_conf = {'/': {'server.environment': 'development'}, 53 '/prod': {'server.environment': 'production'}, 54 } 55 cherrypy.tree.mount(Env(), "/env", _env_conf) 51 56 52 57 # Shortcut syntax--should get put in the "global" bucket … … 69 74 ('/foo/bar', 'baz', 'that2'), 70 75 ('/foo/nex', 'baz', 'that2'), 76 # If 'foo' == 'this', then the mount point '/env' leaks into '/'. 77 ('/env/prod','foo', 'None'), 71 78 ] 72 79 for path, key, expected in tests: … … 85 92 self.getPage("/env/?key=" + key) 86 93 # The dev environment will have logdebuginfo data 87 self.assertEqual(self.body.split("\n")[0], str(val)) 94 data = self.body.split("\n")[0] 95 self.assertEqual(data, str(val)) 88 96 for key, val in cherrypy.config.environments['production'].iteritems(): 89 97 self.getPage("/env/prod/?key=" + key) trunk/cherrypy/test/test_core.py
r894 r910 447 447 if haslength: 448 448 self.assert_(data[0].endswith('] "GET %s/flatten/as_string HTTP/1.1" 200 7\n' 449 % helper.vroot))449 % self.prefix())) 450 450 else: 451 451 self.assert_(data[0].endswith('] "GET %s/flatten/as_string HTTP/1.1" 200 -\n' 452 % helper.vroot))452 % self.prefix())) 453 453 454 454 self.assertEqual(data[1][:15], '127.0.0.1 - - [') … … 459 459 if haslength: 460 460 self.assert_(data[1].endswith('] "GET %s/flatten/as_yield HTTP/1.1" 200 7\n' 461 % helper.vroot))461 % self.prefix())) 462 462 else: 463 463 self.assert_(data[1].endswith('] "GET %s/flatten/as_yield HTTP/1.1" 200 -\n' 464 % helper.vroot))464 % self.prefix())) 465 465 466 466 data = open(log_file, "rb").readlines() … … 501 501 self.assertInBody("<a href='http://127.0.0.1:%s%s/redirect/?id=3'>" 502 502 "http://127.0.0.1:%s%s/redirect/?id=3</a>" % 503 (self.PORT, helper.vroot, self.PORT, helper.vroot))504 505 if helper.vroot:503 (self.PORT, self.prefix(), self.PORT, self.prefix())) 504 505 if self.prefix(): 506 506 # Corner case: the "trailing slash" redirect could be tricky if 507 507 # we're using a virtual root and the URI is "/vroot" (no slash). … … 510 510 self.assertInBody("<a href='http://127.0.0.1:%s%s/'>" 511 511 "http://127.0.0.1:%s%s/</a>" % 512 (self.PORT, helper.vroot, self.PORT, helper.vroot))512 (self.PORT, self.prefix(), self.PORT, self.prefix())) 513 513 514 514 self.getPage("/redirect/by_code?code=300") … … 872 872 if httpcls: 873 873 cherrypy.config.update({ 874 '%s/maxrequestsize' % helper.vroot: {'server.max_request_body_size': 3}})874 '%s/maxrequestsize' % self.prefix(): {'server.max_request_body_size': 3}}) 875 875 self.getPage('/maxrequestsize/upload', h, "POST", b) 876 876 self.assertStatus("413 Request Entity Too Large") trunk/cherrypy/test/test_logdebuginfo_filter.py
r856 r910 47 47 """ 48 48 cherrypy.config.update({ 49 ('%s/bug326' % helper.vroot): {49 ('%s/bug326' % self.prefix): { 50 50 'server.max_request_body_size': 3, 51 51 'server.environment': 'development', trunk/cherrypy/test/test_objectmapping.py
r886 r910 88 88 return "index for dir4, not exposed" 89 89 90 cherrypy.root = Root() 91 cherrypy.root.exposing = Exposing() 92 cherrypy.root.exposingnew = ExposingNewStyle() 93 cherrypy.root.dir1 = Dir1() 94 cherrypy.root.dir1.dir2 = Dir2() 95 cherrypy.root.dir1.dir2.dir3 = Dir3() 96 cherrypy.root.dir1.dir2.dir3.dir4 = Dir4() 90 Root.exposing = Exposing() 91 Root.exposingnew = ExposingNewStyle() 92 Root.dir1 = Dir1() 93 Root.dir1.dir2 = Dir2() 94 Root.dir1.dir2.dir3 = Dir3() 95 Root.dir1.dir2.dir3.dir4 = Dir4() 96 97 mount_points = ["/", "/users/fred/blog", "/corp/blog"] 98 for url in mount_points: 99 cherrypy.tree.mount(Root(), url) 100 97 101 cherrypy.config.update({ 98 102 'server.log_to_screen': False, … … 101 105 102 106 107 class Isolated: 108 def index(self): 109 return "made it!" 110 index.exposed = True 111 112 cherrypy.tree.mount(Isolated(), "/isolated") 113 114 103 115 import helper 104 116 … … 106 118 107 119 def testObjectMapping(self): 108 self.getPage('/') 109 self.assertBody('world') 110 111 self.getPage("/dir1/myMethod") 112 self.assertBody("myMethod from dir1, object Path is:'/dir1/myMethod'") 113 114 self.getPage("/this/method/does/not/exist") 115 self.assertBody("default:('this', 'method', 'does', 'not', 'exist')") 116 117 self.getPage("/extra/too/much") 118 self.assertBody("('too', 'much')") 119 120 self.getPage("/other") 121 self.assertBody('other') 122 123 self.getPage("/notExposed") 124 self.assertBody("default:('notExposed',)") 125 126 self.getPage("/dir1/dir2/") 127 self.assertBody('index for dir2, path is:%s/dir1/dir2/' % helper.vroot) 128 129 self.getPage("/dir1/dir2") 130 self.assert_(self.status in ('302 Found', '303 See Other')) 131 self.assertHeader('Location', 'http://%s:%s%s/dir1/dir2/' 132 % (self.HOST, self.PORT, helper.vroot)) 133 134 self.getPage("/dir1/dir2/dir3/dir4/index") 135 self.assertBody("default for dir1, param is:('dir2', 'dir3', 'dir4', 'index')") 136 137 self.getPage("/redirect") 138 self.assertStatus('302 Found') 139 self.assertHeader('Location', 'http://%s:%s%s/dir1/' 140 % (self.HOST, self.PORT, helper.vroot)) 141 142 # Test that we can use URL's which aren't all valid Python identifiers 143 # This should also test the %XX-unquoting of URL's. 144 self.getPage("/Von%20B%fclow?ID=14") 145 self.assertBody("ID is 14") 146 147 # Test that %2F in the path doesn't get unquoted too early; 148 # that is, it should not be used to separate path components. 149 # See ticket #393. 150 self.getPage("/page%2Fname") 151 self.assertBody("default:('page/name',)") 120 def run(): 121 prefix = self.mount_point 122 if prefix == "/": 123 prefix = "" 124 125 self.getPage('/') 126 self.assertBody('world') 127 128 self.getPage("/dir1/myMethod") 129 self.assertBody("myMethod from dir1, object Path is:'%s/dir1/myMethod'" 130 % prefix) 131 132 self.getPage("/this/method/does/not/exist") 133 self.assertBody("default:('this', 'method', 'does', 'not', 'exist')") 134 135 self.getPage("/extra/too/much") 136 self.assertBody("('too', 'much')") 137 138 self.getPage("/other") 139 self.assertBody('other') 140 141 self.getPage("/notExposed") 142 self.assertBody("default:('notExposed',)") 143 144 self.getPage("/dir1/dir2/") 145 self.assertBody('index for dir2, path is:%s/dir1/dir2/' 146 % prefix) 147 148 self.getPage("/dir1/dir2") 149 self.assert_(self.status in ('302 Found', '303 See Other')) 150 self.assertHeader('Location', 'http://%s:%s%s/dir1/dir2/' 151 % (self.HOST, self.PORT, prefix)) 152 153 self.getPage("/dir1/dir2/dir3/dir4/index") 154 self.assertBody("default for dir1, param is:('dir2', 'dir3', 'dir4', 'index')") 155 156 self.getPage("/redirect") 157 self.assertStatus('302 Found') 158 self.assertHeader('Location', 'http://%s:%s%s/dir1/' 159 % (self.HOST, self.PORT, prefix)) 160 161 # Test that we can use URL's which aren't all valid Python identifiers 162 # This should also test the %XX-unquoting of URL's. 163 self.getPage("/Von%20B%fclow?ID=14") 164 self.assertBody("ID is 14") 165 166 # Test that %2F in the path doesn't get unquoted too early; 167 # that is, it should not be used to separate path components. 168 # See ticket #393. 169 self.getPage("/page%2Fname") 170 self.assertBody("default:('page/name',)") 171 172 for url in mount_points: 173 self.mount_point = url 174 run() 175 176 self.mount_point = "" 177 178 # Test that the "isolated" app doesn't leak url's into the root app. 179 # If it did leak, Root.default() would answer with 180 # "default:('isolated', 'doesnt', 'exist')". 181 self.getPage("/isolated/") 182 self.assertStatus("200 OK") 183 self.assertBody("made it!") 184 self.getPage("/isolated/doesnt/exist") 185 self.assertStatus("404 Not Found") 152 186 153 187 def testPositionalParams(self): trunk/cherrypy/test/test_response_headers_filter.py
r872 r910 15 15 return "salut" 16 16 other.exposed = True 17 17 18 18 cherrypy.root = Root() 19 cherrypy.config.update({ 20 '/other': { 21 'response_headers_filter.on': True, 22 'response_headers_filter.headers': [("Content-Language", "fr"), 23 ('Content-Type', 'text/plain')] 24 }, 25 }) 26 19 27 20 28 import helper … … 28 36 29 37 def testResponseHeadersFilter(self): 30 cherrypy.config.update({'/other': {31 'response_headers_filter.on': True,32 'response_headers_filter.headers': [("Content-Language", "fr"),33 ('Content-Type', 'text/plain')]34 }})35 38 self.getPage('/other') 36 39 self.assertHeader("Content-Language", "fr")

