1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/47e32138de3d/ Changeset: 47e32138de3d User: greg Date: 2014-06-10 16:33:48 Summary: Fixes for the Tool Shed API POST and PUT requests that were broken when attempting to handle urllib2 not handling 307 redirects. The initial attempt at handling the urllib2 weakness made a call to urllib2.get_url() which turns POST requests into GET requests as a side-effect. Affected #: 3 files diff -r 0ed41ad6e8b803867947c4d28daef882cf411773 -r 47e32138de3d0a9debf25cb6b59c967b647af84e lib/galaxy/webapps/tool_shed/api/repositories.py --- a/lib/galaxy/webapps/tool_shed/api/repositories.py +++ b/lib/galaxy/webapps/tool_shed/api/repositories.py @@ -30,7 +30,7 @@ @web.expose_api def add_repository_registry_entry( self, trans, payload, **kwd ): """ - POST /api/repository_revisions/add_repository_registry_entry + POST /api/repositories/add_repository_registry_entry Adds appropriate entries to the repository registry for the repository defined by the received name and owner. :param key: the user's API key @@ -65,7 +65,7 @@ # Update the repository registry. trans.app.repository_registry.add_entry( repository ) response_dict[ 'status' ] = 'ok' - response_dict[ 'message' ] = 'Entries for repository %s owned by %s have been added to the Tool Shed repository registry..' \ + response_dict[ 'message' ] = 'Entries for repository %s owned by %s have been added to the Tool Shed repository registry.' \ % ( name, owner ) return response_dict @@ -315,7 +315,7 @@ @web.expose_api def remove_repository_registry_entry( self, trans, payload, **kwd ): """ - POST /api/repository_revisions/add_repository_registry_entry + POST /api/repositories/remove_repository_registry_entry Removes appropriate entries from the repository registry for the repository defined by the received name and owner. :param key: the user's API key diff -r 0ed41ad6e8b803867947c4d28daef882cf411773 -r 47e32138de3d0a9debf25cb6b59c967b647af84e lib/tool_shed/scripts/api/common.py --- a/lib/tool_shed/scripts/api/common.py +++ b/lib/tool_shed/scripts/api/common.py @@ -11,31 +11,43 @@ from tool_shed.util import common_util from tool_shed.util import hg_util +def build_request_with_data( url, data, api_key, method ): + """Build a request with the received method.""" + protocol = common_util.get_protocol_from_tool_shed_url( url ) + if protocol == 'http': + opener = urllib2.build_opener( urllib2.HTTPHandler ) + elif protocol == 'https': + opener = urllib2.build_opener( urllib2.HTTPSHandler ) + url = make_url( url, api_key=api_key, args=None ) + request = urllib2.Request( url, headers={ 'Content-Type': 'application/json' }, data=json.dumps( data ) ) + request_method = request.get_method() + if request_method != method: + request.get_method = lambda: method + return opener, request + def delete( api_key, url, data, return_formatted=True ): """ Sends an API DELETE request and acts as a generic formatter for the JSON response. The 'data' will become the JSON payload read by the Tool Shed. """ try: - url = make_url( url, api_key=api_key, args=None ) - # Fix for handling 307 redirect not being handled nicely by urllib2.urlopen when the - # urllib2.Request has data provided. - url = urllib2.urlopen( urllib2.Request( url ) ).geturl() - req = urllib2.Request( url, headers = { 'Content-Type': 'application/json' }, data = json.dumps( data )) - req.get_method = lambda: 'DELETE' - r = json.loads( urllib2.urlopen( req ).read() ) + opener, request = build_request_with_data( url, data, api_key, 'DELETE' ) + delete_request = opener.open( request ) + response = json.loads( delete_request.read() ) except urllib2.HTTPError, e: if return_formatted: print e print e.read( 1024 ) sys.exit( 1 ) else: - return 'Error. '+ str( e.read( 1024 ) ) - if not return_formatted: - return r - print 'Response' - print '--------' - print r + return dict( status='error', message=str( e.read( 1024 ) ) ) + if return_formatted: + return response + print 'Response' + print '--------' + print response + else: + return response def display( url, api_key=None, return_formatted=True ): """Sends an API GET request and acts as a generic formatter for the JSON response.""" @@ -176,25 +188,21 @@ def post( url, data, api_key=None ): """Do the POST.""" - url = make_url( url, api_key=api_key, args=None ) - # Fix for handling 307 redirect not being handled nicely by urllib2.urlopen when the - # urllib2.Request has data provided. - # NOTE: This approach does *not* work -- this makes an extra GET request to the - # base collection with the method as the ID. That will never decode - # correctly. - # url = urllib2.urlopen( urllib2.Request( url ) ).geturl() - req = urllib2.Request( url, headers = { 'Content-Type': 'application/json' }, data = json.dumps( data ) ) - return json.loads( urllib2.urlopen( req ).read() ) + try: + opener, request = build_request_with_data( url, data, api_key, 'POST' ) + post_request = opener.open( request ) + return json.loads( post_request.read() ) + except urllib2.HTTPError, e: + return dict( status='error', message=str( e.read( 1024 ) ) ) def put( url, data, api_key=None ): """Do the PUT.""" - url = make_url( url, api_key=api_key, args=None ) - # Fix for handling 307 redirect not being handled nicely by urllib2.urlopen when the - # urllib2.Request has data provided. - url = urllib2.urlopen( urllib2.Request( url ) ).geturl() - req = urllib2.Request( url, headers = { 'Content-Type': 'application/json' }, data = json.dumps( data )) - req.get_method = lambda: 'PUT' - return json.loads( urllib2.urlopen( req ).read() ) + try: + opener, request = build_request_with_data( url, data, api_key, 'PUT' ) + put_request = opener.open( request ) + return json.loads( put_request.read() ) + except urllib2.HTTPError, e: + return dict( status='error', message=str( e.read( 1024 ) ) ) def submit( url, data, api_key=None, return_formatted=True ): """ @@ -202,7 +210,7 @@ 'data' will become the JSON payload read by the Tool Shed. """ try: - r = post( url, data, api_key=api_key ) + response = post( url, data, api_key=api_key ) except urllib2.HTTPError, e: if return_formatted: print e @@ -211,13 +219,13 @@ else: return dict( status='error', message=str( e.read( 1024 ) ) ) if not return_formatted: - return r + return response print 'Response' print '--------' - if type( r ) == list: + if type( response ) == list: # Currently the only implemented responses are lists of dicts, because submission creates # some number of collection elements. - for i in r: + for i in response: if type( i ) == dict: if 'url' in i: print i.pop( 'url' ) @@ -230,7 +238,7 @@ else: print i else: - print r + print response def update( api_key, url, data, return_formatted=True ): """ @@ -238,16 +246,17 @@ 'data' will become the JSON payload read by the Tool Shed. """ try: - r = put( url, data, api_key=api_key ) + response = put( url, data, api_key=api_key ) except urllib2.HTTPError, e: if return_formatted: print e print e.read( 1024 ) sys.exit( 1 ) else: - return 'Error. ' + str( e.read( 1024 ) ) - if not return_formatted: - return r - print 'Response' - print '--------' - print r + return dict( status='error', message=str( e.read( 1024 ) ) ) + if return_formatted: + print 'Response' + print '--------' + print response + else: + return response diff -r 0ed41ad6e8b803867947c4d28daef882cf411773 -r 47e32138de3d0a9debf25cb6b59c967b647af84e lib/tool_shed/util/common_util.py --- a/lib/tool_shed/util/common_util.py +++ b/lib/tool_shed/util/common_util.py @@ -160,6 +160,19 @@ repository_dependencies_dict = encoding_util.tool_shed_decode( encoded_text ) return tool_shed_accessible, repository_dependencies_dict +def get_protocol_from_tool_shed_url( tool_shed_url ): + """Return the protocol from the received tool_shed_url if it exists.""" + try: + if tool_shed_url.find( '://' ) > 0: + return tool_shed_url.split( '://' )[0].lower() + except Exception, e: + # We receive a lot of calls here where the tool_shed_url is None. The container_util uses + # that value when creating a header row. If the tool_shed_url is not None, we have a problem. + if tool_shed_url is not None: + log.exception( "Handled exception getting the protocol from Tool Shed URL %s:\n%s" % ( str( tool_shed_url ), str( e ) ) ) + # Default to HTTP protocol. + return 'http' + def get_tool_dependencies( app, tool_shed_url, repository_name, repository_owner, changeset_revision ): tool_dependencies = [] tool_shed_accessible = True Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.