From f45c41ef3e326b933757e1681ca633d1fa7203fe Mon Sep 17 00:00:00 2001 From: Dag Wieers Date: Fri, 4 Jan 2019 00:06:13 +0100 Subject: [PATCH] urldecode filter for Jinja2 (#28503) * urldecode filter for Jinja2 We needed this in order to deconstruct correct URLs using Jinja2. And we might as well upstream this. * Add integration tests * Fixes for Python 3 * Add urlencode for older Jinja2 --- lib/ansible/plugins/filter/urls.py | 69 +++++++++++++++++++ .../targets/filters/tasks/main.yml | 13 ++++ 2 files changed, 82 insertions(+) create mode 100644 lib/ansible/plugins/filter/urls.py diff --git a/lib/ansible/plugins/filter/urls.py b/lib/ansible/plugins/filter/urls.py new file mode 100644 index 0000000000..cdd0e42dec --- /dev/null +++ b/lib/ansible/plugins/filter/urls.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +# Copyright: (c) 2012, Dag Wieers (@dagwieers) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +from ansible.module_utils.six import PY3, iteritems, string_types +from ansible.module_utils.six.moves.urllib.parse import quote, quote_plus, unquote_plus +from ansible.module_utils._text import to_bytes, to_text + +try: + from jinja2.filters import do_urlencode + HAS_URLENCODE = True +except ImportError: + HAS_URLENCODE = False + + +def unicode_urldecode(string): + if PY3: + return unquote_plus(string) + return to_text(unquote_plus(to_bytes(string))) + + +def do_urldecode(string): + return unicode_urldecode(string) + + +# NOTE: We implement urlencode when Jinja2 is older than v2.7 +def unicode_urlencode(string, for_qs=False): + safe = b'' if for_qs else b'/' + if for_qs: + quote_func = quote_plus + else: + quote_func = quote + if PY3: + return quote_func(string, safe) + return to_text(quote_func(to_bytes(string), safe)) + + +def do_urlencode(value): + itemiter = None + if isinstance(value, dict): + itemiter = iteritems(value) + elif not isinstance(value, string_types): + try: + itemiter = iter(value) + except TypeError: + pass + if itemiter is None: + return unicode_urlencode(value) + return u'&'.join(unicode_urlencode(k) + '=' + + unicode_urlencode(v, for_qs=True) + for k, v in itemiter) + + +class FilterModule(object): + ''' Ansible core jinja2 filters ''' + + def filters(self): + filters = { + 'urldecode': do_urldecode, + } + + if not HAS_URLENCODE: + filters['urlencode'] = do_urlencode + + return filters diff --git a/test/integration/targets/filters/tasks/main.yml b/test/integration/targets/filters/tasks/main.yml index 80f84ae15d..89815fe9ff 100644 --- a/test/integration/targets/filters/tasks/main.yml +++ b/test/integration/targets/filters/tasks/main.yml @@ -169,6 +169,19 @@ - _bad_urlsplit_filter is failed - "'unknown URL component' in _bad_urlsplit_filter.msg" +- name: Test urldecode filter + set_fact: + urldecoded_string: key="@{}é&%£ foo bar '(;\<>""°) + +- name: Test urlencode filter + set_fact: + urlencoded_string: '{{ urldecoded_string|urlencode }}' + +- name: Verify urlencode en urldecode + assert: + that: + - urldecoded_string == urlencoded_string|urldecode + - name: Flatten tests block: - name: use flatten