Skip to content

Commit

Permalink
[#3002] Only allow JSONP callback on the action API for GET requests
Browse files Browse the repository at this point in the history
Updated the tests from the legacy ones.
  • Loading branch information
amercader committed May 9, 2016
1 parent 595b2d5 commit 44a6783
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 19 deletions.
6 changes: 3 additions & 3 deletions ckan/controllers/api.py
Expand Up @@ -89,9 +89,9 @@ def _finish(self, status_int, response_data=None,
else:
response_msg = response_data
# Support "JSONP" callback.
if status_int == 200 and 'callback' in request.params and \
(request.method == 'GET' or
c.logic_function and request.method == 'POST'):
if (status_int == 200 and
'callback' in request.params and
request.method == 'GET'):
# escape callback to remove '<', '&', '>' chars
callback = cgi.escape(request.params['callback'])
response_msg = self._wrap_jsonp(callback, response_msg)
Expand Down
50 changes: 50 additions & 0 deletions ckan/tests/controllers/test_api.py
Expand Up @@ -3,6 +3,7 @@
controller itself.
'''
import json
import re

from routes import url_for
from nose.tools import assert_equal
Expand All @@ -13,6 +14,9 @@
from ckan import model


eq_ = assert_equal


class TestApiController(helpers.FunctionalTestBase):

def test_unicode_in_error_message_works_ok(self):
Expand Down Expand Up @@ -201,6 +205,52 @@ def test_config_option_list_access_sysadmin_jsonp(self):
status=403,
)

def test_jsonp_works_on_get_requests(self):

dataset1 = factories.Dataset()
dataset2 = factories.Dataset()

url = url_for(
controller='api',
action='action',
logic_function='package_list',
ver='/3')
app = self._get_test_app()
res = app.get(
url=url,
params={'callback': 'my_callback'},
)
assert re.match('my_callback\(.*\);', res.body), res
# Unwrap JSONP callback (we want to look at the data).
msg = res.body[len('my_callback')+1:-2]
res_dict = json.loads(msg)
eq_(res_dict['success'], True)
eq_(sorted(res_dict['result']),
sorted([dataset1['name'], dataset2['name']]))

def test_jsonp_does_not_work_on_post_requests(self):

dataset1 = factories.Dataset()
dataset2 = factories.Dataset()

url = url_for(
controller='api',
action='action',
logic_function='package_list',
ver='/3',
callback='my_callback',
)
app = self._get_test_app()
res = app.post(
url=url,
)
# The callback param is ignored and the normal response is returned
assert not res.body.startswith('my_callback')
res_dict = json.loads(res.body)
eq_(res_dict['success'], True)
eq_(sorted(res_dict['result']),
sorted([dataset1['name'], dataset2['name']]))


class TestRevisionSearch(helpers.FunctionalTestBase):

Expand Down
16 changes: 0 additions & 16 deletions ckan/tests/legacy/logic/test_action.py
Expand Up @@ -114,22 +114,6 @@ def test_01_package_list_private(self):
assert 'public_dataset' in res
assert not 'private_dataset' in res

def test_01_package_show_with_jsonp(self):
anna_id = model.Package.by_name(u'annakarenina').id
postparams = '%s=1' % json.dumps({'id': anna_id})
res = self.app.post('/api/action/package_show?callback=jsoncallback', params=postparams)

assert re.match('jsoncallback\(.*\);', res.body), res
# Unwrap JSONP callback (we want to look at the data).
msg = res.body[len('jsoncallback')+1:-2]
res_dict = json.loads(msg)
assert_equal(res_dict['success'], True)
assert "/api/3/action/help_show?name=package_show" in res_dict['help']
pkg = res_dict['result']
assert_equal(pkg['name'], 'annakarenina')
missing_keys = set(('title', 'groups')) - set(pkg.keys())
assert not missing_keys, missing_keys

def test_02_package_autocomplete_match_name(self):
postparams = '%s=1' % json.dumps({'q':'war', 'limit': 5})
res = self.app.post('/api/action/package_autocomplete', params=postparams)
Expand Down

0 comments on commit 44a6783

Please sign in to comment.