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})
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)
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))
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 ]
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)
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)
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
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)
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
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
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))
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
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
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