database: handle invalid reduce results
It is possible to reduce to a value that is not a dict in "insert_item()" and "update_item()". Raise a ServerError with a clear description of what went wrong in these situations. Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
89e78b9a00
commit
bb39a3c1b2
|
@ -15,7 +15,7 @@ from io import BytesIO
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from threading import Lock as ThreadLock
|
from threading import Lock as ThreadLock
|
||||||
import lmdb
|
import lmdb
|
||||||
from utils import SentinelClass
|
from utils import SentinelClass, ServerError
|
||||||
|
|
||||||
# Annotation imports
|
# Annotation imports
|
||||||
from typing import (
|
from typing import (
|
||||||
|
@ -64,6 +64,9 @@ RECORD_DECODE_FUNCS = {
|
||||||
SENTINEL = SentinelClass.get_instance()
|
SENTINEL = SentinelClass.get_instance()
|
||||||
|
|
||||||
def getitem_with_default(item: Dict, field: Any) -> Any:
|
def getitem_with_default(item: Dict, field: Any) -> Any:
|
||||||
|
if not isinstance(item, Dict):
|
||||||
|
raise ServerError(
|
||||||
|
f"Cannot reduce a value of type {type(item)}")
|
||||||
if field not in item:
|
if field not in item:
|
||||||
item[field] = {}
|
item[field] = {}
|
||||||
return item[field]
|
return item[field]
|
||||||
|
@ -210,6 +213,12 @@ class MoonrakerDatabase:
|
||||||
f"{prev_type}. Overwriting with an object.")
|
f"{prev_type}. Overwriting with an object.")
|
||||||
item: Dict[str, Any] = reduce(
|
item: Dict[str, Any] = reduce(
|
||||||
getitem_with_default, key_list[1:-1], record)
|
getitem_with_default, key_list[1:-1], record)
|
||||||
|
if not isinstance(item, dict):
|
||||||
|
rpt_key = ".".join(key_list[:-1])
|
||||||
|
raise self.server.error(
|
||||||
|
f"Item at key '{rpt_key}' in namespace '{namespace}'is "
|
||||||
|
"not a dictionary object, cannot insert"
|
||||||
|
)
|
||||||
item[key_list[-1]] = value
|
item[key_list[-1]] = value
|
||||||
if not self._insert_record(namespace, key_list[0], record):
|
if not self._insert_record(namespace, key_list[0], record):
|
||||||
logging.info(
|
logging.info(
|
||||||
|
@ -233,7 +242,10 @@ class MoonrakerDatabase:
|
||||||
if isinstance(record, dict) and isinstance(value, dict):
|
if isinstance(record, dict) and isinstance(value, dict):
|
||||||
record.update(value)
|
record.update(value)
|
||||||
else:
|
else:
|
||||||
assert value is not None
|
if value is None:
|
||||||
|
raise self.server.error(
|
||||||
|
f"Item at key '{key}', namespace '{namespace}': "
|
||||||
|
"Cannot assign a record level null value")
|
||||||
record = value
|
record = value
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
@ -244,6 +256,12 @@ class MoonrakerDatabase:
|
||||||
raise self.server.error(
|
raise self.server.error(
|
||||||
f"Key '{key}' in namespace '{namespace}' not found",
|
f"Key '{key}' in namespace '{namespace}' not found",
|
||||||
404)
|
404)
|
||||||
|
if not isinstance(item, dict) or key_list[-1] not in item:
|
||||||
|
rpt_key = ".".join(key_list[:-1])
|
||||||
|
raise self.server.error(
|
||||||
|
f"Item at key '{rpt_key}' in namespace '{namespace}'is "
|
||||||
|
"not a dictionary object, cannot update"
|
||||||
|
)
|
||||||
if isinstance(item[key_list[-1]], dict) \
|
if isinstance(item[key_list[-1]], dict) \
|
||||||
and isinstance(value, dict):
|
and isinstance(value, dict):
|
||||||
item[key_list[-1]].update(value)
|
item[key_list[-1]].update(value)
|
||||||
|
|
Loading…
Reference in New Issue