diff --git a/test/alltests.py b/test/alltests.py index d28e5e3a..cef58457 100644 --- a/test/alltests.py +++ b/test/alltests.py @@ -1,7 +1,7 @@ import webtest def suite(): - modules = ["doctests", "db"] + modules = ["doctests", "db", "application"] return webtest.suite(modules) if __name__ == "__main__": diff --git a/test/application.py b/test/application.py new file mode 100644 index 00000000..8828b75d --- /dev/null +++ b/test/application.py @@ -0,0 +1,53 @@ +import webtest +import time + +import web + +data = """ +import web + +urls = ("/", "%(classname)s") +app = web.application(urls, globals(), autoreload=True) + +class %(classname)s: + def GET(self): + return "%(output)s" + +""" + +def write(filename, data): + f = open(filename, 'w') + f.write(data) + f.close() + +class ApplicationTest(webtest.TestCase): + def test_reloader(self): + write('foo.py', data % dict(classname='a', output='a')) + import foo + app = foo.app + + self.assertEquals(app.request('/').data, 'a') + + # test class change + time.sleep(1) + write('foo.py', data % dict(classname='a', output='b')) + self.assertEquals(app.request('/').data, 'b') + + # test urls change + time.sleep(1) + write('foo.py', data % dict(classname='c', output='c')) + self.assertEquals(app.request('/').data, 'c') + + def testUppercaseMethods(self): + urls = ("/", "hello") + app = web.application(urls, locals()) + class hello: + def GET(self): return "hello" + def internal(self): return "secret" + + response = app.request('/', method='internal') + self.assertEquals(response.status, '405 Method Not Allowed') + +if __name__ == '__main__': + webtest.main() + diff --git a/web/application.py b/web/application.py index 61dbc529..8e0fde31 100644 --- a/web/application.py +++ b/web/application.py @@ -165,7 +165,12 @@ def is_generator(x): return x and hasattr(x, 'next') def wsgi(env, start_resp): self.load(env) + try: + # allow uppercase methods only + if web.ctx.method.upper() != web.ctx.method: + raise web.nomethod() + result = self.handle_with_processors() except NotFound: web.ctx.status = "404 Not Found" @@ -451,10 +456,11 @@ def __call__(self): def check(self, mod): try: mtime = os.stat(mod.__file__).st_mtime - except (AttributeError, OSError, IOError): + except (AttributeError, OSError, IOError): return if mod.__file__.endswith('.pyc') and os.path.exists(mod.__file__[:-1]): mtime = max(os.stat(mod.__file__[:-1]).st_mtime, mtime) + if mod not in self.mtimes: self.mtimes[mod] = mtime elif self.mtimes[mod] < mtime: diff --git a/web/webapi.py b/web/webapi.py index bd0349a7..584b9031 100644 --- a/web/webapi.py +++ b/web/webapi.py @@ -124,13 +124,16 @@ def __init__(self, url): class NoMethod(HTTPError): """A `405 Method Not Allowed` error.""" - def __init__(self, cls): + def __init__(self, cls=None): status = '405 Method Not Allowed' headers = {} headers['Content-Type'] = 'text/html' - headers['Allow'] = ', '.join([method for method in \ - ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'] \ - if hasattr(cls, method)]) + + methods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'] + if cls: + methods = [method for method in methods if hasattr(cls, method)] + + headers['Allow'] = ', '.join(methods) data = None HTTPError.__init__(self, status, headers, data)