Home | History | Annotate | Download | only in tests
      1 import os
      2 from paste.urlparser import *
      3 from paste.fixture import *
      4 from pkg_resources import get_distribution
      5 
      6 def relative_path(name):
      7     here = os.path.join(os.path.dirname(os.path.abspath(__file__)),
      8                         'urlparser_data')
      9     f = os.path.join('urlparser_data', '..', 'urlparser_data', name)
     10     return os.path.join(here, f)
     11 
     12 def path(name):
     13     return os.path.join(os.path.dirname(os.path.abspath(__file__)),
     14                         'urlparser_data', name)
     15 
     16 def make_app(name):
     17     app = URLParser({}, path(name), name, index_names=['index', 'Main'])
     18     testapp = TestApp(app)
     19     return testapp
     20 
     21 def test_find_file():
     22     app = make_app('find_file')
     23     res = app.get('/')
     24     assert 'index1' in res
     25     assert res.header('content-type') == 'text/plain'
     26     res = app.get('/index')
     27     assert 'index1' in res
     28     assert res.header('content-type') == 'text/plain'
     29     res = app.get('/index.txt')
     30     assert 'index1' in res
     31     assert res.header('content-type') == 'text/plain'
     32     res = app.get('/test2.html')
     33     assert 'test2' in res
     34     assert res.header('content-type') == 'text/html'
     35     res = app.get('/test 3.html')
     36     assert 'test 3' in res
     37     assert res.header('content-type') == 'text/html'
     38     res = app.get('/test%203.html')
     39     assert 'test 3' in res
     40     assert res.header('content-type') == 'text/html'
     41     res = app.get('/dir with spaces/test 4.html')
     42     assert 'test 4' in res
     43     assert res.header('content-type') == 'text/html'
     44     res = app.get('/dir%20with%20spaces/test%204.html')
     45     assert 'test 4' in res
     46     assert res.header('content-type') == 'text/html'
     47     # Ensure only data under the app's root directory is accessible
     48     res = app.get('/../secured.txt', status=404)
     49     res = app.get('/dir with spaces/../../secured.txt', status=404)
     50     res = app.get('/%2e%2e/secured.txt', status=404)
     51     res = app.get('/%2e%2e%3fsecured.txt', status=404)
     52     res = app.get('/..%3fsecured.txt', status=404)
     53     res = app.get('/dir%20with%20spaces/%2e%2e/%2e%2e/secured.txt', status=404)
     54 
     55 def test_deep():
     56     app = make_app('deep')
     57     res = app.get('/')
     58     assert 'index2' in res
     59     res = app.get('/sub')
     60     assert res.status == 301
     61     print(res)
     62     assert res.header('location') == 'http://localhost/sub/'
     63     assert 'http://localhost/sub/' in res
     64     res = app.get('/sub/')
     65     assert 'index3' in res
     66 
     67 def test_python():
     68     app = make_app('python')
     69     res = app.get('/simpleapp')
     70     assert 'test1' in res
     71     assert res.header('test-header') == 'TEST!'
     72     assert res.header('content-type') == 'text/html'
     73     res = app.get('/stream')
     74     assert 'test2' in res
     75     res = app.get('/sub/simpleapp')
     76     assert 'subsimple' in res
     77 
     78 def test_hook():
     79     app = make_app('hook')
     80     res = app.get('/bob/app')
     81     assert 'user: bob' in res
     82     res = app.get('/tim/')
     83     assert 'index: tim' in res
     84 
     85 def test_not_found_hook():
     86     app = make_app('not_found')
     87     res = app.get('/simple/notfound')
     88     assert res.status == 200
     89     assert 'not found' in res
     90     res = app.get('/simple/found')
     91     assert 'is found' in res
     92     res = app.get('/recur/__notfound', status=404)
     93     # @@: It's unfortunate that the original path doesn't actually show up
     94     assert '/recur/notfound' in res
     95     res = app.get('/recur/__isfound')
     96     assert res.status == 200
     97     assert 'is found' in res
     98     res = app.get('/user/list')
     99     assert 'user: None' in res
    100     res = app.get('/user/bob/list')
    101     assert res.status == 200
    102     assert 'user: bob' in res
    103 
    104 def test_relative_path_in_static_parser():
    105     x = relative_path('find_file')
    106     app = StaticURLParser(relative_path('find_file'))
    107     assert '..' not in app.root_directory
    108 
    109 def test_xss():
    110     app = TestApp(StaticURLParser(relative_path('find_file')),
    111                   extra_environ={'HTTP_ACCEPT': 'text/html'})
    112     res = app.get("/-->%0D<script>alert('xss')</script>", status=404)
    113     assert b'--><script>' not in res.body
    114 
    115 def test_static_parser():
    116     app = StaticURLParser(path('find_file'))
    117     testapp = TestApp(app)
    118     res = testapp.get('', status=301)
    119     res = testapp.get('/', status=404)
    120     res = testapp.get('/index.txt')
    121     assert res.body.strip() == b'index1'
    122     res = testapp.get('/index.txt/foo', status=404)
    123     res = testapp.get('/test 3.html')
    124     assert res.body.strip() == b'test 3'
    125     res = testapp.get('/test%203.html')
    126     assert res.body.strip() == b'test 3'
    127     res = testapp.get('/dir with spaces/test 4.html')
    128     assert res.body.strip() == b'test 4'
    129     res = testapp.get('/dir%20with%20spaces/test%204.html')
    130     assert res.body.strip() == b'test 4'
    131     # Ensure only data under the app's root directory is accessible
    132     res = testapp.get('/../secured.txt', status=404)
    133     res = testapp.get('/dir with spaces/../../secured.txt', status=404)
    134     res = testapp.get('/%2e%2e/secured.txt', status=404)
    135     res = testapp.get('/dir%20with%20spaces/%2e%2e/%2e%2e/secured.txt', status=404)
    136     res = testapp.get('/dir%20with%20spaces/', status=404)
    137 
    138 def test_egg_parser():
    139     app = PkgResourcesParser('Paste', 'paste')
    140     testapp = TestApp(app)
    141     res = testapp.get('', status=301)
    142     res = testapp.get('/', status=404)
    143     res = testapp.get('/flup_session', status=404)
    144     res = testapp.get('/util/classinit.py')
    145     assert 'ClassInitMeta' in res
    146     res = testapp.get('/util/classinit', status=404)
    147     res = testapp.get('/util', status=301)
    148     res = testapp.get('/util/classinit.py/foo', status=404)
    149 
    150     # Find a readable file in the Paste pkg's root directory (or upwards the
    151     # directory tree). Ensure it's not accessible via the URLParser
    152     unreachable_test_file = None
    153     search_path = pkg_root_path = get_distribution('Paste').location
    154     level = 0
    155     # We might not find any readable files in the pkg's root directory (this
    156     # is likely when Paste is installed as a .egg in site-packages). We
    157     # (hopefully) can prevent this by traversing up the directory tree until
    158     # a usable file is found
    159     while unreachable_test_file is None and \
    160             os.path.normpath(search_path) != os.path.sep:
    161         for file in os.listdir(search_path):
    162             full_path = os.path.join(search_path, file)
    163             if os.path.isfile(full_path) and os.access(full_path, os.R_OK):
    164                 unreachable_test_file = file
    165                 break
    166 
    167         search_path = os.path.dirname(search_path)
    168         level += 1
    169     assert unreachable_test_file is not None, \
    170            'test_egg_parser requires a readable file in a parent dir of the\n' \
    171            'Paste pkg\'s root dir:\n%s' % pkg_root_path
    172 
    173     unreachable_path = '/' + '../'*level + unreachable_test_file
    174     unreachable_path_quoted = '/' + '%2e%2e/'*level + unreachable_test_file
    175     res = testapp.get(unreachable_path, status=404)
    176     res = testapp.get('/util/..' + unreachable_path, status=404)
    177     res = testapp.get(unreachable_path_quoted, status=404)
    178     res = testapp.get('/util/%2e%2e' + unreachable_path_quoted, status=404)
    179