Fixing a schema validation bug related to specialized RestController routing.
https://github.com/pecan/pecan/issues/13
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user