diff --git a/lib/galaxy/tools/actions/upload_common.py b/lib/galaxy/tools/actions/upload_common.py index 3af3b64eaee..ab0f76b38ca 100644 --- a/lib/galaxy/tools/actions/upload_common.py +++ b/lib/galaxy/tools/actions/upload_common.py @@ -28,7 +28,7 @@ def persist_uploads( params ): local_filename = local_filename ) elif type( f ) == dict and 'filename' and 'local_filename' not in f: raise Exception( 'Uploaded file was encoded in a way not understood by Galaxy.' ) - if upload_dataset['url_paste'].strip() != '': + if upload_dataset['url_paste'] and upload_dataset['url_paste'].strip() != '': upload_dataset['url_paste'], is_multi_byte = datatypes.sniff.stream_to_file( StringIO.StringIO( upload_dataset['url_paste'] ), prefix="strio_url_paste_" ) else: upload_dataset['url_paste'] = None diff --git a/lib/galaxy/web/framework/__init__.py b/lib/galaxy/web/framework/__init__.py index 3cb0a147343..1cdbb85e0d3 100644 --- a/lib/galaxy/web/framework/__init__.py +++ b/lib/galaxy/web/framework/__init__.py @@ -5,6 +5,7 @@ Galaxy web application framework import pkg_resources import os, sys, time, socket, random, string +import inspect pkg_resources.require( "Cheetah" ) from Cheetah.Template import Template import base @@ -125,9 +126,27 @@ def expose_api( func ): 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 + 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) + 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( simplejson.loads( trans.request.body ) ) + return payload + try: + kwargs['payload'] = extract_payload_from_request(trans, func, kwargs) except ValueError: error_status = '400 Bad Request' error_message = 'Your request did not appear to be valid JSON, please consult the API documentation'