From 50c6ce4301a9c39a2aa3779ceb339004294c0b88 Mon Sep 17 00:00:00 2001 From: Renzo Frigato Date: Wed, 24 Feb 2016 16:10:37 -0800 Subject: [PATCH 1/2] stop using handler.abort in validators raise exceptions instead (catched by base.RequestHandler.handle_exception) --- api/handlers/containerhandler.py | 4 ++-- api/handlers/grouphandler.py | 8 ++++---- api/handlers/listhandler.py | 6 +++--- api/handlers/userhandler.py | 8 ++++---- api/upload.py | 4 ++-- api/validators.py | 16 +++++++--------- 6 files changed, 22 insertions(+), 24 deletions(-) diff --git a/api/handlers/containerhandler.py b/api/handlers/containerhandler.py index ab35e96e0..2a156383f 100644 --- a/api/handlers/containerhandler.py +++ b/api/handlers/containerhandler.py @@ -308,8 +308,8 @@ def get_groups_with_project(self): def _get_validators(self): - mongo_validator = validators.mongo_from_schema_file(self, self.config.get('storage_schema_file')) - payload_validator = validators.payload_from_schema_file(self, self.config.get('payload_schema_file')) + mongo_validator = validators.mongo_from_schema_file(self.config.get('storage_schema_file')) + payload_validator = validators.payload_from_schema_file(self.config.get('payload_schema_file')) return mongo_validator, payload_validator def _get_parent_container(self, payload): diff --git a/api/handlers/grouphandler.py b/api/handlers/grouphandler.py index e1bcde0aa..db62be4e2 100644 --- a/api/handlers/grouphandler.py +++ b/api/handlers/grouphandler.py @@ -58,8 +58,8 @@ def put(self, _id): self.abort(404, 'no such Group: ' + _id) permchecker = groupauth.default(self, group) payload = self.request.json_body - mongo_validator = validators.mongo_from_schema_file(self, 'group.json') - payload_validator = validators.payload_from_schema_file(self, 'group.json') + mongo_validator = validators.mongo_from_schema_file('group.json') + payload_validator = validators.payload_from_schema_file('group.json') payload_validator(payload, 'PUT') result = mongo_validator(permchecker(self.storage.exec_op))('PUT', _id=_id, payload=payload) if result.modified_count == 1: @@ -71,8 +71,8 @@ def post(self): self._init_storage() permchecker = groupauth.default(self, None) payload = self.request.json_body - mongo_validator = validators.mongo_from_schema_file(self, 'group.json') - payload_validator = validators.payload_from_schema_file(self, 'group.json') + mongo_validator = validators.mongo_from_schema_file('group.json') + payload_validator = validators.payload_from_schema_file('group.json') payload_validator(payload, 'POST') payload['created'] = payload['modified'] = datetime.datetime.utcnow() payload['roles'] = [{'_id': self.uid, 'access': 'admin', 'site': self.user_site}] diff --git a/api/handlers/listhandler.py b/api/handlers/listhandler.py index 7abc40ae2..ff9c9a538 100644 --- a/api/handlers/listhandler.py +++ b/api/handlers/listhandler.py @@ -181,9 +181,9 @@ def _initialize_request(self, cont_name, list_name, _id, query_params=None): permchecker = permchecker(self, container) else: self.abort(404, 'Element {} not found in container {}'.format(_id, storage.cont_name)) - mongo_validator = validators.mongo_from_schema_file(self, config.get('storage_schema_file')) - input_validator = validators.payload_from_schema_file(self, config.get('input_schema_file')) - keycheck = validators.key_check(self, config.get('storage_schema_file')) + mongo_validator = validators.mongo_from_schema_file(config.get('storage_schema_file')) + input_validator = validators.payload_from_schema_file(config.get('input_schema_file')) + keycheck = validators.key_check(config.get('storage_schema_file')) return container, permchecker, storage, mongo_validator, input_validator, keycheck diff --git a/api/handlers/userhandler.py b/api/handlers/userhandler.py index 608087f7c..42b6e65e6 100644 --- a/api/handlers/userhandler.py +++ b/api/handlers/userhandler.py @@ -64,8 +64,8 @@ def put(self, _id): user = self._get_user(_id) permchecker = userauth.default(self, user) payload = self.request.json_body - mongo_validator = validators.mongo_from_schema_file(self, 'user.json') - payload_validator = validators.payload_from_schema_file(self, 'user.json') + mongo_validator = validators.mongo_from_schema_file('user.json') + payload_validator = validators.payload_from_schema_file('user.json') payload_validator(payload, 'PUT') payload['modified'] = datetime.datetime.utcnow() result = mongo_validator(permchecker(self.storage.exec_op))('PUT', _id=_id, payload=payload) @@ -78,8 +78,8 @@ def post(self): self._init_storage() permchecker = userauth.default(self) payload = self.request.json_body - mongo_validator = validators.mongo_from_schema_file(self, 'user.json') - payload_validator = validators.payload_from_schema_file(self, 'user.json') + mongo_validator = validators.mongo_from_schema_file('user.json') + payload_validator = validators.payload_from_schema_file('user.json') payload_validator(payload, 'POST') payload['created'] = payload['modified'] = datetime.datetime.utcnow() payload['root'] = payload.get('root', False) diff --git a/api/upload.py b/api/upload.py index 3ec641dfb..a72d2a312 100644 --- a/api/upload.py +++ b/api/upload.py @@ -62,7 +62,7 @@ def uploader(self): self.abort(400, str(e)) if not file_store.metadata: self.abort(400, 'metadata is missing') - metadata_validator = validators.payload_from_schema_file(self, 'uploader.json') + metadata_validator = validators.payload_from_schema_file('uploader.json') metadata_validator(file_store.metadata, 'POST') try: target_containers = reaperutil.create_root_to_leaf_hierarchy(file_store.metadata, file_store.files) @@ -108,7 +108,7 @@ def engine(self): self.abort(400, str(e)) if not file_store.metadata: self.abort(400, 'metadata is missing') - metadata_validator = validators.payload_from_schema_file(self, 'enginemetadata.json') + metadata_validator = validators.payload_from_schema_file('enginemetadata.json') metadata_validator(file_store.metadata, 'POST') file_infos = file_store.metadata['acquisition'].pop('files', []) now = datetime.datetime.utcnow() diff --git a/api/validators.py b/api/validators.py index d31b0e587..15a4f787f 100644 --- a/api/validators.py +++ b/api/validators.py @@ -1,5 +1,6 @@ import os import copy +import webapp2 import jsonschema from . import config @@ -69,7 +70,7 @@ def _validate_json(json_data, schema, resolver): def no_op(g, *args): return g -def mongo_from_schema_file(handler, schema_file): +def mongo_from_schema_file(schema_file): if schema_file is None: return no_op schema = resolver_mongo.resolve(schema_file)[1] @@ -83,15 +84,12 @@ def mongo_val(method, **kwargs): else: _schema = schema if method in ['POST', 'PUT']: - try: - _validate_json(payload, _schema, resolver_mongo) - except jsonschema.ValidationError as e: - handler.abort(500, str(e)) + _validate_json(payload, _schema, resolver_mongo) return exec_op(method, **kwargs) return mongo_val return g -def payload_from_schema_file(handler, schema_file): +def payload_from_schema_file(schema_file): if schema_file is None: return no_op schema = resolver_input.resolve(schema_file)[1] @@ -105,10 +103,10 @@ def g(payload, method): try: _validate_json(payload, _schema, resolver_input) except jsonschema.ValidationError as e: - handler.abort(400, str(e)) + raise webapp2.exc.HTTPBadRequest(str(e)) return g -def key_check(handler, schema_file): +def key_check(schema_file): """ for sublists of mongo container there is no automatic key check when creating, updating or deleting an object. We are adding a custom array field to the json schemas ("key_fields"). @@ -135,7 +133,7 @@ def f(method, _id, query_params = None, payload = None, exclude_params=None): try: exclude_params = _post_exclude_params(schema.get('key_fields', []), payload) except KeyError as e: - handler.abort(400, 'missing key {} in payload'.format(e.args)) + raise webapp2.exc.HTTPBadRequest('missing key {} in payload'.format(e.args)) else: _check_query_params(schema.get('key_fields'), query_params) if method == 'PUT' and schema.get('key_fields'): From ea97a704944192a84acbe8f2ce5ee884ef526a34 Mon Sep 17 00:00:00 2001 From: Renzo Frigato Date: Thu, 25 Feb 2016 11:19:43 -0800 Subject: [PATCH 2/2] remove webapp2 dependency in validators --- api/base.py | 3 +++ api/validators.py | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/api/base.py b/api/base.py index 36056990c..a3e385ca0 100644 --- a/api/base.py +++ b/api/base.py @@ -9,6 +9,7 @@ from . import util from . import config +from . import validators log = config.log @@ -128,6 +129,8 @@ def handle_exception(self, exception, debug): # Otherwise use a generic 500 error code. if isinstance(exception, webapp2.HTTPException): code = exception.code + elif isinstance(exception, validators.InputValidationException): + code = 400 else: code = 500 util.send_json_http_exception(self.response, str(exception), code) diff --git a/api/validators.py b/api/validators.py index 15a4f787f..ede73c5a0 100644 --- a/api/validators.py +++ b/api/validators.py @@ -1,12 +1,17 @@ import os import copy -import webapp2 import jsonschema from . import config log = config.log +class InputValidationException(Exception): + pass + +class DBValidationException(Exception): + pass + # following https://github.com/Julian/jsonschema/issues/98 # json schema files are expected to be in the schemas folder relative to this module schema_path = os.path.abspath(os.path.dirname(__file__)) @@ -84,7 +89,10 @@ def mongo_val(method, **kwargs): else: _schema = schema if method in ['POST', 'PUT']: - _validate_json(payload, _schema, resolver_mongo) + try: + _validate_json(payload, _schema, resolver_mongo) + except jsonschema.ValidationError as e: + raise DBValidationException(str(e)) return exec_op(method, **kwargs) return mongo_val return g @@ -103,7 +111,7 @@ def g(payload, method): try: _validate_json(payload, _schema, resolver_input) except jsonschema.ValidationError as e: - raise webapp2.exc.HTTPBadRequest(str(e)) + raise InputValidationException(str(e)) return g def key_check(schema_file): @@ -133,7 +141,7 @@ def f(method, _id, query_params = None, payload = None, exclude_params=None): try: exclude_params = _post_exclude_params(schema.get('key_fields', []), payload) except KeyError as e: - raise webapp2.exc.HTTPBadRequest('missing key {} in payload'.format(e.args)) + raise InputValidationException('missing key {} in payload'.format(e.args)) else: _check_query_params(schema.get('key_fields'), query_params) if method == 'PUT' and schema.get('key_fields'):