from flask import make_response from functools import wraps import json import logging from werkzeug.wrappers import BaseResponse as Response from rz_api_common import API_Exception__bad_request from rz_kernel import RZDoc_Exception__not_found HTTP_STATUS__101_SWITCHING_PROTOCOLS = 101 HTTP_STATUS__201_CREATED = 201 HTTP_STATUS__204_NO_CONTENT = 204 HTTP_STATUS__500_INTERNAL_SERVER_ERROR = 500 log = logging.getLogger('rhizi') def __common_resp_handle(data, error, status): """ common response handling: - add common response headers - serialize response @data must be json serializable @error will be serialized with str() """ def __response_wrap(data=None, error=None): """ wrap response data/errors as dict - this should always be used when returning data to allow easy return of list objects, assist in error case distinction, etc. """ return dict(data=data, error=error) if not error: error_str = None else: error_str = str(error) # convert any Exception objects to serializable form ret_data = __response_wrap(data, error_str) resp_payload = json.dumps(ret_data) resp = Response(resp_payload, mimetype='application/json', status=status) resp.headers['Access-Control-Allow-Origin'] = '*' # more response processing return resp def common_resp_handle__success(data=None, error=None, status=200): return __common_resp_handle(data, error, status) def common_resp_handle__redirect(data=None, error=None, status=300): return __common_resp_handle(data, error, status) def common_resp_handle__client_error(data=None, error=None, status=400): return __common_resp_handle(data, error, status) def common_resp_handle__server_error(data=None, error=None, status=500): return __common_resp_handle(data, error, status) def common_rest_req_exception_handler(rest_API_endpoint): @wraps(rest_API_endpoint) def rest_API_endpoint__decorated(*args, **kwargs): try: return rest_API_endpoint(*args, **kwargs) except API_Exception__bad_request as e: log.exception(e) return common_resp_handle__client_error(error=e) # currently blame client for all DNFs except RZDoc_Exception__not_found as e: log.exception(e) return common_resp_handle__client_error(error=e) # currently blame client for all DNFs except Exception as e: log.exception(e) return common_resp_handle__server_error(error=e) return rest_API_endpoint__decorated def make_response__json(status=200, data={}): """ Construct a json response with proper content-type header @param data: must be serializable via json.dumps """ data_str = json.dumps(data) resp = make_response(data_str) resp.headers['Content-Type'] = "application/json" resp.status = str(status) return resp def make_response__http__empty(status=200): """ Construct an empty HTTP response """ resp = make_response() resp.status = str(status) return resp def make_response__http__pre_tag_wrapped(html_str, status=200): """ Construct a '
' tag wrapped HTTP response
"""
resp_arr = ['',
'',
html_str,
''
]
return (''.join(resp_arr), 200)
def make_response__json__html(status=200, html_str=''):
"""
Construct a json response with HTML payload
"""
return make_response__json(status=status, data={'response__html': html_str })
def make_response__json__redirect(redirect_url, status=303, html_str=''):
"""
Construct a json response with redirect payload
"""
assert status >= 300 and status < 400
return make_response__json(status=status,
data={'response__html': html_str,
'redirect_url': redirect_url })
def sock_addr_from_env_HTTP_headers(req_env, key_name__addr):
"""
Extract remote socket address based on header data
[!] if header value contains more than a single address only the first one is used.
@param key_name__addr: header name to probe for address value
@return: (remote_addr, remote_port) where remote_port may be None
@raise Exception: if header is missing from env
"""
header_key = 'HTTP_' + key_name__addr.upper().replace('-', '_')
addr_set_str = req_env.get(header_key)
if not addr_set_str:
raise Exception('\'%s\' header missing' % (key_name__addr))
addr_set = addr_set_str.split(',')
if len(addr_set) > 1:
log.warning('%s header contains multiple addresses, using first: header value: \'%s\'' % (key_name__addr, addr_set_str))
addr_val = addr_set.pop()
# deduce addr:port - port might not be present in header value
addr_val_arr = addr_val.split(':')
rmt_addr = addr_val_arr[0]
rmt_port = addr_val_arr[1] if 2 == len(addr_val_arr) else None
return rmt_addr, rmt_port
def sock_addr_from_REMOTE_X_keys(req_env):
rmt_addr = req_env['REMOTE_ADDR']
rmt_port = req_env['REMOTE_PORT']
return rmt_addr, rmt_port