from tornado.testing import AsyncHTTPTestCase, ExpectLog, gen_test
from tornado.test.util import unittest
from tornado.util import u, bytes_type, ObjectDict, unicode_type
-from tornado.web import RequestHandler, authenticated, Application, asynchronous, url, HTTPError, StaticFileHandler, _create_signature_v1, create_signed_value, decode_signed_value, ErrorHandler, UIModule, MissingArgumentError, stream_request_body
+from tornado.web import RequestHandler, authenticated, Application, asynchronous, url, HTTPError, StaticFileHandler, _create_signature_v1, create_signed_value, decode_signed_value, ErrorHandler, UIModule, MissingArgumentError, stream_request_body, Finish
import binascii
import contextlib
body=urllib_parse.urlencode(dict(_xsrf=body_token)),
headers=self.cookie_headers(cookie_token))
self.assertEqual(response.code, 200)
+
+
+@wsgi_safe
+class FinishExceptionTest(SimpleHandlerTestCase):
+ class Handler(RequestHandler):
+ def get(self):
+ self.set_status(401)
+ self.set_header('WWW-Authenticate', 'Basic realm="something"')
+ self.write('authentication required')
+ raise Finish()
+
+ def test_finish_exception(self):
+ response = self.fetch('/')
+ self.assertEqual(response.code, 401)
+ self.assertEqual('Basic realm="something"',
+ response.headers.get('WWW-Authenticate'))
+ self.assertEqual(b'authentication required', response.body)
" (" + self.request.remote_ip + ")"
def _handle_request_exception(self, e):
+ if isinstance(e, Finish):
+ # Not an error; just finish the request without logging.
+ if not self._finished:
+ self.finish()
+ return
self.log_exception(*sys.exc_info())
if self._finished:
# Extra errors after the request has been finished should
`RequestHandler.send_error` since it automatically ends the
current function.
+ To customize the response sent with an `HTTPError`, override
+ `RequestHandler.write_error`.
+
:arg int status_code: HTTP status code. Must be listed in
`httplib.responses <http.client.responses>` unless the ``reason``
keyword argument is given.
return message
+class Finish(Exception):
+ """An exception that ends the request without producing an error response.
+
+ When `Finish` is raised in a `RequestHandler`, the request will end
+ (calling `RequestHandler.finish` if it hasn't already been called),
+ but the outgoing response will not be modified and the error-handling
+ methods (including `RequestHandler.write_error`) will not be called.
+
+ This can be a more convenient way to implement custom error pages
+ than overriding ``write_error`` (especially in library code)::
+
+ if self.current_user is None:
+ self.set_status(401)
+ self.set_header('WWW-Authenticate', 'Basic realm="something"')
+ raise Finish()
+ """
+ pass
+
+
class MissingArgumentError(HTTPError):
"""Exception raised by `RequestHandler.get_argument`.