Пример #1
0
 def tonadoapi_prepare(self):
     self.tonadoapi_field_info()
     super(ApiHandler, self).tonadoapi_prepare()
     errors = {}
     for field_name in dir(self):
         field = getattr(self, field_name, None)
         if not isinstance(field, Field):
             continue
         if field.raw_body:
             if self.request.method.upper() in ('HEAD', 'GET', 'OPTIONS'):
                 data = empty
             else:
                 data = to_text(self.request.body)
         else:
             data = self.path_kwargs.get(
                 field_name, self.get_argument(field_name, empty))
         try:
             value = field.run_validation(data)
         except ValidationError as exc:
             if isinstance(exc.detail, dict):
                 raise
             errors[field_name] = exc.detail
         else:
             setattr(self, field_name, value)
     if errors:
         raise CustomError(ErrCode.ERR_COMMON_BAD_PARAM,
                           **{CodeData.get_data_tag(): errors})
Пример #2
0
    def send_error(self, status_code=500, **kwargs):
        if 'exc_info' in kwargs:
            exc_info = kwargs['exc_info']
            if self._finished:
                self.log.error("ApiHandler exception in finished %s\n%r",
                               self._request_summary(),
                               self.request,
                               exc_info=exc_info)
            else:
                if isinstance(exc_info[1], CustomError):
                    kwargs['__api_data'] = exc_info[1]
                    status_code = exc_info[1].status_code
                    if status_code is not None:
                        if not isinstance(status_code, six.integer_types):
                            status_code = to_text(status_code)
                            if not status_code.isdigit():
                                status_code = None
                            else:
                                status_code = int(status_code)

                    if status_code is None or status_code <= 0 or status_code >= 1000:
                        status_code = self.CUSTOM_ERROR_STATUS_CODE
                else:
                    kwargs['__api_data'] = ErrCode.ERR_SYS_ERROR
                    kwargs['__api_exc_info'] = exc_info
                    if not isinstance(exc_info[1], HTTPError):
                        status_code = self.EXCEPTION_STATUS_CODE
                        self.mail_exc_info(exc_info)
        super(ApiHandler, self).send_error(status_code, **kwargs)
Пример #3
0
    def to_python(self, data):
        """
        Validate that the input is a decimal number and return a Decimal
        instance.
        """

        data = to_text(data).strip()

        if len(data) > self.MAX_STRING_LENGTH:
            self.fail('max_string_length')

        try:
            value = decimal.Decimal(data)
        except decimal.DecimalException:
            self.fail('invalid')

        # Check for NaN. It is the only value that isn't equal to itself,
        # so we can use this to identify NaN values.
        if value != value:
            self.fail('invalid')

        # Check for infinity and negative infinity.
        if value in (decimal.Decimal('Inf'), decimal.Decimal('-Inf')):
            self.fail('invalid')

        return self.quantize(self.validate_precision(value))
Пример #4
0
 def mget(self, keys=()):
     if not keys:
         return ()
     if not hasattr(self.kvdb, 'mget'):
         return super(KvStorage, self).mget(keys)
     key_names = [self.key_name(key) for key in keys]
     ret = self.kvdb.mget(key_names)
     return [
         json.loads(to_text(value)) if value is not None else None
         for value in ret
     ]
Пример #5
0
    def emit(self, record):
        subject = '%s: %s' % (
            to_text(record.levelname),
            to_text(record.getMessage())
        )
        subject = self.format_subject(subject)

        # Since we add a nicely formatted traceback on our own, create a copy
        # of the log record without the exception data.
        no_exc_record = copy(record)
        no_exc_record.exc_info = None
        no_exc_record.exc_text = None

        if record.exc_info:
            exc_info = record.exc_info
        else:
            exc_info = (None, record.getMessage(), None)

        reporter = ExceptionReporter(getattr(record, 'handler', None), *exc_info, is_email=True)
        message = "%s\n\n%s" % (to_text(self.format(no_exc_record)), to_text(reporter.get_traceback_text()))
        html_message = reporter.get_traceback_html() if self.include_html else None
        self.send_mail(subject, message, fail_silently=True, html_message=html_message)
Пример #6
0
def _get_error_details(data, default_code=None):
    """
    Descend into a nested data structure, forcing any
    lazy translation strings or strings into `ErrorDetail`.
    """
    if isinstance(data, list):
        ret = [_get_error_details(item, default_code) for item in data]
        return ret
    elif isinstance(data, dict):
        ret = {
            key: _get_error_details(value, default_code)
            for key, value in data.items()
        }
        return ret

    text = to_text(data)
    code = getattr(data, 'code', default_code)
    return ErrorDetail(text, code)
Пример #7
0
def forbid_multi_line_headers(name, val, encoding):
    """Forbids multi-line headers, to prevent header injection."""
    encoding = encoding or settings.DEFAULT_CHARSET
    val = to_text(val)
    if '\n' in val or '\r' in val:
        raise BadHeaderError(
            "Header values can't contain newlines (got %r for header %r)" %
            (val, name))
    try:
        val.encode('ascii')
    except UnicodeEncodeError:
        if name.lower() in ADDRESS_HEADERS:
            val = ', '.join(
                sanitize_address(addr, encoding)
                for addr in getaddresses((val, )))
        else:
            val = Header(val, encoding).encode()
    else:
        if name.lower() == 'subject':
            val = Header(val).encode()
    return str(name), val
Пример #8
0
def sanitize_address(addr, encoding):
    """
    Format a pair of (name, address) or an email address string.
    """
    if not isinstance(addr, tuple):
        addr = parseaddr(to_text(addr))
    nm, addr = addr
    localpart, domain = None, None
    nm = Header(nm, encoding).encode()
    try:
        addr.encode('ascii')
    except UnicodeEncodeError:  # IDN or non-ascii in the local part
        localpart, domain = split_addr(addr, encoding)

    if six.PY2:
        # On Python 2, use the stdlib since `email.headerregistry` doesn't exist.
        from email.utils import formataddr
        if localpart and domain:
            addr = '@'.join([localpart, domain])
        return formataddr((nm, addr))

    # On Python 3, an `email.headerregistry.Address` object is used since
    # email.utils.formataddr() naively encodes the name as ascii (see #25986).
    from email.headerregistry import Address
    from email.errors import InvalidHeaderDefect, NonASCIILocalPartDefect

    if localpart and domain:
        address = Address(nm, username=localpart, domain=domain)
        return str(address)

    try:
        address = Address(nm, addr_spec=addr)
    except (InvalidHeaderDefect, NonASCIILocalPartDefect):
        localpart, domain = split_addr(addr, encoding)
        address = Address(nm, username=localpart, domain=domain)
    return str(address)
Пример #9
0
    def get_traceback_data(self):
        """Return a dictionary containing traceback information."""

        frames = self.get_traceback_frames()
        for i, frame in enumerate(frames):
            if 'vars' in frame:
                frame_vars = []
                for k, v in frame['vars']:
                    v = pprint(v)
                    # The force_escape filter assume unicode, make sure that works
                    if isinstance(v, six.binary_type):
                        v = v.decode(
                            'utf-8',
                            'replace')  # don't choke on non-utf-8 input
                    # Trim large blobs of data
                    if len(v) > 4096:
                        v = '%s... <trimmed %d bytes string>' % (v[0:4096],
                                                                 len(v))
                    frame_vars.append((k, escape(v)))
                frame['vars'] = frame_vars
            frames[i] = frame

        unicode_hint = ''
        if self.exc_type and issubclass(self.exc_type, UnicodeError):
            start = getattr(self.exc_value, 'start', None)
            end = getattr(self.exc_value, 'end', None)
            if start is not None and end is not None:
                unicode_str = self.exc_value.args[1]
                unicode_hint = to_text(
                    unicode_str[max(start - 5, 0):min(end +
                                                      5, len(unicode_str))],
                    'ascii')
        from tornado import version
        if self.handler is None:
            user_str = None
        else:
            try:
                user_str = to_text(self.handler.current_user)
            except Exception:
                # request.user may raise OperationalError if the database is
                # unavailable, for example.
                user_str = '[unable to retrieve the current user]'

        c = {
            'is_email':
            self.is_email,
            'unicode_hint':
            unicode_hint,
            'frames':
            frames,
            'handler':
            self.handler,
            'user_str':
            user_str,
            'filtered_POST_items':
            list(self.filter.get_post_parameters(self.handler).items()),
            'settings':
            get_safe_settings(),
            'app_settings':
            get_safe_app_settings(self.handler),
            'sys_executable':
            sys.executable,
            'sys_version_info':
            '%d.%d.%d' % sys.version_info[0:3],
            'server_time':
            datetime.datetime.now(),
            'tornado_version_info':
            version,
            'tornadoapi_version_info':
            tornadoapi.__version__,
            'sys_path':
            sys.path,
            'template_info':
            self.template_info,
            'template_does_not_exist':
            self.template_does_not_exist,
            'postmortem':
            self.postmortem,
        }
        if self.handler is not None:
            c['request_GET_items'] = self.handler.request.query_arguments.items(
            )
            c['request_FILES_items'] = self.handler.request.files.items()
            c['request_COOKIES_items'] = self.handler.request.cookies.items()
        # Check whether exception info is available
        if self.exc_type:
            c['exception_type'] = self.exc_type.__name__
        if self.exc_value:
            c['exception_value'] = to_text(self.exc_value)
        if frames:
            c['lastframe'] = frames[-1]
        return c
Пример #10
0
 def to_python(self, data):
     if isinstance(data, bool) or not isinstance(
             data, six.string_types + six.integer_types + (float, )):
         self.fail('invalid')
     value = to_text(data)
     return value.strip() if self.trim_whitespace else value
Пример #11
0
 def get(self, key, default=None):
     key = self.key_name(key)
     value = self.kvdb.get(key)
     if value is None:
         return default
     return json.loads(to_text(value))
Пример #12
0
 def get_data_tag(cls):
     data_tag = 'data'
     if settings.RESPONSE_DATA_TAG and isinstance(
             settings.RESPONSE_DATA_TAG, six.string_types):
         data_tag = to_text(settings.RESPONSE_DATA_TAG)
     return data_tag
Пример #13
0
 def get_message_tag(cls):
     message_tag = 'message'
     if settings.RESPONSE_MESSAGE_TAG and isinstance(
             settings.RESPONSE_MESSAGE_TAG, six.string_types):
         message_tag = to_text(settings.RESPONSE_MESSAGE_TAG)
     return message_tag
Пример #14
0
 def get_code_tag(cls):
     code_tag = 'code'
     if settings.RESPONSE_CODE_TAG and isinstance(
             settings.RESPONSE_CODE_TAG, six.string_types):
         code_tag = to_text(settings.RESPONSE_CODE_TAG)
     return code_tag