Fixing a schema validation bug related to specialized RestController routing.

https://github.com/pecan/pecan/issues/13
This commit is contained in:
Ryan Petrello
2011-08-21 01:56:31 -04:00
parent 0311e0b5a2
commit bfb45e033a
3 changed files with 68 additions and 2 deletions

View File

@@ -153,6 +153,7 @@ class ValidationException(ForwardRequestException):
if cfg.get('htmlfill') is not None:
request.environ['pecan.htmlfill'] = cfg['htmlfill']
request.environ['REQUEST_METHOD'] = 'GET'
request.environ['pecan.validation_redirected'] = True
ForwardRequestException.__init__(self, location)

View File

@@ -19,12 +19,20 @@ class RestController(object):
def _route(self, args):
# convention uses "_method" to handle browser-unsupported methods
method = request.params.get('_method', request.method).lower()
if request.environ.get('pecan.validation_redirected', False) == True:
#
# If the request has been internally redirected due to a validation
# exception, we want the request method to be enforced as GET, not
# the `_method` param which may have been passed for REST support.
#
method = request.method.lower()
else:
method = request.params.get('_method', request.method).lower()
# make sure DELETE/PUT requests don't use GET
if request.method == 'GET' and method in ('delete', 'put'):
abort(405)
# check for nested controllers
result = self._find_sub_controllers(args)
if result:

View File

@@ -6,6 +6,8 @@ try:
except:
from json import dumps, loads
import formencode
class TestRestController(object):
@@ -829,3 +831,58 @@ class TestRestController(object):
r = app.get('/foos/bars/bazs/final/named')
assert r.status_int == 200
assert r.body == 'NAMED'
def test_rest_with_validation_redirects(self):
"""
Fixing a bug:
When schema validation fails, pecan can use an internal redirect
(paste.recursive.ForwardRequestException) to send you to another
controller to "handle" the display of error messages. Additionally,
pecan overwrites the request method as GET.
In some circumstances, RestController's special `_method` parameter
prevents the redirected request from routing to the appropriate
`error_handler` controller.
"""
class SampleSchema(formencode.Schema):
name = formencode.validators.String()
class UserController(RestController):
@expose()
def get_one(self, id):
return "FORM VALIDATION FAILED"
@expose(
schema = SampleSchema(),
error_handler = lambda: request.path
)
def put(self, id):
raise AssertionError, "Schema validation should fail."
@expose(
schema = SampleSchema(),
error_handler = lambda: request.path
)
def delete(self, id):
raise AssertionError, "Schema validation should fail."
class RootController(object):
users = UserController()
# create the app
app = TestApp(make_app(RootController()))
# create the app
app = TestApp(make_app(RootController()))
# test proper internal redirection
r = app.post('/users/1?_method=put')
assert r.status_int == 200
assert r.body == "FORM VALIDATION FAILED"
r = app.post('/users/1?_method=delete')
assert r.status_int == 200
assert r.body == "FORM VALIDATION FAILED"