# Path: zoe_api/custom_request_handler.py
# class ZoeRequestHandler(tornado.web.RequestHandler):
#     """Customized request handler."""
# 
#     def initialize(self, **kwargs):
#         """Initializes the request handler."""
#         super().initialize()
#         self.api_endpoint = kwargs['api_endpoint']  # type: APIEndpoint
# 
#     def get_current_user(self):
#         """Get the user making the request from one of several possible locations."""
#         auth_header = self.request.headers.get('Authorization')
#         if self.get_secure_cookie('zoe'):  # cookie auth
#             username = tornado.escape.xhtml_escape(self.get_secure_cookie('zoe'))
#             user = self.api_endpoint.user_by_name(username)
#         elif auth_header is not None and auth_header.startswith('Basic '):  # basic auth
#             auth_decoded = base64.decodebytes(bytes(auth_header[6:], 'ascii')).decode('utf-8')
#             username, password = auth_decoded.split(':', 2)
#             user = BaseAuthenticator().full_auth(username, password)
#         else:
#             user = None
# 
#         if user is None:
#             raise ZoeAuthException('Invalid username or password')
#         if not user.enabled:
#             raise ZoeAuthException('User has been disabled by the administrator')
# 
#         return user
# 
#     def on_finish(self):
#         """Log request."""
#         try:
#             user = ZoeRequestHandler.get_current_user(self)
#         except ZoeAuthException:
#             user = "not authenticated"
#         log.info("{} {} {} ({}, {}) {:.2f}ms".format(self.get_status(), self.request.method, self.request.path, self.request.remote_ip, user, self.request.request_time()))
# 
#     def data_received(self, chunk):
#         """Not implemented as we do not use stream uploads"""
# 
# Path: zoe_api/exceptions.py
# class ZoeAuthException(ZoeException):
#     """An authentication error."""
#     def __init__(self, message=None):
#         super().__init__()
#         if message is None:
#             self.message = 'Unauthorized'
#         else:
#             self.message = message
#         self.status_code = 401


import json
import datetime
import logging
import zoe_lib.config
import zoe_lib.version
from jinja2 import Environment, FileSystemLoader, Markup, TemplateSyntaxError
from tornado.escape import squeeze, linkify, url_escape, xhtml_escape
from zoe_api.custom_request_handler import ZoeRequestHandler
from zoe_api.exceptions import ZoeAuthException
            'cache_size': 50 if app_settings.get('compiled_template_cache', True) else 0,
            'autoescape': app_settings.get('autoescape', 'xhtml_escape') == "xhtml_escape"
        }

        _jinja_config.update(**(jinja_options or {}))
        environment = Environment(**_jinja_config)

        application.jinja_environment = environment
        app_settings['jinja_environment'] = environment
        environment.filters.update(tojson=tojson_filter, xhtml_escape=xhtml_escape, url_escape=url_escape, squeeze=squeeze, linkify=linkify)

        return environment


def dumps(obj, **kwargs):
    """Escape characters."""
    # https://github.com/mitsuhiko/flask/blob/master/flask/json.py
    return json.dumps(obj, **kwargs) \
        .replace(u'<', u'\\u003c') \
        .replace(u'>', u'\\u003e') \
        .replace(u'&', u'\\u0026') \
        .replace(u"'", u'\\u0027')


def tojson_filter(obj, **kwargs):
    """Filter for JSON output in templates."""
    # https://github.com/mitsuhiko/flask/blob/master/flask/json.py
    return Markup(dumps(obj, **kwargs))



# Path: zoe_api/custom_request_handler.py
# class ZoeRequestHandler(tornado.web.RequestHandler):
#     """Customized request handler."""
# 
#     def initialize(self, **kwargs):
#         """Initializes the request handler."""
#         super().initialize()
#         self.api_endpoint = kwargs['api_endpoint']  # type: APIEndpoint
# 
#     def get_current_user(self):
#         """Get the user making the request from one of several possible locations."""
#         auth_header = self.request.headers.get('Authorization')
#         if self.get_secure_cookie('zoe'):  # cookie auth
#             username = tornado.escape.xhtml_escape(self.get_secure_cookie('zoe'))
#             user = self.api_endpoint.user_by_name(username)
#         elif auth_header is not None and auth_header.startswith('Basic '):  # basic auth
#             auth_decoded = base64.decodebytes(bytes(auth_header[6:], 'ascii')).decode('utf-8')
#             username, password = auth_decoded.split(':', 2)
#             user = BaseAuthenticator().full_auth(username, password)
#         else:
#             user = None
# 
#         if user is None:
#             raise ZoeAuthException('Invalid username or password')
#         if not user.enabled:
#             raise ZoeAuthException('User has been disabled by the administrator')
# 
#         return user
# 
#     def on_finish(self):
#         """Log request."""
#         try:
#             user = ZoeRequestHandler.get_current_user(self)
#         except ZoeAuthException:
#             user = "not authenticated"
#         log.info("{} {} {} ({}, {}) {:.2f}ms".format(self.get_status(), self.request.method, self.request.path, self.request.remote_ip, user, self.request.request_time()))
# 
#     def data_received(self, chunk):
#         """Not implemented as we do not use stream uploads"""
# 
# Path: zoe_api/exceptions.py
# class ZoeAuthException(ZoeException):
#     """An authentication error."""
#     def __init__(self, message=None):
#         super().__init__()
#         if message is None:
#             self.message = 'Unauthorized'
#         else:
#             self.message = message
#         self.status_code = 401


# Path: zoe_api/web/request_handler.py
import json
import datetime
import logging
import zoe_lib.config
import zoe_lib.version
from jinja2 import Environment, FileSystemLoader, Markup, TemplateSyntaxError
from tornado.escape import squeeze, linkify, url_escape, xhtml_escape
from zoe_api.custom_request_handler import ZoeRequestHandler
from zoe_api.exceptions import ZoeAuthException

            'cache_size': 50 if app_settings.get('compiled_template_cache', True) else 0,
            'autoescape': app_settings.get('autoescape', 'xhtml_escape') == "xhtml_escape"
        }

        _jinja_config.update(**(jinja_options or {}))
        environment = Environment(**_jinja_config)

        application.jinja_environment = environment
        app_settings['jinja_environment'] = environment
        environment.filters.update(tojson=tojson_filter, xhtml_escape=xhtml_escape, url_escape=url_escape, squeeze=squeeze, linkify=linkify)

        return environment


def dumps(obj, **kwargs):
    """Escape characters."""
    # https://github.com/mitsuhiko/flask/blob/master/flask/json.py
    return json.dumps(obj, **kwargs) \
        .replace(u'<', u'\\u003c') \
        .replace(u'>', u'\\u003e') \
        .replace(u'&', u'\\u0026') \
        .replace(u"'", u'\\u0027')


def tojson_filter(obj, **kwargs):
    """Filter for JSON output in templates."""
    # https://github.com/mitsuhiko/flask/blob/master/flask/json.py
    return Markup(dumps(obj, **kwargs))



class ZoeWebRequestHandler(ZoeRequestHandler):