Fix JSON parsing in _serial_redfish_request when terminal wraps long curl commands

The serial terminal echoes the curl command back before executing it.
The -w format string contains '%{http_code}' which includes a literal '{'.
When the terminal wraps long command lines (IOM2's path is ~70 chars),
that '{' can land at a line boundary, causing find("{") to pick up the
wrong position and produce garbled JSON/error output.

Fix: narrow the JSON search to the text before the HTTP_CODE: marker,
then use rfind("\n{") to find the last newline-prefixed '{'. The actual
curl response always starts on its own line, while the echoed '{http_code}'
is embedded mid-line in the command echo — so rfind("\n{") reliably skips it.

Also tighten the error snippet to use the same search_area bounds so the
displayed error shows actual response content rather than command echo text.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-16 10:31:00 -04:00
parent 4c820c5086
commit c587e64f9e

View File

@@ -161,6 +161,8 @@ def _serial_redfish_request(ser: SerialPort, password: str, method: str,
raw = _ANSI_RE.sub("", ser.read_until_quiet(quiet_period=1.5, timeout=30.0)) raw = _ANSI_RE.sub("", ser.read_until_quiet(quiet_period=1.5, timeout=30.0))
# ── Parse HTTP status code ───────────────────────────────────────────────── # ── Parse HTTP status code ─────────────────────────────────────────────────
# Use the LAST occurrence of HTTP_CODE: so the echoed curl -w argument
# (which also contains the literal text "HTTP_CODE:") doesn't interfere.
http_code = 0 http_code = 0
if "HTTP_CODE:" in raw: if "HTTP_CODE:" in raw:
try: try:
@@ -168,13 +170,34 @@ def _serial_redfish_request(ser: SerialPort, password: str, method: str,
except ValueError: except ValueError:
pass pass
# ── Extract JSON body (outermost { ... }) ────────────────────────────────── # ── Extract JSON body ──────────────────────────────────────────────────────
# The terminal echoes the curl command before executing it, and the
# -w format string contains '%{http_code}' which includes a literal '{'.
# When the terminal wraps long command lines, that '{' can land at a
# line boundary, causing find("{") to return the wrong position.
#
# Strategy: narrow the search to the text before HTTP_CODE: (the actual
# curl response body appears there), then find the LAST newline-prefixed
# '{' — because the JSON response always starts on its own line, while
# the echoed '{http_code}' is embedded mid-line in the curl command echo.
http_code_pos = raw.find("HTTP_CODE:")
search_area = raw[:http_code_pos].rstrip() if http_code_pos >= 0 else raw
data: dict = {} data: dict = {}
json_start = raw.find("{") json_end = search_area.rfind("}") + 1
json_end = raw.rfind("}") + 1 if json_end > 0:
if json_start >= 0 and json_end > json_start: json_start = -1
for nl in ("\r\n", "\n"):
pos = search_area.rfind(nl + "{")
if pos >= 0:
json_start = pos + len(nl)
break
if json_start < 0:
json_start = search_area.find("{") # fallback if no newline found
if json_start >= 0:
try: try:
data = json.loads(raw[json_start:json_end]) data = json.loads(search_area[json_start:json_end])
except json.JSONDecodeError: except json.JSONDecodeError:
pass pass
@@ -182,7 +205,8 @@ def _serial_redfish_request(ser: SerialPort, password: str, method: str,
if http_code >= 400: if http_code >= 400:
msg = (data.get("error", {}).get("message", "") msg = (data.get("error", {}).get("message", "")
if isinstance(data, dict) else "") if isinstance(data, dict) else "")
return False, f"HTTP {http_code}: {msg or raw[json_start:json_start+120]}" snippet = search_area[json_start:json_start + 120] if json_start >= 0 else search_area[-120:]
return False, f"HTTP {http_code}: {msg or snippet}"
if http_code >= 200 or data: if http_code >= 200 or data:
return True, data return True, data