Permalink
Browse files

Move HTML escaping into Message functions; fixes #99.

  • Loading branch information...
1 parent abe31be commit c5c1f715a3ac58e98ea47b8fc15befbfbf8fa01e @mnot committed Feb 3, 2012
Showing with 92 additions and 125 deletions.
  1. +4 −5 redbot/fetch.py
  2. +30 −30 redbot/formatter/html.py
  3. +2 −3 redbot/headers/README.md
  4. +10 −11 redbot/headers/__init__.py
  5. +0 −1 redbot/headers/accept_ranges.py
  6. +0 −1 redbot/headers/age.py
  7. +0 −1 redbot/headers/allow.py
  8. +0 −1 redbot/headers/cache_control.py
  9. +0 −1 redbot/headers/content_base.py
  10. +1 −2 redbot/headers/content_disposition.py
  11. +1 −2 redbot/headers/content_encoding.py
  12. +0 −1 redbot/headers/content_length.py
  13. +0 −1 redbot/headers/content_md5.py
  14. +0 −1 redbot/headers/content_range.py
  15. +0 −1 redbot/headers/content_transfer_encoding.py
  16. +0 −1 redbot/headers/content_type.py
  17. +0 −1 redbot/headers/date.py
  18. +0 −1 redbot/headers/etag.py
  19. +0 −1 redbot/headers/expires.py
  20. +0 −1 redbot/headers/keep_alive.py
  21. +0 −1 redbot/headers/last_modified.py
  22. +3 −4 redbot/headers/link.py
  23. +1 −2 redbot/headers/location.py
  24. +0 −1 redbot/headers/mime_version.py
  25. +0 −1 redbot/headers/p3p.py
  26. +0 −1 redbot/headers/pragma.py
  27. +0 −1 redbot/headers/retry_after.py
  28. +0 −1 redbot/headers/server.py
  29. +4 −3 redbot/headers/set_cookie.py
  30. +0 −1 redbot/headers/set_cookie2.py
  31. +0 −1 redbot/headers/soapaction.py
  32. +0 −1 redbot/headers/tcn.py
  33. +1 −2 redbot/headers/transfer_encoding.py
  34. +0 −1 redbot/headers/vary.py
  35. +1 −2 redbot/headers/via.py
  36. +0 −1 redbot/headers/warning.py
  37. +0 −1 redbot/headers/x_cache.py
  38. +0 −1 redbot/headers/x_content_type_options.py
  39. +0 −1 redbot/headers/x_download_options.py
  40. +0 −1 redbot/headers/x_frame_options.py
  41. +0 −1 redbot/headers/x_meta_mssmarttagspreventparsing.py
  42. +0 −1 redbot/headers/x_pingback.py
  43. +1 −5 redbot/headers/x_ua_compatible.py
  44. +0 −1 redbot/headers/x_xrds_location.py
  45. +0 −1 redbot/headers/x_xss_protection.py
  46. +23 −2 redbot/speak.py
  47. +0 −2 redbot/status_check.py
  48. +2 −3 redbot/subrequest/conneg.py
  49. +2 −3 redbot/subrequest/etag_validate.py
  50. +1 −2 redbot/subrequest/lm_validate.py
  51. +5 −8 redbot/subrequest/range.py
  52. +0 −1 unicorn/unicorn_ui.py
View
@@ -37,7 +37,6 @@
import base64
import hashlib
import zlib
-from cgi import escape as e
import thor
import thor.http.error as httperr
@@ -203,7 +202,7 @@ def _response_body(self, chunk):
except IOError, gzip_error:
state.set_message('header-content-encoding',
rs.BAD_GZIP,
- gzip_error=e(str(gzip_error))
+ gzip_error=str(gzip_error)
)
self._gzip_ok = False
return
@@ -213,9 +212,9 @@ def _response_body(self, chunk):
state.set_message(
'header-content-encoding',
rs.BAD_ZLIB,
- zlib_error=e(str(zlib_error)),
+ zlib_error=str(zlib_error),
ok_zlib_len=f_num(state.res_body_sample[-1][0]),
- chunk_sample=e(chunk[:20].encode('string_escape'))
+ chunk_sample=chunk[:20].encode('string_escape')
)
self._gzip_ok = False
return
@@ -276,7 +275,7 @@ def _response_error(self, error):
elif isinstance(error, httperr.ChunkError):
err_msg = error.detail[:20] or ""
state.set_message('header-transfer-encoding', rs.BAD_CHUNK,
- chunk_sample=e(err_msg.encode('string_escape'))
+ chunk_sample=err_msg.encode('string_escape')
)
self.done()
self.finish_task()
View
@@ -35,7 +35,7 @@
import textwrap
import urllib
-from cgi import escape as e
+from cgi import escape as e_html
from functools import partial
from urlparse import urljoin
@@ -84,7 +84,7 @@ def start_output(self):
self.output(html_header.__doc__ % {
'static': static_root,
'version': droid.__version__,
- 'html_uri': e(self.uri),
+ 'html_uri': e_html(self.uri),
'js_uri': e_js(self.uri),
'config': urllib.quote(json.dumps({
'redbot_uri': self.uri,
@@ -118,7 +118,7 @@ def status(self, message):
window.status="%s";
-->
</script>
- """ % (thor.time() - self.start, e(message)))
+ """ % (thor.time() - self.start, e_html(message)))
def final_status(self):
# self.status("RED made %(reqs)s requests in %(elapse)2.3f seconds." % {
@@ -324,14 +324,14 @@ def finish_output(self):
elif isinstance(self.red.res_error, httperr.MalformedCLError):
self.output(self.error_template % \
"%s (<code>%s</code>)" % (
- self.red.res_error.desc, e(self.red.res_error.detail)
+ self.red.res_error.desc, e_html(self.red.res_error.detail)
))
elif isinstance(self.red.res_error, httperr.ReadTimeoutError):
self.output(self.error_template % self.red.res_error.desc)
elif isinstance(self.red.res_error, httperr.HttpVersionError):
self.output(self.error_template % \
"<code>%s</code> isn't HTTP." % \
- e(self.red.res_error.detail or '')[:20])
+ e_html(self.red.res_error.detail or '')[:20])
else:
raise AssertionError, \
"Unknown incomplete response error %s" % self.red.res_error
@@ -347,9 +347,9 @@ def format_response(self, red):
return \
u" <span class='status'>HTTP/%s %s %s</span>\n" % (
- e(str(red.res_version)),
- e(str(red.res_status)),
- e(red.res_phrase)
+ e_html(str(red.res_version)),
+ e_html(str(red.res_status)),
+ e_html(red.res_phrase)
) + \
nl.join(headers)
@@ -366,8 +366,8 @@ def format_header(self, name, value, offset):
return u"""\
<span data-offset='%s' data-name='%s' class='hdr'>%s:%s</span>""" % (
offset,
- e(name.lower()),
- e(name),
+ e_html(name.lower()),
+ e_html(name),
self.header_presenter.Show(name, value)
)
@@ -379,7 +379,7 @@ def format_body_sample(self, red):
uni_sample = unicode(red.body_sample, red.res_body_enc, 'ignore')
except LookupError:
uni_sample = unicode(red.body_sample, 'utf-8', 'ignore')
- safe_sample = e(uni_sample)
+ safe_sample = e_html(uni_sample)
message = ""
for tag, link_set in red.links.items():
for link in link_set:
@@ -392,7 +392,7 @@ def link_to(matchobj):
return r"%s<a href='%s' class='nocode'>%s</a>%s" % (
matchobj.group(1),
u"?uri=%s" % e_query_arg(qlink),
- e(link),
+ e_html(link),
matchobj.group(1)
)
safe_sample = re.sub(r"(['\"])%s\1" % \
@@ -422,13 +422,13 @@ def format_category(self, category, red):
</li>"""
% (
m.level,
- e(m.subject),
+ e_html(m.subject),
id(m),
- e(m.summary[self.lang] % m.vars)
+ m.show_summary(self.lang)
)
)
self.hidden_text.append(
- ("msgid-%s" % id(m), m.text[self.lang] % m.vars)
+ ("msgid-%s" % id(m), m.show_text(self.lang))
)
subreq = red.subreqs.get(m.subrequest, None)
smsgs = [msg for msg in getattr(subreq, "messages", []) if \
@@ -441,13 +441,13 @@ def format_category(self, category, red):
<span>%s</span>
</li>""" % (
sm.level,
- e(sm.subject),
+ e_html(sm.subject),
id(sm),
- e(sm.summary[self.lang] % sm.vars)
+ sm.show_summary(self.lang)
)
)
self.hidden_text.append(
- ("msgid-%s" % id(sm), sm.text[self.lang] % sm.vars)
+ ("msgid-%s" % id(sm), sm.show_text(self.lang))
)
out.append(u"</ul>")
out.append(u"</ul>\n")
@@ -537,7 +537,7 @@ def Show(self, name, value):
if name_token[0] != "_" and hasattr(self, name_token):
return getattr(self, name_token)(name, value)
else:
- return self.I(e(value), len(name))
+ return self.I(e_html(value), len(name))
def BARE_URI(self, name, value):
"Present a bare URI header value"
@@ -547,7 +547,7 @@ def BARE_URI(self, name, value):
return u"%s<a href='?uri=%s'>%s</a>" % (
" " * space,
e_query_arg(urljoin(self.URI, svalue)),
- self.I(e(svalue), len(name))
+ self.I(e_html(svalue), len(name))
)
content_location = \
location = \
@@ -642,21 +642,21 @@ def format_droid(self, red):
</a>
</td>""" % (
u"?%s" % self.req_qs(red.uri),
- e(red.uri),
+ e_html(red.uri),
cl,
- e(red.uri[:m-2]),
- e(red.uri[m-2]),
- e(red.uri[m-1]),
- e(red.uri[m]),
+ e_html(red.uri[:m-2]),
+ e_html(red.uri[m-2]),
+ e_html(red.uri[m-1]),
+ e_html(red.uri[m]),
)
)
else:
out.append(
u'<td class="uri"><a href="%s" title="%s"%s>%s</a></td>' % (
u"?%s" % self.req_qs(red.uri),
- e(red.uri),
+ e_html(red.uri),
cl,
- e(red.uri)
+ e_html(red.uri)
)
)
if red.res_complete:
@@ -701,7 +701,7 @@ def format_droid(self, red):
for p in pr_enum:
m = self.problems[p]
out.append("<span class='prob_num'> %s <span class='hidden'>%s</span></span>" % (
- p + 1, e(m.summary[self.lang] % m.vars)
+ p + 1, e_html(m.show_summary(self.lang))
)
)
else:
@@ -780,9 +780,9 @@ def format_problems(self):
out.append(u"""\
<li class='%s %s msg' name='msgid-%s'><span>%s</span></li>""" % (
m.level,
- e(m.subject),
+ e_html(m.subject),
id(m),
- e(m.summary[self.lang] % m.vars)
+ e_html(m.summary[self.lang] % m.vars)
)
)
self.hidden_text.append(
View
@@ -127,9 +127,8 @@ passed to _parse_.
examples.
When writing new messages, it's important to keep in mind that the `text`
-field is expected to contain valid HTML, with appropriate escaping; if you
-allow arbitrary text from the user to pass into it without escaping, it
-can present a security risk.
+field is expected to contain valid HTML; any variables you pass to it will
+be escaped for you before rendering.
### Writing Tests
View
@@ -46,7 +46,6 @@
"""
import calendar
-from cgi import escape as e
from email.utils import parsedate as lib_parsedate
import locale
import re
@@ -295,40 +294,40 @@ def parse_params(red, subject, instr, nostar=None, delim=";"):
continue
k_norm = k.lower() # TODO: warn on upper-case in param?
if param_dict.has_key(k_norm):
- red.set_message(subject, rs.PARAM_REPEATS, param=e(k_norm))
+ red.set_message(subject, rs.PARAM_REPEATS, param=k_norm)
if v[0] == v[-1] == "'":
red.set_message(subject,
rs.PARAM_SINGLE_QUOTED,
- param=e(k_norm),
- param_val=e(v),
- param_val_unquoted=e(v[1:-1])
+ param=k_norm,
+ param_val=v,
+ param_val_unquoted=v[1:-1]
)
if k[-1] == '*':
if nostar is True or (nostar and k_norm[:-1] in nostar):
red.set_message(subject, rs.PARAM_STAR_BAD,
- param=e(k_norm[:-1]))
+ param=k_norm[:-1])
else:
if v[0] == '"' and v[-1] == '"':
red.set_message(subject, rs.PARAM_STAR_QUOTED,
- param=e(k_norm))
+ param=k_norm)
v = unquote_string(v)
try:
enc, lang, esc_v = v.split("'", 3)
except ValueError:
red.set_message(subject, rs.PARAM_STAR_ERROR,
- param=e(k_norm))
+ param=k_norm)
continue
enc = enc.lower()
lang = lang.lower()
if enc == '':
red.set_message(subject,
- rs.PARAM_STAR_NOCHARSET, param=e(k_norm))
+ rs.PARAM_STAR_NOCHARSET, param=k_norm)
continue
elif enc not in ['utf-8']:
red.set_message(subject,
rs.PARAM_STAR_CHARSET,
- param=e(k_norm),
- enc=e(enc)
+ param=k_norm,
+ enc=enc
)
continue
# TODO: catch unquoting errors, range of chars, charset
@@ -23,7 +23,6 @@
THE SOFTWARE.
"""
-from cgi import escape as e
import redbot.speak as rs
import redbot.headers as rh
View
@@ -23,7 +23,6 @@
THE SOFTWARE.
"""
-from cgi import escape as e
import redbot.speak as rs
import redbot.headers as rh
View
@@ -23,7 +23,6 @@
THE SOFTWARE.
"""
-from cgi import escape as e
import redbot.speak as rs
import redbot.headers as rh
@@ -23,7 +23,6 @@
THE SOFTWARE.
"""
-from cgi import escape as e
import redbot.speak as rs
import redbot.headers as rh
@@ -23,7 +23,6 @@
THE SOFTWARE.
"""
-from cgi import escape as e
import redbot.speak as rs
import redbot.headers as rh
@@ -23,7 +23,6 @@
THE SOFTWARE.
"""
-from cgi import escape as e
import redbot.speak as rs
import redbot.headers as rh
@@ -45,7 +44,7 @@ def parse(subject, value, red):
if disposition not in ['inline', 'attachment']:
red.set_message(subject,
rs.DISPOSITION_UNKNOWN,
- disposition=e(disposition)
+ disposition=disposition
)
if not param_dict.has_key('filename'):
red.set_message(subject, rs.DISPOSITION_OMITS_FILENAME)
@@ -23,7 +23,6 @@
THE SOFTWARE.
"""
-from cgi import escape as e
import redbot.speak as rs
import redbot.headers as rh
@@ -38,7 +37,7 @@ def parse(subject, value, red):
if value.lower() != 'gzip':
red.set_message(subject,
rs.ENCODING_UNWANTED,
- unwanted_codings=e(value)
+ unwanted_codings=value
)
return value.lower()
@@ -23,7 +23,6 @@
THE SOFTWARE.
"""
-from cgi import escape as e
import redbot.speak as rs
import redbot.headers as rh
@@ -23,7 +23,6 @@
THE SOFTWARE.
"""
-from cgi import escape as e
import redbot.speak as rs
import redbot.headers as rh
@@ -23,7 +23,6 @@
THE SOFTWARE.
"""
-from cgi import escape as e
import redbot.speak as rs
import redbot.headers as rh
Oops, something went wrong.

0 comments on commit c5c1f71

Please sign in to comment.