Skip to content

Commit

Permalink
Move HTML escaping into Message functions; fixes #99.
Browse files Browse the repository at this point in the history
  • Loading branch information
mnot committed Feb 3, 2012
1 parent abe31be commit c5c1f71
Show file tree
Hide file tree
Showing 52 changed files with 92 additions and 125 deletions.
9 changes: 4 additions & 5 deletions redbot/fetch.py
Expand Up @@ -37,7 +37,6 @@
import base64
import hashlib
import zlib
from cgi import escape as e

import thor
import thor.http.error as httperr
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand Down
60 changes: 30 additions & 30 deletions redbot/formatter/html.py
Expand Up @@ -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

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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." % {
Expand Down Expand Up @@ -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
Expand All @@ -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)

Expand All @@ -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)
)

Expand All @@ -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:
Expand All @@ -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" % \
Expand Down Expand Up @@ -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 \
Expand All @@ -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")
Expand Down Expand Up @@ -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"
Expand All @@ -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 = \
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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(
Expand Down
5 changes: 2 additions & 3 deletions redbot/headers/README.md
Expand Up @@ -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
Expand Down
21 changes: 10 additions & 11 deletions redbot/headers/__init__.py
Expand Up @@ -46,7 +46,6 @@
"""

import calendar
from cgi import escape as e
from email.utils import parsedate as lib_parsedate
import locale
import re
Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion redbot/headers/accept_ranges.py
Expand Up @@ -23,7 +23,6 @@
THE SOFTWARE.
"""

from cgi import escape as e

import redbot.speak as rs
import redbot.headers as rh
Expand Down
1 change: 0 additions & 1 deletion redbot/headers/age.py
Expand Up @@ -23,7 +23,6 @@
THE SOFTWARE.
"""

from cgi import escape as e

import redbot.speak as rs
import redbot.headers as rh
Expand Down
1 change: 0 additions & 1 deletion redbot/headers/allow.py
Expand Up @@ -23,7 +23,6 @@
THE SOFTWARE.
"""

from cgi import escape as e

import redbot.speak as rs
import redbot.headers as rh
Expand Down
1 change: 0 additions & 1 deletion redbot/headers/cache_control.py
Expand Up @@ -23,7 +23,6 @@
THE SOFTWARE.
"""

from cgi import escape as e

import redbot.speak as rs
import redbot.headers as rh
Expand Down
1 change: 0 additions & 1 deletion redbot/headers/content_base.py
Expand Up @@ -23,7 +23,6 @@
THE SOFTWARE.
"""

from cgi import escape as e

import redbot.speak as rs
import redbot.headers as rh
Expand Down
3 changes: 1 addition & 2 deletions redbot/headers/content_disposition.py
Expand Up @@ -23,7 +23,6 @@
THE SOFTWARE.
"""

from cgi import escape as e

import redbot.speak as rs
import redbot.headers as rh
Expand All @@ -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)
Expand Down
3 changes: 1 addition & 2 deletions redbot/headers/content_encoding.py
Expand Up @@ -23,7 +23,6 @@
THE SOFTWARE.
"""

from cgi import escape as e

import redbot.speak as rs
import redbot.headers as rh
Expand All @@ -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()

Expand Down
1 change: 0 additions & 1 deletion redbot/headers/content_length.py
Expand Up @@ -23,7 +23,6 @@
THE SOFTWARE.
"""

from cgi import escape as e

import redbot.speak as rs
import redbot.headers as rh
Expand Down
1 change: 0 additions & 1 deletion redbot/headers/content_md5.py
Expand Up @@ -23,7 +23,6 @@
THE SOFTWARE.
"""

from cgi import escape as e

import redbot.speak as rs
import redbot.headers as rh
Expand Down
1 change: 0 additions & 1 deletion redbot/headers/content_range.py
Expand Up @@ -23,7 +23,6 @@
THE SOFTWARE.
"""

from cgi import escape as e

import redbot.speak as rs
import redbot.headers as rh
Expand Down

0 comments on commit c5c1f71

Please sign in to comment.