Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 910

Show
Ignore:
Timestamp:
01/02/06 18:06:45
Author:
fumanchu
Message:

Fix for #145. See the ticket for details about this fix.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/__init__.py

    r887 r910  
    99from _cperror import * 
    1010import config 
     11 
     12import _cptree 
     13tree = _cptree.Tree() 
     14 
     15# Legacy code may clobber this. 
     16root = None 
     17 
    1118import _cpserver 
    1219server = _cpserver.Server() 
  • trunk/cherrypy/_cphttptools.py

    r904 r910  
    275275        names = [name for name, candidate in objectTrail] 
    276276         
    277         # Try successive objects 
     277        # Try successive objects (reverse order) 
     278        mounted_app_roots = cherrypy.tree.mount_points.values() 
    278279        for i in xrange(len(objectTrail) - 1, -1, -1): 
    279280             
     
    300301                        raise cherrypy.HTTPRedirect(newUrl) 
    301302                return candidate, names[:i+1], names[i+1:-1] 
     303             
     304            if candidate in mounted_app_roots: 
     305                break 
    302306         
    303307        # We didn't find anything 
  • trunk/cherrypy/_cputil.py

    r901 r910  
    6262    # First, we look in the right-most object to see if this special 
    6363    # 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() 
    6767    objectList = get_object_trail() 
    6868    objectList.reverse() 
     
    7272        elif hasattr(obj, name): 
    7373            return getattr(obj, name) 
     74        if obj in mounted_app_roots: 
     75            break 
    7476     
    7577    try: 
  • trunk/cherrypy/config.py

    r892 r910  
    66import cherrypy 
    77from cherrypy import _cputil 
    8 from cherrypy.lib import autoreload, cptools 
     8from cherrypy.lib import autoreload, cptools, httptools 
    99 
    1010 
     
    5656    } 
    5757 
    58 def update(updateMap=None, file=None, overwrite=True): 
     58def update(updateMap=None, file=None, overwrite=True, baseurl=""): 
    5959    """Update configs from a dictionary or a config file. 
    6060     
     
    7979            section = 'global' 
    8080         
     81        if baseurl and section.startswith("/"): 
     82            if section == "/": 
     83                section = baseurl 
     84            else: 
     85                section = httptools.urljoin(baseurl, section) 
     86         
    8187        bucket = configs.setdefault(section, {}) 
    8288        if overwrite: 
     
    142148        # Move one node up the tree and try again. 
    143149        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"). 
    144154            path = "global" 
    145155        else: 
  • trunk/cherrypy/lib/httptools.py

    r899 r910  
    2121import urllib 
    2222from urlparse import urlparse 
     23 
     24 
     25def urljoin(*atoms): 
     26    url = "/".join(atoms) 
     27    while "//" in url: 
     28        url = url.replace("//", "/") 
     29    return url 
    2330 
    2431 
  • trunk/cherrypy/test/helper.py

    r893 r910  
    3030import cherrypy 
    3131from cherrypy import _cpwsgi 
     32from cherrypy.lib import httptools 
    3233import webtest 
    3334 
     
    4344    if not handled: 
    4445        cherrypy._cputil._cp_on_error() 
    45  
    46  
    47 class VirtualRootFilter: 
    48      
    49     def __init__(self, prefix): 
    50         self.prefix = prefix 
    51      
    52     def on_start_resource(self): 
    53         path = cherrypy.request.object_path 
    54         if path.startswith(self.prefix): 
    55             cherrypy.request.object_path = path[len(self.prefix):] 
    56 vroot = "" 
    57 ##vroot = "/vpath" 
    58 test_vrf = VirtualRootFilter(vroot) 
    5946 
    6047 
     
    8572 
    8673class CPWebCase(webtest.WebCase): 
     74     
     75    mount_point = "" 
     76     
     77    def prefix(self): 
     78        return self.mount_point.rstrip("/") 
    8779     
    8880    def exit(self): 
     
    147139        cherrypy.root._cpOnError = onerror 
    148140         
    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) 
    157143         
    158144        if cherrypy.server.httpserver is None: 
     
    220206        # Must run each module in a separate suite, 
    221207        # because each module uses/overwrites cherrypy globals. 
     208        cherrypy.root = None 
    222209        cherrypy.config.reset() 
    223210        setConfig(conf) 
  • trunk/cherrypy/test/test_baseurl_filter.py

    r856 r910  
    2525        self.getPage("/") 
    2626        self.assertHeader('Location', 
    27                           "http://www.mydomain.com%s/dummy" % helper.vroot
     27                          "http://www.mydomain.com%s/dummy" % self.prefix()
    2828 
    2929 
  • trunk/cherrypy/test/test_config.py

    r856 r910  
    55import StringIO 
    66import cherrypy 
     7 
    78 
    89class Root: 
     
    2627    prod = index 
    2728 
    28 cherrypy.root = Root() 
     29 
     30cherrypy.tree.mount(Root()) 
    2931cherrypy.root.foo = Foo() 
    30 cherrypy.root.env = Env() 
     32 
    3133cherrypy.config.update({ 
    3234    'global': {'server.log_to_screen': False, 
     
    4648        'bax': 'this4', 
    4749        }, 
    48     '/env': {'server.environment': 'development'}, 
    49     '/env/prod': {'server.environment': 'production'}, 
    5050}) 
     51 
     52_env_conf = {'/': {'server.environment': 'development'}, 
     53             '/prod': {'server.environment': 'production'}, 
     54             } 
     55cherrypy.tree.mount(Env(), "/env", _env_conf) 
    5156 
    5257# Shortcut syntax--should get put in the "global" bucket 
     
    6974            ('/foo/bar', 'baz', 'that2'), 
    7075            ('/foo/nex', 'baz', 'that2'), 
     76            # If 'foo' == 'this', then the mount point '/env' leaks into '/'. 
     77            ('/env/prod','foo', 'None'), 
    7178        ] 
    7279        for path, key, expected in tests: 
     
    8592            self.getPage("/env/?key=" + key) 
    8693            # 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)) 
    8896        for key, val in cherrypy.config.environments['production'].iteritems(): 
    8997            self.getPage("/env/prod/?key=" + key) 
  • trunk/cherrypy/test/test_core.py

    r894 r910  
    447447        if haslength: 
    448448            self.assert_(data[0].endswith('] "GET %s/flatten/as_string HTTP/1.1" 200 7\n' 
    449                                           % helper.vroot)) 
     449                                          % self.prefix())) 
    450450        else: 
    451451            self.assert_(data[0].endswith('] "GET %s/flatten/as_string HTTP/1.1" 200 -\n' 
    452                                           % helper.vroot)) 
     452                                          % self.prefix())) 
    453453         
    454454        self.assertEqual(data[1][:15], '127.0.0.1 - - [') 
     
    459459        if haslength: 
    460460            self.assert_(data[1].endswith('] "GET %s/flatten/as_yield HTTP/1.1" 200 7\n' 
    461                                           % helper.vroot)) 
     461                                          % self.prefix())) 
    462462        else: 
    463463            self.assert_(data[1].endswith('] "GET %s/flatten/as_yield HTTP/1.1" 200 -\n' 
    464                                           % helper.vroot)) 
     464                                          % self.prefix())) 
    465465         
    466466        data = open(log_file, "rb").readlines() 
     
    501501        self.assertInBody("<a href='http://127.0.0.1:%s%s/redirect/?id=3'>" 
    502502                          "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()
    506506            # Corner case: the "trailing slash" redirect could be tricky if 
    507507            # we're using a virtual root and the URI is "/vroot" (no slash). 
     
    510510            self.assertInBody("<a href='http://127.0.0.1:%s%s/'>" 
    511511                              "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())) 
    513513         
    514514        self.getPage("/redirect/by_code?code=300") 
     
    872872        if httpcls: 
    873873            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}}) 
    875875            self.getPage('/maxrequestsize/upload', h, "POST", b) 
    876876            self.assertStatus("413 Request Entity Too Large") 
  • trunk/cherrypy/test/test_logdebuginfo_filter.py

    r856 r910  
    4747""" 
    4848            cherrypy.config.update({ 
    49                 ('%s/bug326' % helper.vroot): { 
     49                ('%s/bug326' % self.prefix): { 
    5050                    'server.max_request_body_size': 3, 
    5151                    'server.environment': 'development', 
  • trunk/cherrypy/test/test_objectmapping.py

    r886 r910  
    8888        return "index for dir4, not exposed" 
    8989 
    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() 
     90Root.exposing = Exposing() 
     91Root.exposingnew = ExposingNewStyle() 
     92Root.dir1 = Dir1() 
     93Root.dir1.dir2 = Dir2() 
     94Root.dir1.dir2.dir3 = Dir3() 
     95Root.dir1.dir2.dir3.dir4 = Dir4() 
     96 
     97mount_points = ["/", "/users/fred/blog", "/corp/blog"] 
     98for url in mount_points: 
     99    cherrypy.tree.mount(Root(), url) 
     100 
    97101cherrypy.config.update({ 
    98102        'server.log_to_screen': False, 
     
    101105 
    102106 
     107class Isolated: 
     108    def index(self): 
     109        return "made it!" 
     110    index.exposed = True 
     111 
     112cherrypy.tree.mount(Isolated(), "/isolated") 
     113 
     114 
    103115import helper 
    104116 
     
    106118     
    107119    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") 
    152186     
    153187    def testPositionalParams(self): 
  • trunk/cherrypy/test/test_response_headers_filter.py

    r872 r910  
    1515        return "salut" 
    1616    other.exposed = True 
    17      
     17 
    1818cherrypy.root = Root() 
     19cherrypy.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 
    1927 
    2028import helper 
     
    2836 
    2937    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         }}) 
    3538        self.getPage('/other') 
    3639        self.assertHeader("Content-Language", "fr") 

Hosted by WebFaction

Log in as guest/cpguest to create tickets