def handle_error(self, e): ''' Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param Exception e: the raised Exception object ''' got_request_exception.send(current_app._get_current_object(), exception=e) headers = Headers() if e.__class__ in self.error_handlers: handler = self.error_handlers[e.__class__] result = handler(e) default_data, code, headers = unpack(result, 500) elif isinstance(e, HTTPException): code = e.code default_data = { 'message': getattr(e, 'description', HTTP_STATUS_CODES.get(code, '')) } headers = e.get_response().headers elif self._default_error_handler: result = self._default_error_handler(e) default_data, code, headers = unpack(result, 500) else: code = 500 default_data = { 'message': HTTP_STATUS_CODES.get(code, str(e)), } default_data['message'] = default_data.get('message', str(e)) data = getattr(e, 'data', default_data) fallback_mediatype = None if code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) elif code == 404 and current_app.config.get("ERROR_404_HELP", True): data['message'] = self._help_on_404(data.get('message', None)) elif code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" # Remove blacklisted headers for header in HEADERS_BLACKLIST: headers.pop(header, None) resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) if code == 401: resp = self.unauthorized(resp) return resp
def _create_error_out(api_exception): got_request_exception.send(current_app._get_current_object(), exception=api_exception) headers = Headers() if isinstance(api_exception, HTTPException): status_code = api_exception.code msg = getattr(api_exception, 'description', http_status_message(status_code)) headers = api_exception.get_response().headers else: status_code = 500 msg = http_status_message(status_code) remove_headers = ('Content-Length', ) for header in remove_headers: headers.pop(header, None) if status_code and status_code >= 500: exc_info = sys.exc_info() current_app.log_exception(exc_info) error_out = { 'error': { 'message': msg, 'name': type(api_exception).__name__ }, 'status': status_code, 'success': False } return error_out, status_code, headers
def from_environ(cls, environ, **kwargs): """Turn an environ dict back into a builder. Any extra kwargs override the args extracted from the environ. .. versionadded:: 0.15 """ headers = Headers(EnvironHeaders(environ)) out = { "path": environ["PATH_INFO"], "base_url": cls._make_base_url( environ["wsgi.url_scheme"], headers.pop("Host"), environ["SCRIPT_NAME"], ), "query_string": environ["QUERY_STRING"], "method": environ["REQUEST_METHOD"], "input_stream": environ["wsgi.input"], "content_type": headers.pop("Content-Type", None), "content_length": headers.pop("Content-Length", None), "errors_stream": environ["wsgi.errors"], "multithread": environ["wsgi.multithread"], "multiprocess": environ["wsgi.multiprocess"], "run_once": environ["wsgi.run_once"], "headers": headers, } out.update(kwargs) return cls(**out)
def get_request(): # copy of headers headers = Headers(request.headers) # remove unwanted extra headers for h in REMOVE_HEADERS: if headers.has_key(h): headers.pop(h) json_headers = json.dumps(OrderedDict(headers)) # create file if not exists if not os.path.isfile(os.path.abspath(HTTP_HEADERS_FILENAME)): with open(os.path.abspath(HTTP_HEADERS_FILENAME), "w+"): pass # read file with open(os.path.abspath(HTTP_HEADERS_FILENAME), "r") as f: headers_data = f.readlines() # append new headers headers_data.append(json_headers + ",\n") # deduplicate headers_data_to_write = dedup(headers_data) # write output data with open(os.path.abspath(HTTP_HEADERS_FILENAME), "w") as f: for h in headers_data_to_write: f.write(h) return json_headers
def get_pdf(self, report, record_id, context=None): """Used to return the content of a generated PDF. :returns: pdf """ url = "/report/pdf/report/" + report.report_file + "/" + str(record_id) reqheaders = Headers(request.httprequest.headers) reqheaders.pop("Accept") reqheaders.add("Accept", "application/pdf") reqheaders.pop("Content-Type") reqheaders.add("Content-Type", "text/plain") response = Client(request.httprequest.app, BaseResponse).get(url, headers=reqheaders, follow_redirects=True) return response.data
def copy_headers(remote: requests.Response, response: Response, *, server_map, **kwargs) -> Headers: server_origin = server_map['origins']['main'] remote_url: SplitResult = urlsplit(remote.url) headers = Headers(remote.headers.items()) headers.pop('Set-Cookie', None) headers.pop('Transfer-Encoding', None) response.headers = headers if 'Location' in headers: headers[ 'Location'] = f'{server_origin}/{urljoin(remote_url.geturl(), headers["Location"])}' response.headers.update(headers) return headers
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not isinstance(e, HTTPException) and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e headers = Headers() if isinstance(e, HTTPException): code = e.code default_data = { 'message': getattr(e, 'description', http_status_message(code)) } headers = e.get_response().headers else: code = 500 default_data = { 'message': http_status_message(code), } # Werkzeug exceptions generate a content-length header which is added # to the response in addition to the actual content-length header # https://github.com/flask-restful/flask-restful/issues/534 remove_headers = ('Content-Length',) for header in remove_headers: headers.pop(header, None) data = getattr(e, 'data', default_data) if code and code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404: rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] = data["message"].rstrip('.') + '. ' else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join(( rules[match] for match in close_matches) ) + ' ?' error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" resp = self.make_response( data, code, headers, fallback_mediatype = fallback_mediatype ) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not isinstance(e, HTTPException) and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e headers = Headers() if isinstance(e, HTTPException): code = e.code default_data = { 'message': getattr(e, 'description', http_status_message(code)) } headers = e.get_response().headers else: code = 500 default_data = { 'message': http_status_message(code), } # Werkzeug exceptions generate a content-length header which is added # to the response in addition to the actual content-length header # https://github.com/flask-restful/flask-restful/issues/534 remove_headers = ('Content-Length',) for header in remove_headers: headers.pop(header, None) data = getattr(e, 'data', default_data) if code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404: rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] = data["message"].rstrip('.') + '. ' else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join(( rules[match] for match in close_matches) ) + ' ?' error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" resp = self.make_response( data, code, headers, fallback_mediatype = fallback_mediatype ) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): ''' Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param Exception e: the raised Exception object ''' got_request_exception.send(current_app._get_current_object(), exception=e) include_message_in_response = current_app.config.get("ERROR_INCLUDE_MESSAGE", True) default_data = {} headers = Headers() for typecheck, handler in six.iteritems(self._own_and_child_error_handlers): if isinstance(e, typecheck): result = handler(e) default_data, code, headers = unpack(result, HTTPStatus.INTERNAL_SERVER_ERROR) break else: if isinstance(e, HTTPException): code = HTTPStatus(e.code) if include_message_in_response: default_data = { 'message': getattr(e, 'description', code.phrase) } headers = e.get_response().headers elif self._default_error_handler: result = self._default_error_handler(e) default_data, code, headers = unpack(result, HTTPStatus.INTERNAL_SERVER_ERROR) else: code = HTTPStatus.INTERNAL_SERVER_ERROR if include_message_in_response: default_data = { 'message': code.phrase, } if include_message_in_response: default_data['message'] = default_data.get('message', str(e)) data = getattr(e, 'data', default_data) fallback_mediatype = None if code >= HTTPStatus.INTERNAL_SERVER_ERROR: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) elif code == HTTPStatus.NOT_FOUND and current_app.config.get("ERROR_404_HELP", True) \ and include_message_in_response: data['message'] = self._help_on_404(data.get('message', None)) elif code == HTTPStatus.NOT_ACCEPTABLE and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" # Remove blacklisted headers for header in HEADERS_BLACKLIST: headers.pop(header, None) resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) if code == HTTPStatus.UNAUTHORIZED: resp = self.unauthorized(resp) return resp
class Response(AbstractResponse, ResponseCookieMixin, ResponseRedirectMixin): def __init__(self, context, *, status=200, version=None, headers=None, body=None): super().__init__() self.context = context context.response = self self._status = HTTPStatus(status) self.version = version or 'HTTP/1.1' if headers is None: self.headers = Headers() else: self.headers = Headers(headers) self.body = body @property def status(self): return int(self._status) @status.setter def status(self, value): self._status = HTTPStatus(value) @property def status_text(self): return self._status.phrase @property def body(self): return self._body @body.setter def body(self, value): if value is None: self._body = stream(b'') self.content_length = 0 elif isinstance(value, bytes): self._body = stream(value) self.content_length = len(value) elif isinstance(value, str): value = value.encode('utf-8') self._body = stream(value) self.content_length = len(value) elif inspect.isasyncgen(value): self._body = value else: msg = (f'response body should be bytes, str or async generator, ' f'type {type(value).__name__} is not supported') raise ValueError(msg) def json(self, value): sort_keys = self.context.config.json_sort_keys indent = None if self.context.config.json_pretty: indent = 4 if self.context.config.json_ujson_enable: dumps = ujson.dumps else: dumps = json.dumps text = dumps(value, ensure_ascii=False, indent=indent, sort_keys=sort_keys) self.body = text.encode('utf-8') self.headers['Content-Type'] = 'application/json;charset=utf-8' @property def chunked(self): return self.headers.get('Transfer-Encoding', '').lower() == 'chunked' @chunked.setter def chunked(self, value): if value: self.headers['Transfer-Encoding'] = 'chunked' else: self.headers.pop('Transfer-Encoding', None) @property def content_length(self): length = self.headers.get('Content-Length', '') if not length: return None return int(length) @content_length.setter def content_length(self, value): if value is None: self.headers.pop('Content-Length', None) else: self.headers['Content-Length'] = value @property def keep_alive(self): connection = self.headers.get('Connection', '').lower() if connection == 'keep-alive': return True elif connection == 'close': return False return None @keep_alive.setter def keep_alive(self, value): if value is None: self.headers.pop('Connection', None) elif value: self.headers['Connection'] = 'keep-alive' else: self.headers['Connection'] = 'close' def __repr__(self): return f'<{type(self).__name__} {self.status} {self.status_text}>'
def test_headers(): # simple header tests headers = Headers() headers.add("Content-Type", "text/plain") headers.add("X-Foo", "bar") assert "x-Foo" in headers assert "Content-type" in headers headers["Content-Type"] = "foo/bar" assert headers["Content-Type"] == "foo/bar" assert len(headers.getlist("Content-Type")) == 1 # list conversion assert headers.to_list() == [("Content-Type", "foo/bar"), ("X-Foo", "bar")] assert str(headers) == ("Content-Type: foo/bar\r\n" "X-Foo: bar\r\n" "\r\n") assert str(Headers()) == "\r\n" # extended add headers.add("Content-Disposition", "attachment", filename="foo") assert headers["Content-Disposition"] == "attachment; filename=foo" headers.add("x", "y", z='"') assert headers["x"] == r'y; z="\""' # defaults headers = Headers([("Content-Type", "text/plain"), ("X-Foo", "bar"), ("X-Bar", "1"), ("X-Bar", "2")]) assert headers.getlist("x-bar") == ["1", "2"] assert headers.get("x-Bar") == "1" assert headers.get("Content-Type") == "text/plain" assert headers.setdefault("X-Foo", "nope") == "bar" assert headers.setdefault("X-Bar", "nope") == "1" assert headers.setdefault("X-Baz", "quux") == "quux" assert headers.setdefault("X-Baz", "nope") == "quux" headers.pop("X-Baz") # type conversion assert headers.get("x-bar", type=int) == 1 assert headers.getlist("x-bar", type=int) == [1, 2] # list like operations assert headers[0] == ("Content-Type", "text/plain") assert headers[:1] == Headers([("Content-Type", "text/plain")]) del headers[:2] del headers[-1] assert headers == Headers([("X-Bar", "1")]) # copying a = Headers([("foo", "bar")]) b = a.copy() a.add("foo", "baz") assert a.getlist("foo") == ["bar", "baz"] assert b.getlist("foo") == ["bar"] headers = Headers([("a", 1)]) assert headers.pop("a") == 1 assert headers.pop("b", 2) == 2 assert_raises(KeyError, headers.pop, "c") # set replaces and accepts same arguments as add a = Headers() a.set("Content-Disposition", "useless") a.set("Content-Disposition", "attachment", filename="foo") assert a["Content-Disposition"] == "attachment; filename=foo"
def handle_error(self, e): ''' Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param Exception e: the raised Exception object ''' got_request_exception.send(current_app._get_current_object(), exception=e) include_message_in_response = current_app.config.get( "ERROR_INCLUDE_MESSAGE", True) default_data = {} headers = Headers() if e.__class__ in self.error_handlers: handler = self.error_handlers[e.__class__] result = handler(e) default_data, code, headers = unpack( result, HTTPStatus.INTERNAL_SERVER_ERROR) elif isinstance(e, HTTPException): code = HTTPStatus(e.code) if include_message_in_response: default_data = { 'message': getattr(e, 'description', code.phrase) } headers = e.get_response().headers elif self._default_error_handler: result = self._default_error_handler(e) default_data, code, headers = unpack( result, HTTPStatus.INTERNAL_SERVER_ERROR) else: code = HTTPStatus.INTERNAL_SERVER_ERROR if include_message_in_response: default_data = { 'message': code.phrase, } if include_message_in_response: default_data['message'] = default_data.get('message', str(e)) data = getattr(e, 'data', default_data) fallback_mediatype = None if code >= HTTPStatus.INTERNAL_SERVER_ERROR: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) elif code == HTTPStatus.NOT_FOUND and current_app.config.get("ERROR_404_HELP", True) \ and include_message_in_response: data['message'] = self._help_on_404(data.get('message', None)) elif code == HTTPStatus.NOT_ACCEPTABLE and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[ 0] if supported_mediatypes else "text/plain" # Remove blacklisted headers for header in HEADERS_BLACKLIST: headers.pop(header, None) resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) if code == HTTPStatus.UNAUTHORIZED: resp = self.unauthorized(resp) return resp
def test_headers(): # simple header tests headers = Headers() headers.add('Content-Type', 'text/plain') headers.add('X-Foo', 'bar') assert 'x-Foo' in headers assert 'Content-type' in headers headers['Content-Type'] = 'foo/bar' assert headers['Content-Type'] == 'foo/bar' assert len(headers.getlist('Content-Type')) == 1 # list conversion assert headers.to_list() == [ ('Content-Type', 'foo/bar'), ('X-Foo', 'bar') ] assert str(headers) == ( "Content-Type: foo/bar\r\n" "X-Foo: bar\r\n" "\r\n") assert str(Headers()) == "\r\n" # extended add headers.add('Content-Disposition', 'attachment', filename='foo') assert headers['Content-Disposition'] == 'attachment; filename=foo' headers.add('x', 'y', z='"') assert headers['x'] == r'y; z="\""' # defaults headers = Headers([ ('Content-Type', 'text/plain'), ('X-Foo', 'bar'), ('X-Bar', '1'), ('X-Bar', '2') ]) assert headers.getlist('x-bar') == ['1', '2'] assert headers.get('x-Bar') == '1' assert headers.get('Content-Type') == 'text/plain' assert headers.setdefault('X-Foo', 'nope') == 'bar' assert headers.setdefault('X-Bar', 'nope') == '1' assert headers.setdefault('X-Baz', 'quux') == 'quux' assert headers.setdefault('X-Baz', 'nope') == 'quux' headers.pop('X-Baz') # type conversion assert headers.get('x-bar', type=int) == 1 assert headers.getlist('x-bar', type=int) == [1, 2] # list like operations assert headers[0] == ('Content-Type', 'text/plain') assert headers[:1] == Headers([('Content-Type', 'text/plain')]) del headers[:2] del headers[-1] assert headers == Headers([('X-Bar', '1')]) # copying a = Headers([('foo', 'bar')]) b = a.copy() a.add('foo', 'baz') assert a.getlist('foo') == ['bar', 'baz'] assert b.getlist('foo') == ['bar'] headers = Headers([('a', 1)]) assert headers.pop('a') == 1 assert headers.pop('b', 2) == 2 assert_raises(KeyError, headers.pop, 'c') # set replaces and accepts same arguments as add a = Headers() a.set('Content-Disposition', 'useless') a.set('Content-Disposition', 'attachment', filename='foo') assert a['Content-Disposition'] == 'attachment; filename=foo'
def test_headers(): # simple header tests headers = Headers() headers.add('Content-Type', 'text/plain') headers.add('X-Foo', 'bar') assert 'x-Foo' in headers assert 'Content-type' in headers headers['Content-Type'] = 'foo/bar' assert headers['Content-Type'] == 'foo/bar' assert len(headers.getlist('Content-Type')) == 1 # list conversion assert headers.to_list() == [('Content-Type', 'foo/bar'), ('X-Foo', 'bar')] assert str(headers) == ("Content-Type: foo/bar\r\n" "X-Foo: bar\r\n" "\r\n") assert str(Headers()) == "\r\n" # extended add headers.add('Content-Disposition', 'attachment', filename='foo') assert headers['Content-Disposition'] == 'attachment; filename=foo' headers.add('x', 'y', z='"') assert headers['x'] == r'y; z="\""' # defaults headers = Headers([('Content-Type', 'text/plain'), ('X-Foo', 'bar'), ('X-Bar', '1'), ('X-Bar', '2')]) assert headers.getlist('x-bar') == ['1', '2'] assert headers.get('x-Bar') == '1' assert headers.get('Content-Type') == 'text/plain' assert headers.setdefault('X-Foo', 'nope') == 'bar' assert headers.setdefault('X-Bar', 'nope') == '1' assert headers.setdefault('X-Baz', 'quux') == 'quux' assert headers.setdefault('X-Baz', 'nope') == 'quux' headers.pop('X-Baz') # type conversion assert headers.get('x-bar', type=int) == 1 assert headers.getlist('x-bar', type=int) == [1, 2] # list like operations assert headers[0] == ('Content-Type', 'text/plain') assert headers[:1] == Headers([('Content-Type', 'text/plain')]) del headers[:2] del headers[-1] assert headers == Headers([('X-Bar', '1')]) # copying a = Headers([('foo', 'bar')]) b = a.copy() a.add('foo', 'baz') assert a.getlist('foo') == ['bar', 'baz'] assert b.getlist('foo') == ['bar'] headers = Headers([('a', 1)]) assert headers.pop('a') == 1 assert headers.pop('b', 2) == 2 assert_raises(KeyError, headers.pop, 'c') # set replaces and accepts same arguments as add a = Headers() a.set('Content-Disposition', 'useless') a.set('Content-Disposition', 'attachment', filename='foo') assert a['Content-Disposition'] == 'attachment; filename=foo'
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not isinstance(e, HTTPException) and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e headers = Headers() if isinstance(e, HTTPException): if e.response is not None: # If HTTPException is initialized with a response, then return e.get_response(). # This prevents specified error response from being overridden. # eg. HTTPException(response=Response("Hello World")) resp = e.get_response() return resp code = e.code default_data = { 'message': getattr(e, 'description', http_status_message(code)) } headers = e.get_response().headers else: code = 500 default_data = { 'message': http_status_message(code), } # Werkzeug exceptions generate a content-length header which is added # to the response in addition to the actual content-length header # https://github.com/flask-restful/flask-restful/issues/534 remove_headers = ('Content-Length', ) for header in remove_headers: headers.pop(header, None) data = getattr(e, 'data', default_data) if code and code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[ 0] if supported_mediatypes else "text/plain" resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """ Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param Exception e: the raised Exception object """ got_request_exception.send(current_app._get_current_object(), exception=e) # When propagate_exceptions is set, do not return the exception to the # client if a handler is configured for the exception. if (not isinstance(e, HTTPException) and current_app.propagate_exceptions and not isinstance(e, tuple(self.error_handlers.keys()))): exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e include_message_in_response = current_app.config.get( "ERROR_INCLUDE_MESSAGE", True) default_data = {} headers = Headers() for typecheck, handler in six.iteritems( self._own_and_child_error_handlers): if isinstance(e, typecheck): result = handler(e) default_data, code, headers = unpack( result, HTTPStatus.INTERNAL_SERVER_ERROR) break else: if isinstance(e, HTTPException): code = HTTPStatus(e.code) if include_message_in_response: default_data = { "message": getattr(e, "description", code.phrase) } headers = e.get_response().headers elif self._default_error_handler: result = self._default_error_handler(e) default_data, code, headers = unpack( result, HTTPStatus.INTERNAL_SERVER_ERROR) else: code = HTTPStatus.INTERNAL_SERVER_ERROR if include_message_in_response: default_data = { "message": code.phrase, } if include_message_in_response: default_data["message"] = default_data.get("message", str(e)) data = getattr(e, "data", default_data) fallback_mediatype = None if code >= HTTPStatus.INTERNAL_SERVER_ERROR: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) elif (code == HTTPStatus.NOT_FOUND and current_app.config.get("ERROR_404_HELP", True) and include_message_in_response): data["message"] = self._help_on_404(data.get("message", None)) elif code == HTTPStatus.NOT_ACCEPTABLE and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = (supported_mediatypes[0] if supported_mediatypes else "text/plain") # Remove blacklisted headers for header in HEADERS_BLACKLIST: headers.pop(header, None) resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) if code == HTTPStatus.UNAUTHORIZED: resp = self.unauthorized(resp) return resp
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not isinstance(e, HTTPException) and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e headers = Headers() if isinstance(e, HTTPException): if e.response is not None: # If HTTPException is initialized with a response, then return e.get_response(). # This prevents specified error response from being overridden. # eg. HTTPException(response=Response("Hello World")) resp = e.get_response() return resp code = e.code default_data = { 'message': getattr(e, 'description', http_status_message(code)) } headers = e.get_response().headers else: code = 500 default_data = { 'message': http_status_message(code), } # Werkzeug exceptions generate a content-length header which is added # to the response in addition to the actual content-length header # https://github.com/flask-restful/flask-restful/issues/534 remove_headers = ('Content-Length',) for header in remove_headers: headers.pop(header, None) data = getattr(e, 'data', default_data) if code and code >= 500: exc_info = sys.exc_info() if exc_info[1] is None: exc_info = None current_app.log_exception(exc_info) error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" resp = self.make_response( data, code, headers, fallback_mediatype = fallback_mediatype ) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp