webhooks: Improve type checking of api requests
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
7ec2ec30e3
commit
fa83b1319c
|
@ -27,10 +27,6 @@ def byteify(data, ignore_dicts=False):
|
||||||
for k, v in data.items()}
|
for k, v in data.items()}
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def json_loads_byteified(data):
|
|
||||||
return byteify(
|
|
||||||
json.loads(data, object_hook=byteify), True)
|
|
||||||
|
|
||||||
class WebRequestError(homing.CommandError):
|
class WebRequestError(homing.CommandError):
|
||||||
def __init__(self, message,):
|
def __init__(self, message,):
|
||||||
Exception.__init__(self, message)
|
Exception.__init__(self, message)
|
||||||
|
@ -47,28 +43,39 @@ class WebRequest:
|
||||||
error = WebRequestError
|
error = WebRequestError
|
||||||
def __init__(self, client_conn, request):
|
def __init__(self, client_conn, request):
|
||||||
self.client_conn = client_conn
|
self.client_conn = client_conn
|
||||||
base_request = json_loads_byteified(request)
|
base_request = json.loads(request, object_hook=byteify)
|
||||||
|
if type(base_request) != dict:
|
||||||
|
raise ValueError("Not a top-level dictionary")
|
||||||
self.id = base_request.get('id', None)
|
self.id = base_request.get('id', None)
|
||||||
self.method = base_request['method']
|
self.method = base_request.get('method')
|
||||||
self.params = base_request.get('params', {})
|
self.params = base_request.get('params', {})
|
||||||
|
if type(self.method) != str or type(self.params) != dict:
|
||||||
|
raise ValueError("Invalid request type")
|
||||||
self.response = None
|
self.response = None
|
||||||
self.is_error = False
|
self.is_error = False
|
||||||
|
|
||||||
def get_client_connection(self):
|
def get_client_connection(self):
|
||||||
return self.client_conn
|
return self.client_conn
|
||||||
|
|
||||||
def get(self, item, default=Sentinel):
|
def get(self, item, default=Sentinel, types=None):
|
||||||
if item not in self.params:
|
value = self.params.get(item, default)
|
||||||
if default == Sentinel:
|
if value is Sentinel:
|
||||||
raise WebRequestError("Invalid Argument [%s]" % item)
|
raise WebRequestError("Missing Argument [%s]" % (item,))
|
||||||
return default
|
if types is not None and type(value) not in types:
|
||||||
return self.params[item]
|
raise WebRequestError("Invalid Argument Type [%s]" % (item,))
|
||||||
|
return value
|
||||||
|
|
||||||
def get_int(self, item):
|
def get_str(self, item, default=Sentinel):
|
||||||
return int(self.get(item))
|
return self.get(item, default, types=(str,))
|
||||||
|
|
||||||
def get_float(self, item):
|
def get_int(self, item, default=Sentinel):
|
||||||
return float(self.get(item))
|
return self.get(item, default, types=(int,))
|
||||||
|
|
||||||
|
def get_float(self, item, default=Sentinel):
|
||||||
|
return float(self.get(item, default, types=(int, float)))
|
||||||
|
|
||||||
|
def get_dict(self, item, default=Sentinel):
|
||||||
|
return self.get(item, default, types=(dict,))
|
||||||
|
|
||||||
def get_method(self):
|
def get_method(self):
|
||||||
return self.method
|
return self.method
|
||||||
|
@ -196,14 +203,11 @@ class ClientConnection:
|
||||||
requests[0] = self.partial_data + requests[0]
|
requests[0] = self.partial_data + requests[0]
|
||||||
self.partial_data = requests.pop()
|
self.partial_data = requests.pop()
|
||||||
for req in requests:
|
for req in requests:
|
||||||
logging.debug(
|
|
||||||
"webhooks: Request received: %s" % (req))
|
|
||||||
try:
|
try:
|
||||||
web_request = WebRequest(self, req)
|
web_request = WebRequest(self, req)
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception(
|
logging.exception("webhooks: Error decoding Server Request %s"
|
||||||
"webhooks: Error decoding Server Request %s"
|
% (req))
|
||||||
% (req))
|
|
||||||
continue
|
continue
|
||||||
self.reactor.register_callback(
|
self.reactor.register_callback(
|
||||||
lambda e, s=self, wr=web_request: s._process_request(wr))
|
lambda e, s=self, wr=web_request: s._process_request(wr))
|
||||||
|
@ -320,7 +324,7 @@ class GCodeHelper:
|
||||||
def _handle_help(self, web_request):
|
def _handle_help(self, web_request):
|
||||||
web_request.send(self.gcode.get_command_help())
|
web_request.send(self.gcode.get_command_help())
|
||||||
def _handle_script(self, web_request):
|
def _handle_script(self, web_request):
|
||||||
self.gcode.run_script(web_request.get('script'))
|
self.gcode.run_script(web_request.get_str('script'))
|
||||||
def _handle_restart(self, web_request):
|
def _handle_restart(self, web_request):
|
||||||
self.gcode.run_script('restart')
|
self.gcode.run_script('restart')
|
||||||
def _handle_firmware_restart(self, web_request):
|
def _handle_firmware_restart(self, web_request):
|
||||||
|
@ -335,7 +339,7 @@ class GCodeHelper:
|
||||||
cconn.send(tmp)
|
cconn.send(tmp)
|
||||||
def _handle_subscribe_output(self, web_request):
|
def _handle_subscribe_output(self, web_request):
|
||||||
cconn = web_request.get_client_connection()
|
cconn = web_request.get_client_connection()
|
||||||
template = web_request.get('response_template', {})
|
template = web_request.get_dict('response_template', {})
|
||||||
self.clients[cconn] = template
|
self.clients[cconn] = template
|
||||||
if not self.is_output_registered:
|
if not self.is_output_registered:
|
||||||
self.gcode.register_output_handler(self._output_callback)
|
self.gcode.register_output_handler(self._output_callback)
|
||||||
|
@ -406,20 +410,18 @@ class QueryStatusHelper:
|
||||||
return reactor.NEVER
|
return reactor.NEVER
|
||||||
return eventtime + SUBSCRIPTION_REFRESH_TIME
|
return eventtime + SUBSCRIPTION_REFRESH_TIME
|
||||||
def _handle_query(self, web_request, is_subscribe=False):
|
def _handle_query(self, web_request, is_subscribe=False):
|
||||||
objects = web_request.get('objects')
|
objects = web_request.get_dict('objects')
|
||||||
# Validate subscription format
|
# Validate subscription format
|
||||||
if type(objects) != type({}):
|
|
||||||
raise web_request.error("Invalid argument")
|
|
||||||
for k, v in objects.items():
|
for k, v in objects.items():
|
||||||
if type(k) != type("") or type(v) not in [type([]), type(None)]:
|
if type(k) != str or (v is not None and type(v) != list):
|
||||||
raise web_request.error("Invalid argument")
|
raise web_request.error("Invalid argument")
|
||||||
if v is not None:
|
if v is not None:
|
||||||
for ri in v:
|
for ri in v:
|
||||||
if type(ri) != type(""):
|
if type(ri) != str:
|
||||||
raise web_request.error("Invalid argument")
|
raise web_request.error("Invalid argument")
|
||||||
# Add to pending queries
|
# Add to pending queries
|
||||||
cconn = web_request.get_client_connection()
|
cconn = web_request.get_client_connection()
|
||||||
template = web_request.get('response_template', {})
|
template = web_request.get_dict('response_template', {})
|
||||||
if is_subscribe and cconn in self.clients:
|
if is_subscribe and cconn in self.clients:
|
||||||
del self.clients[cconn]
|
del self.clients[cconn]
|
||||||
reactor = self.printer.get_reactor()
|
reactor = self.printer.get_reactor()
|
||||||
|
|
Loading…
Reference in New Issue