Move send_with_safety_check functionality into AsyncDjangoHandler

This will mainly be useful in the event system branch, where we want
to actually send a response from a file other than tornadoviews.py.

(imported from commit b7ae9bb9b062215ab44eb5f0a3a72d6baeee1d07)
This commit is contained in:
Zev Benjamin
2013-03-13 16:02:00 -04:00
parent 0f621f5f89
commit 22457277f4
2 changed files with 26 additions and 22 deletions

View File

@@ -324,3 +324,22 @@ class AsyncDjangoHandler(tornado.web.RequestHandler, base.BaseHandler):
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
return response
def finish(self, response=None, apply_markdown=True):
superself = super(AsyncDjangoHandler, self)
if not isinstance(response, dict):
return superself.finish(response)
# Make sure that Markdown rendering really happened, if requested.
# This is a security issue because it's where we escape HTML.
# c.f. ticket #64
#
# apply_markdown=True is the fail-safe default.
if response['result'] == 'success' and 'messages' in response and apply_markdown:
for msg in response['messages']:
if msg['content_type'] != 'text/html':
self.set_status(500)
return superself.finish('Internal error: bad message format')
if response['result'] == 'error':
self.set_status(400)
return superself.finish(response)

View File

@@ -342,22 +342,6 @@ def return_messages_immediately(user_profile, client_id, last,
return None
def send_with_safety_check(response, handler, apply_markdown=True, **kwargs):
# Make sure that Markdown rendering really happened, if requested.
# This is a security issue because it's where we escape HTML.
# c.f. ticket #64
#
# apply_markdown=True is the fail-safe default.
if response['result'] == 'success' and apply_markdown:
for msg in response['messages']:
if msg['content_type'] != 'text/html':
handler.set_status(500)
handler.finish('Internal error: bad message format')
return
if response['result'] == 'error':
handler.set_status(400)
handler.finish(response)
# Note: We allow any stream name at all here! Validation and
# authorization (is the stream "public") are handled by the caller of
# notify_new_message. If a user makes a get_updates request for a
@@ -370,19 +354,19 @@ def get_updates_backend(request, user_profile, handler, client_id,
converter=int),
client_pointer = POST(whence='pointer', converter=int, default=None),
dont_block = POST(converter=simplejson.loads, default=False),
stream_name = POST(default=None),
stream_name = POST(default=None), apply_markdown=True,
**kwargs):
resp = return_messages_immediately(user_profile, client_id, last,
client_server_generation,
client_pointer,
dont_block, stream_name, **kwargs)
dont_block, stream_name,
apply_markdown=apply_markdown, **kwargs)
if resp is not None:
send_with_safety_check(resp, handler, **kwargs)
handler.finish(resp, apply_markdown)
# We have already invoked handler.finish(), so we bypass the usual view
# response path. We are "responding asynchronously" except that it
# already happened. This is slightly weird, but lets us share
# send_with_safety_check with the code below.
# already happened. This is slightly weird.
return RespondAsynchronously
# Enter long-polling mode.
@@ -416,8 +400,9 @@ def get_updates_backend(request, user_profile, handler, client_id,
kwargs.update(cb_kwargs)
res = format_updates_response(user_profile=user_profile,
client_server_generation=client_server_generation,
apply_markdown=apply_markdown,
**kwargs)
send_with_safety_check(res, handler, **kwargs)
handler.finish(res, apply_markdown)
except socket.error:
pass