def __extract_payload_from_request(trans, func, kwargs): content_type = trans.request.headers['content-type'] if content_type.startswith('application/x-www-form-urlencoded') or content_type.startswith('multipart/form-data'): # If the content type is a standard type such as multipart/form-data, the wsgi framework parses the request body # and loads all field values into kwargs. However, kwargs also contains formal method parameters etc. which # are not a part of the request body. This is a problem because it's not possible to differentiate between values # which are a part of the request body, and therefore should be a part of the payload, and values which should not be # in the payload. Therefore, the decorated method's formal arguments are discovered through reflection and removed from # the payload dictionary. This helps to prevent duplicate argument conflicts in downstream methods. payload = kwargs.copy() named_args, _, _, _ = inspect.getargspec(func) for arg in named_args: payload.pop(arg, None) for k, v in payload.iteritems(): if isinstance(v, (str, unicode)): try: payload[k] = loads(v) except: # may not actually be json, just continue pass payload = util.recursively_stringify_dictionary_keys( payload ) else: # Assume application/json content type and parse request body manually, since wsgi won't do it. However, the order of this check # should ideally be in reverse, with the if clause being a check for application/json and the else clause assuming a standard encoding # such as multipart/form-data. Leaving it as is for backward compatibility, just in case. payload = util.recursively_stringify_dictionary_keys( loads( trans.request.body ) ) return payload
def __extract_payload_from_request(trans, func, kwargs): content_type = trans.request.headers['content-type'] if content_type.startswith( 'application/x-www-form-urlencoded') or content_type.startswith( 'multipart/form-data'): # If the content type is a standard type such as multipart/form-data, the wsgi framework parses the request body # and loads all field values into kwargs. However, kwargs also contains formal method parameters etc. which # are not a part of the request body. This is a problem because it's not possible to differentiate between values # which are a part of the request body, and therefore should be a part of the payload, and values which should not be # in the payload. Therefore, the decorated method's formal arguments are discovered through reflection and removed from # the payload dictionary. This helps to prevent duplicate argument conflicts in downstream methods. payload = kwargs.copy() named_args, _, _, _ = inspect.getargspec(func) for arg in named_args: payload.pop(arg, None) for k, v in payload.iteritems(): if isinstance(v, (str, unicode)): try: payload[k] = loads(v) except: # may not actually be json, just continue pass payload = util.recursively_stringify_dictionary_keys(payload) else: # Assume application/json content type and parse request body manually, since wsgi won't do it. However, the order of this check # should ideally be in reverse, with the if clause being a check for application/json and the else clause assuming a standard encoding # such as multipart/form-data. Leaving it as is for backward compatibility, just in case. payload = util.recursively_stringify_dictionary_keys( loads(trans.request.body)) return payload
def decorator( self, trans, *args, **kwargs ): def error( environ, start_response ): start_response( error_status, [('Content-type', 'text/plain')] ) return error_message error_status = '403 Forbidden' ## If there is a user, we've authenticated a session. if not trans.user and isinstance(trans.galaxy_session, Bunch): # If trans.user is already set, don't check for a key. # This happens when we're authenticating using session instead of an API key. # The Bunch clause is used to prevent the case where there's no user, but there is a real session. # DBTODO: This needs to be fixed when merging transaction types. if 'key' not in kwargs: error_message = 'No API key provided with request, please consult the API documentation.' return error try: provided_key = trans.sa_session.query( trans.app.model.APIKeys ).filter( trans.app.model.APIKeys.table.c.key == kwargs['key'] ).one() except NoResultFound: error_message = 'Provided API key is not valid.' return error if provided_key.user.deleted: error_message = 'User account is deactivated, please contact an administrator.' return error newest_key = provided_key.user.api_keys[0] if newest_key.key != provided_key.key: error_message = 'Provided API key has expired.' return error trans.set_user( provided_key.user ) if trans.request.body: try: payload = util.recursively_stringify_dictionary_keys( simplejson.loads( trans.request.body ) ) kwargs['payload'] = payload except ValueError: error_status = '400 Bad Request' error_message = 'Your request did not appear to be valid JSON, please consult the API documentation' return error trans.response.set_content_type( "application/json" ) # Perform api_run_as processing, possibly changing identity if 'run_as' in kwargs: if not trans.user_can_do_run_as(): error_message = 'User does not have permissions to run jobs as another user' return error try: decoded_user_id = trans.security.decode_id( kwargs['run_as'] ) except TypeError: trans.response.status = 400 return "Malformed user id ( %s ) specified, unable to decode." % str( kwargs['run_as'] ) try: user = trans.sa_session.query( trans.app.model.User ).get( decoded_user_id ) trans.api_inherit_admin = trans.user_is_admin() trans.set_user(user) except: trans.response.status = 400 return "That user does not exist." try: if trans.debug: return simplejson.dumps( func( self, trans, *args, **kwargs ), indent=4, sort_keys=True ) else: return simplejson.dumps( func( self, trans, *args, **kwargs ) ) except paste.httpexceptions.HTTPException: raise # handled except: log.exception( 'Uncaught exception in exposed API method:' ) raise paste.httpexceptions.HTTPServerError()