[utils] add a ``js_href`` function to generated proper javascript href
authorPierre-Yves David <pierre-yves.david@logilab.fr>
Tue, 18 Oct 2011 12:25:32 +0200
changeset 7998 9ef285eb20f4
parent 7997 e6eb86233e6f
child 7999 ea012d90825d
[utils] add a ``js_href`` function to generated proper javascript href The main gain is the escaping of % * * * [pagination] use js_href for building javascript link (closes #2035033) This prevent snicky error with url unquoting of javascript code
utils.py
web/component.py
--- a/utils.py	Fri Oct 21 14:32:37 2011 +0200
+++ b/utils.py	Tue Oct 18 12:25:32 2011 +0200
@@ -25,6 +25,8 @@
 import decimal
 import datetime
 import random
+import re
+
 from operator import itemgetter
 from inspect import getargspec
 from itertools import repeat
@@ -540,6 +542,29 @@
             return something
         return json_dumps(something)
 
+PERCENT_IN_URLQUOTE_RE = re.compile(r'%(?=[0-9a-fA-F]{2})')
+def js_href(javascript_code):
+    """Generate a "javascript: ..." string for an href attribute.
+
+    Some % which may be interpreted in a href context will be escaped.
+
+    In an href attribute, url-quotes-looking fragments are interpreted before
+    being given to the javascript engine. Valid url quotes are in the form
+    ``%xx`` with xx being a byte in hexadecimal form. This means that ``%toto``
+    will be unaltered but ``%babar`` will be mangled because ``ba`` is the
+    hexadecimal representation of 186.
+
+    >>> js_href('alert("babar");')
+    'javascript: alert("babar");'
+    >>> js_href('alert("%babar");')
+    'javascript: alert("%25babar");'
+    >>> js_href('alert("%toto %babar");')
+    'javascript: alert("%toto %25babar");'
+    >>> js_href('alert("%1337%");')
+    'javascript: alert("%251337%");'
+    """
+    return 'javascript: ' + PERCENT_IN_URLQUOTE_RE.sub(r'%25', javascript_code)
+
 
 @deprecated('[3.7] merge_dicts is deprecated')
 def merge_dicts(dict1, dict2):
--- a/web/component.py	Fri Oct 21 14:32:37 2011 +0200
+++ b/web/component.py	Tue Oct 18 12:25:32 2011 +0200
@@ -30,7 +30,7 @@
 from cubicweb import Unauthorized, role, target, tags
 from cubicweb.schema import display_name
 from cubicweb.uilib import js, domid
-from cubicweb.utils import json_dumps
+from cubicweb.utils import json_dumps, js_href
 from cubicweb.view import ReloadableMixIn, Component
 from cubicweb.selectors import (no_cnx, paginated_rset, one_line_rset,
                                 non_final_entity, partial_relation_possible,
@@ -120,8 +120,8 @@
     def ajax_page_url(self, **params):
         divid = params.setdefault('divid', 'pageContent')
         params['rql'] = self.cw_rset.printable_rql()
-        return "javascript: $(%s).loadxhtml('json', %s, 'get', 'swap')" % (
-            json_dumps('#'+divid), js.ajaxFuncArgs('view', params))
+        return js_href("$(%s).loadxhtml('json', %s, 'get', 'swap')" % (
+            json_dumps('#'+divid), js.ajaxFuncArgs('view', params)))
 
     def page_link(self, path, params, start, stop, content):
         url = xml_escape(self.page_url(path, params, start, stop))