From cb24646948a8c00c5b39f0d76bf75e153ac502b1 Mon Sep 17 00:00:00 2001 From: Christoph Heer Date: Tue, 17 Jan 2012 21:09:59 +0100 Subject: [PATCH 1/4] Add jsonp support inside of jsonify --- flask/helpers.py | 21 +++++++++++++++++++++ flask/testsuite/helpers.py | 14 ++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/flask/helpers.py b/flask/helpers.py index 25250d26..ebe5fca5 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -117,9 +117,30 @@ def jsonify(*args, **kwargs): information about this, have a look at :ref:`json-security`. .. versionadded:: 0.2 + + .. versionadded:: 0.9 + If the argument ``padded`` true than the json object will pad for + JSONP calls like from jquery. The response mimetype will also change + to ``text/javascript``. + + The json object will pad as javascript function with the function name + from the request argument ``callback`` or ``jsonp``. If the argument + ``padded`` a string jsonify will look for the function name in the + request argument with the name which is equal to ``padded``. Is there + no function name it will fallback and use ``jsonp`` as function name. """ if __debug__: _assert_have_json() + if 'padded' in kwargs: + if isinstance(kwargs['padded'], str): + callback = request.args.get(kwargs['padded']) or 'jsonp' + else: + callback = request.args.get('callback') or \ + request.args.get('jsonp') or 'jsonp' + del kwargs['padded'] + json_str = json.dumps(dict(*args, **kwargs), indent=None) + content = str(callback) + "(" + json_str + ")" + return current_app.response_class(content, mimetype='text/javascript') return current_app.response_class(json.dumps(dict(*args, **kwargs), indent=None if request.is_xhr else 2), mimetype='application/json') diff --git a/flask/testsuite/helpers.py b/flask/testsuite/helpers.py index 89c6c188..44ac9016 100644 --- a/flask/testsuite/helpers.py +++ b/flask/testsuite/helpers.py @@ -61,11 +61,25 @@ class JSONTestCase(FlaskTestCase): @app.route('/dict') def return_dict(): return flask.jsonify(d) + @app.route("/padded") + def return_padded_json(): + return flask.jsonify(d, padded=True) + @app.route("/padded_custom") + def return_padded_json_custom_callback(): + return flask.jsonify(d, padded='my_func_name') c = app.test_client() for url in '/kw', '/dict': rv = c.get(url) self.assert_equal(rv.mimetype, 'application/json') self.assert_equal(flask.json.loads(rv.data), d) + for get_arg in 'callback=funcName', 'jsonp=funcName': + rv = c.get('/padded?' + get_arg) + self.assert_( rv.data.startswith("funcName(") ) + self.assert_( rv.data.endswith(")") ) + rv_json = rv.data.split('(')[1].split(')')[0] + self.assert_equal(flask.json.loads(rv_json), d) + rv = c.get('/padded_custom?my_func_name=funcName') + self.assert_( rv.data.startswith("funcName(") ) def test_json_attr(self): app = flask.Flask(__name__) From 09370c3f1c808e9251292bc228b6bef4b1223e93 Mon Sep 17 00:00:00 2001 From: Ned Jackson Lovely Date: Mon, 12 Mar 2012 15:26:05 -0400 Subject: [PATCH 2/4] Clean up docs and review pull request #384 Spelunking through the issues at the PyCon sprints. --- flask/helpers.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/flask/helpers.py b/flask/helpers.py index ebe5fca5..ee68ce95 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -119,15 +119,16 @@ def jsonify(*args, **kwargs): .. versionadded:: 0.2 .. versionadded:: 0.9 - If the argument ``padded`` true than the json object will pad for - JSONP calls like from jquery. The response mimetype will also change - to ``text/javascript``. + If the ``padded`` argument is true, the JSON object will be padded + for JSONP calls and the response mimetype will be changed to + ``text/javascript``. By default, the request arguments ``callback`` + and ``jsonp`` will be used as the name for the callback function. + This will work with jQuery and most other JavaScript libraries + by default. - The json object will pad as javascript function with the function name - from the request argument ``callback`` or ``jsonp``. If the argument - ``padded`` a string jsonify will look for the function name in the - request argument with the name which is equal to ``padded``. Is there - no function name it will fallback and use ``jsonp`` as function name. + If the ``padded`` argument is a string, jsonify will look for + the request argument with the same name and use that value as the + callback-function name. """ if __debug__: _assert_have_json() From 27194a01d8f7e4fd913811859ec4051ff99c52f4 Mon Sep 17 00:00:00 2001 From: Ned Jackson Lovely Date: Mon, 12 Mar 2012 16:02:53 -0400 Subject: [PATCH 3/4] Fix typo in docs. http://feedback.flask.pocoo.org/message/279 --- docs/quickstart.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 9fde0c2f..b442af28 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -169,8 +169,8 @@ The following converters exist: .. admonition:: Unique URLs / Redirection Behaviour Flask's URL rules are based on Werkzeug's routing module. The idea behind - that module is to ensure beautiful and unique also unique URLs based on - precedents laid down by Apache and earlier HTTP servers. + that module is to ensure beautiful and unique URLs based on precedents + laid down by Apache and earlier HTTP servers. Take these two rules:: From 68f93634de2e25afda209b710002e4c9159fd38e Mon Sep 17 00:00:00 2001 From: Ned Jackson Lovely Date: Mon, 12 Mar 2012 17:18:27 -0400 Subject: [PATCH 4/4] Second thoughts on mime type After further review, changing the mime type on jsonp responses from text/javascript to application/javascript, with a hat-tip to http://stackoverflow.com/questions/111302/best-content-type-to-serve-jsonp --- flask/helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flask/helpers.py b/flask/helpers.py index ee68ce95..31a0f693 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -121,7 +121,7 @@ def jsonify(*args, **kwargs): .. versionadded:: 0.9 If the ``padded`` argument is true, the JSON object will be padded for JSONP calls and the response mimetype will be changed to - ``text/javascript``. By default, the request arguments ``callback`` + ``application/javascript``. By default, the request arguments ``callback`` and ``jsonp`` will be used as the name for the callback function. This will work with jQuery and most other JavaScript libraries by default. @@ -141,7 +141,7 @@ def jsonify(*args, **kwargs): del kwargs['padded'] json_str = json.dumps(dict(*args, **kwargs), indent=None) content = str(callback) + "(" + json_str + ")" - return current_app.response_class(content, mimetype='text/javascript') + return current_app.response_class(content, mimetype='application/javascript') return current_app.response_class(json.dumps(dict(*args, **kwargs), indent=None if request.is_xhr else 2), mimetype='application/json')